From: Daniel Golle Date: Mon, 29 Aug 2022 06:54:41 +0000 (+0200) Subject: kernel: pick patches for MediaTek Ethernet from linux-next X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=c93c5365c0eb78ba8b479a9fe0cc5ec96f773978;p=openwrt%2Fstaging%2Fblocktrron.git kernel: pick patches for MediaTek Ethernet from linux-next Pick patches with several fixes and improvements, preparation for upcoming WED (TX) [1] as well as basic XDP support [2] with MediaTek's Filogic SoCs to the mtk_eth_soc driver. Also pick follow-up patch fixing Ethernet on MT7621 [3]. Tested on Bananapi BPi-R3 (MT7986), Bananapi BPi-R64 (MT7622), Bananapi BPi-R2 (MT7623), MikroTik RouterBoard M11G (MT7621). [1]: https://patchwork.kernel.org/project/netdevbpf/list/?series=662108&state=* [2]: https://patchwork.kernel.org/project/netdevbpf/list/?series=675368&state=* (the first part of the series adding wed nodes to mt7986a.dtsi was applied to the copy of mt7986a.dtsi in our tree) [3]: https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/commit/?id=5e69163d3b9931098922b3fc2f8e786af8c1f37e Signed-off-by: Daniel Golle --- diff --git a/target/linux/generic/backport-5.15/600-v5.18-page_pool-Add-allocation-stats.patch b/target/linux/generic/backport-5.15/600-v5.18-page_pool-Add-allocation-stats.patch new file mode 100644 index 0000000000..7b97181403 --- /dev/null +++ b/target/linux/generic/backport-5.15/600-v5.18-page_pool-Add-allocation-stats.patch @@ -0,0 +1,161 @@ +commit 8610037e8106b48c79cfe0afb92b2b2466e51c3d +Author: Joe Damato +Date: Tue Mar 1 23:55:47 2022 -0800 + + page_pool: Add allocation stats + + Add per-pool statistics counters for the allocation path of a page pool. + These stats are incremented in softirq context, so no locking or per-cpu + variables are needed. + + This code is disabled by default and a kernel config option is provided for + users who wish to enable them. + + The statistics added are: + - fast: successful fast path allocations + - slow: slow path order-0 allocations + - slow_high_order: slow path high order allocations + - empty: ptr ring is empty, so a slow path allocation was forced. + - refill: an allocation which triggered a refill of the cache + - waive: pages obtained from the ptr ring that cannot be added to + the cache due to a NUMA mismatch. + + Signed-off-by: Joe Damato + Acked-by: Jesper Dangaard Brouer + Reviewed-by: Ilias Apalodimas + Signed-off-by: David S. Miller + +--- a/include/net/page_pool.h ++++ b/include/net/page_pool.h +@@ -82,6 +82,19 @@ struct page_pool_params { + unsigned int offset; /* DMA addr offset */ + }; + ++#ifdef CONFIG_PAGE_POOL_STATS ++struct page_pool_alloc_stats { ++ u64 fast; /* fast path allocations */ ++ u64 slow; /* slow-path order 0 allocations */ ++ u64 slow_high_order; /* slow-path high order allocations */ ++ u64 empty; /* failed refills due to empty ptr ring, forcing ++ * slow path allocation ++ */ ++ u64 refill; /* allocations via successful refill */ ++ u64 waive; /* failed refills due to numa zone mismatch */ ++}; ++#endif ++ + struct page_pool { + struct page_pool_params p; + +@@ -132,6 +145,11 @@ struct page_pool { + refcount_t user_cnt; + + u64 destroy_cnt; ++ ++#ifdef CONFIG_PAGE_POOL_STATS ++ /* these stats are incremented while in softirq context */ ++ struct page_pool_alloc_stats alloc_stats; ++#endif + }; + + struct page *page_pool_alloc_pages(struct page_pool *pool, gfp_t gfp); +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -434,6 +434,19 @@ config NET_DEVLINK + config PAGE_POOL + bool + ++config PAGE_POOL_STATS ++ default n ++ bool "Page pool stats" ++ depends on PAGE_POOL ++ help ++ Enable page pool statistics to track page allocation and recycling ++ in page pools. This option incurs additional CPU cost in allocation ++ and recycle paths and additional memory cost to store the statistics. ++ These statistics are only available if this option is enabled and if ++ the driver using the page pool supports exporting this data. ++ ++ If unsure, say N. ++ + config FAILOVER + tristate "Generic failover module" + help +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -26,6 +26,13 @@ + + #define BIAS_MAX LONG_MAX + ++#ifdef CONFIG_PAGE_POOL_STATS ++/* alloc_stat_inc is intended to be used in softirq context */ ++#define alloc_stat_inc(pool, __stat) (pool->alloc_stats.__stat++) ++#else ++#define alloc_stat_inc(pool, __stat) ++#endif ++ + static int page_pool_init(struct page_pool *pool, + const struct page_pool_params *params) + { +@@ -117,8 +124,10 @@ static struct page *page_pool_refill_all + int pref_nid; /* preferred NUMA node */ + + /* Quicker fallback, avoid locks when ring is empty */ +- if (__ptr_ring_empty(r)) ++ if (__ptr_ring_empty(r)) { ++ alloc_stat_inc(pool, empty); + return NULL; ++ } + + /* Softirq guarantee CPU and thus NUMA node is stable. This, + * assumes CPU refilling driver RX-ring will also run RX-NAPI. +@@ -148,14 +157,17 @@ static struct page *page_pool_refill_all + * This limit stress on page buddy alloactor. + */ + page_pool_return_page(pool, page); ++ alloc_stat_inc(pool, waive); + page = NULL; + break; + } + } while (pool->alloc.count < PP_ALLOC_CACHE_REFILL); + + /* Return last page */ +- if (likely(pool->alloc.count > 0)) ++ if (likely(pool->alloc.count > 0)) { + page = pool->alloc.cache[--pool->alloc.count]; ++ alloc_stat_inc(pool, refill); ++ } + + spin_unlock(&r->consumer_lock); + return page; +@@ -170,6 +182,7 @@ static struct page *__page_pool_get_cach + if (likely(pool->alloc.count)) { + /* Fast-path */ + page = pool->alloc.cache[--pool->alloc.count]; ++ alloc_stat_inc(pool, fast); + } else { + page = page_pool_refill_alloc_cache(pool); + } +@@ -241,6 +254,7 @@ static struct page *__page_pool_alloc_pa + return NULL; + } + ++ alloc_stat_inc(pool, slow_high_order); + page_pool_set_pp_info(pool, page); + + /* Track how many pages are held 'in-flight' */ +@@ -295,10 +309,12 @@ static struct page *__page_pool_alloc_pa + } + + /* Return last page */ +- if (likely(pool->alloc.count > 0)) ++ if (likely(pool->alloc.count > 0)) { + page = pool->alloc.cache[--pool->alloc.count]; +- else ++ alloc_stat_inc(pool, slow); ++ } else { + page = NULL; ++ } + + /* When page just alloc'ed is should/must have refcnt 1. */ + return page; diff --git a/target/linux/generic/backport-5.15/601-v5.18-page_pool-Add-recycle-stats.patch b/target/linux/generic/backport-5.15/601-v5.18-page_pool-Add-recycle-stats.patch new file mode 100644 index 0000000000..8330ae811d --- /dev/null +++ b/target/linux/generic/backport-5.15/601-v5.18-page_pool-Add-recycle-stats.patch @@ -0,0 +1,137 @@ +commit ad6fa1e1ab1b8164f1ba296b1b4dc556a483bcad +Author: Joe Damato +Date: Tue Mar 1 23:55:48 2022 -0800 + + page_pool: Add recycle stats + + Add per-cpu stats tracking page pool recycling events: + - cached: recycling placed page in the page pool cache + - cache_full: page pool cache was full + - ring: page placed into the ptr ring + - ring_full: page released from page pool because the ptr ring was full + - released_refcnt: page released (and not recycled) because refcnt > 1 + + Signed-off-by: Joe Damato + Acked-by: Jesper Dangaard Brouer + Reviewed-by: Ilias Apalodimas + Signed-off-by: David S. Miller + +--- a/include/net/page_pool.h ++++ b/include/net/page_pool.h +@@ -93,6 +93,18 @@ struct page_pool_alloc_stats { + u64 refill; /* allocations via successful refill */ + u64 waive; /* failed refills due to numa zone mismatch */ + }; ++ ++struct page_pool_recycle_stats { ++ u64 cached; /* recycling placed page in the cache. */ ++ u64 cache_full; /* cache was full */ ++ u64 ring; /* recycling placed page back into ptr ring */ ++ u64 ring_full; /* page was released from page-pool because ++ * PTR ring was full. ++ */ ++ u64 released_refcnt; /* page released because of elevated ++ * refcnt ++ */ ++}; + #endif + + struct page_pool { +@@ -136,6 +148,10 @@ struct page_pool { + */ + struct ptr_ring ring; + ++#ifdef CONFIG_PAGE_POOL_STATS ++ /* recycle stats are per-cpu to avoid locking */ ++ struct page_pool_recycle_stats __percpu *recycle_stats; ++#endif + atomic_t pages_state_release_cnt; + + /* A page_pool is strictly tied to a single RX-queue being +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -29,8 +29,15 @@ + #ifdef CONFIG_PAGE_POOL_STATS + /* alloc_stat_inc is intended to be used in softirq context */ + #define alloc_stat_inc(pool, __stat) (pool->alloc_stats.__stat++) ++/* recycle_stat_inc is safe to use when preemption is possible. */ ++#define recycle_stat_inc(pool, __stat) \ ++ do { \ ++ struct page_pool_recycle_stats __percpu *s = pool->recycle_stats; \ ++ this_cpu_inc(s->__stat); \ ++ } while (0) + #else + #define alloc_stat_inc(pool, __stat) ++#define recycle_stat_inc(pool, __stat) + #endif + + static int page_pool_init(struct page_pool *pool, +@@ -80,6 +87,12 @@ static int page_pool_init(struct page_po + pool->p.flags & PP_FLAG_PAGE_FRAG) + return -EINVAL; + ++#ifdef CONFIG_PAGE_POOL_STATS ++ pool->recycle_stats = alloc_percpu(struct page_pool_recycle_stats); ++ if (!pool->recycle_stats) ++ return -ENOMEM; ++#endif ++ + if (ptr_ring_init(&pool->ring, ring_qsize, GFP_KERNEL) < 0) + return -ENOMEM; + +@@ -412,7 +425,12 @@ static bool page_pool_recycle_in_ring(st + else + ret = ptr_ring_produce_bh(&pool->ring, page); + +- return (ret == 0) ? true : false; ++ if (!ret) { ++ recycle_stat_inc(pool, ring); ++ return true; ++ } ++ ++ return false; + } + + /* Only allow direct recycling in special circumstances, into the +@@ -423,11 +441,14 @@ static bool page_pool_recycle_in_ring(st + static bool page_pool_recycle_in_cache(struct page *page, + struct page_pool *pool) + { +- if (unlikely(pool->alloc.count == PP_ALLOC_CACHE_SIZE)) ++ if (unlikely(pool->alloc.count == PP_ALLOC_CACHE_SIZE)) { ++ recycle_stat_inc(pool, cache_full); + return false; ++ } + + /* Caller MUST have verified/know (page_ref_count(page) == 1) */ + pool->alloc.cache[pool->alloc.count++] = page; ++ recycle_stat_inc(pool, cached); + return true; + } + +@@ -482,6 +503,7 @@ __page_pool_put_page(struct page_pool *p + * doing refcnt based recycle tricks, meaning another process + * will be invoking put_page. + */ ++ recycle_stat_inc(pool, released_refcnt); + /* Do not replace this with page_pool_return_page() */ + page_pool_release_page(pool, page); + put_page(page); +@@ -495,6 +517,7 @@ void page_pool_put_page(struct page_pool + page = __page_pool_put_page(pool, page, dma_sync_size, allow_direct); + if (page && !page_pool_recycle_in_ring(pool, page)) { + /* Cache full, fallback to free pages */ ++ recycle_stat_inc(pool, ring_full); + page_pool_return_page(pool, page); + } + } +@@ -641,6 +664,9 @@ static void page_pool_free(struct page_p + if (pool->p.flags & PP_FLAG_DMA_MAP) + put_device(pool->p.dev); + ++#ifdef CONFIG_PAGE_POOL_STATS ++ free_percpu(pool->recycle_stats); ++#endif + kfree(pool); + } + diff --git a/target/linux/generic/backport-5.15/602-v5.18-page_pool-Add-function-to-batch-and-return-stats.patch b/target/linux/generic/backport-5.15/602-v5.18-page_pool-Add-function-to-batch-and-return-stats.patch new file mode 100644 index 0000000000..8afbd5d120 --- /dev/null +++ b/target/linux/generic/backport-5.15/602-v5.18-page_pool-Add-function-to-batch-and-return-stats.patch @@ -0,0 +1,74 @@ +commit 6b95e3388b1ea0ca63500c5a6e39162dbf828433 +Author: Joe Damato +Date: Tue Mar 1 23:55:49 2022 -0800 + + page_pool: Add function to batch and return stats + + Adds a function page_pool_get_stats which can be used by drivers to obtain + stats for a specified page_pool. + + Signed-off-by: Joe Damato + Acked-by: Jesper Dangaard Brouer + Reviewed-by: Ilias Apalodimas + Signed-off-by: David S. Miller + +--- a/include/net/page_pool.h ++++ b/include/net/page_pool.h +@@ -105,6 +105,23 @@ struct page_pool_recycle_stats { + * refcnt + */ + }; ++ ++/* This struct wraps the above stats structs so users of the ++ * page_pool_get_stats API can pass a single argument when requesting the ++ * stats for the page pool. ++ */ ++struct page_pool_stats { ++ struct page_pool_alloc_stats alloc_stats; ++ struct page_pool_recycle_stats recycle_stats; ++}; ++ ++/* ++ * Drivers that wish to harvest page pool stats and report them to users ++ * (perhaps via ethtool, debugfs, or another mechanism) can allocate a ++ * struct page_pool_stats call page_pool_get_stats to get stats for the specified pool. ++ */ ++bool page_pool_get_stats(struct page_pool *pool, ++ struct page_pool_stats *stats); + #endif + + struct page_pool { +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -35,6 +35,31 @@ + struct page_pool_recycle_stats __percpu *s = pool->recycle_stats; \ + this_cpu_inc(s->__stat); \ + } while (0) ++ ++bool page_pool_get_stats(struct page_pool *pool, ++ struct page_pool_stats *stats) ++{ ++ int cpu = 0; ++ ++ if (!stats) ++ return false; ++ ++ memcpy(&stats->alloc_stats, &pool->alloc_stats, sizeof(pool->alloc_stats)); ++ ++ for_each_possible_cpu(cpu) { ++ const struct page_pool_recycle_stats *pcpu = ++ per_cpu_ptr(pool->recycle_stats, cpu); ++ ++ stats->recycle_stats.cached += pcpu->cached; ++ stats->recycle_stats.cache_full += pcpu->cache_full; ++ stats->recycle_stats.ring += pcpu->ring; ++ stats->recycle_stats.ring_full += pcpu->ring_full; ++ stats->recycle_stats.released_refcnt += pcpu->released_refcnt; ++ } ++ ++ return true; ++} ++EXPORT_SYMBOL(page_pool_get_stats); + #else + #define alloc_stat_inc(pool, __stat) + #define recycle_stat_inc(pool, __stat) diff --git a/target/linux/generic/backport-5.15/603-v5.19-page_pool-Add-recycle-stats-to-page_pool_put_page_bu.patch b/target/linux/generic/backport-5.15/603-v5.19-page_pool-Add-recycle-stats-to-page_pool_put_page_bu.patch new file mode 100644 index 0000000000..90f307772a --- /dev/null +++ b/target/linux/generic/backport-5.15/603-v5.19-page_pool-Add-recycle-stats-to-page_pool_put_page_bu.patch @@ -0,0 +1,53 @@ +commit 590032a4d2133ecc10d3078a8db1d85a4842f12c +Author: Lorenzo Bianconi +Date: Mon Apr 11 16:05:26 2022 +0200 + + page_pool: Add recycle stats to page_pool_put_page_bulk + + Add missing recycle stats to page_pool_put_page_bulk routine. + + Reviewed-by: Joe Damato + Signed-off-by: Lorenzo Bianconi + Reviewed-by: Ilias Apalodimas + Link: https://lore.kernel.org/r/3712178b51c007cfaed910ea80e68f00c916b1fa.1649685634.git.lorenzo@kernel.org + Signed-off-by: Paolo Abeni + +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -36,6 +36,12 @@ + this_cpu_inc(s->__stat); \ + } while (0) + ++#define recycle_stat_add(pool, __stat, val) \ ++ do { \ ++ struct page_pool_recycle_stats __percpu *s = pool->recycle_stats; \ ++ this_cpu_add(s->__stat, val); \ ++ } while (0) ++ + bool page_pool_get_stats(struct page_pool *pool, + struct page_pool_stats *stats) + { +@@ -63,6 +69,7 @@ EXPORT_SYMBOL(page_pool_get_stats); + #else + #define alloc_stat_inc(pool, __stat) + #define recycle_stat_inc(pool, __stat) ++#define recycle_stat_add(pool, __stat, val) + #endif + + static int page_pool_init(struct page_pool *pool, +@@ -569,9 +576,13 @@ void page_pool_put_page_bulk(struct page + /* Bulk producer into ptr_ring page_pool cache */ + page_pool_ring_lock(pool); + for (i = 0; i < bulk_len; i++) { +- if (__ptr_ring_produce(&pool->ring, data[i])) +- break; /* ring full */ ++ if (__ptr_ring_produce(&pool->ring, data[i])) { ++ /* ring full */ ++ recycle_stat_inc(pool, ring_full); ++ break; ++ } + } ++ recycle_stat_add(pool, ring, i); + page_pool_ring_unlock(pool); + + /* Hopefully all pages was return into ptr_ring */ diff --git a/target/linux/generic/backport-5.15/604-v5.19-net-page_pool-introduce-ethtool-stats.patch b/target/linux/generic/backport-5.15/604-v5.19-net-page_pool-introduce-ethtool-stats.patch new file mode 100644 index 0000000000..0694c5cfcb --- /dev/null +++ b/target/linux/generic/backport-5.15/604-v5.19-net-page_pool-introduce-ethtool-stats.patch @@ -0,0 +1,144 @@ +commit f3c5264f452a5b0ac1de1f2f657efbabdea3c76a +Author: Lorenzo Bianconi +Date: Tue Apr 12 18:31:58 2022 +0200 + + net: page_pool: introduce ethtool stats + + Introduce page_pool APIs to report stats through ethtool and reduce + duplicated code in each driver. + + Signed-off-by: Lorenzo Bianconi + Reviewed-by: Jakub Kicinski + Reviewed-by: Ilias Apalodimas + Signed-off-by: David S. Miller + +--- a/include/net/page_pool.h ++++ b/include/net/page_pool.h +@@ -115,6 +115,10 @@ struct page_pool_stats { + struct page_pool_recycle_stats recycle_stats; + }; + ++int page_pool_ethtool_stats_get_count(void); ++u8 *page_pool_ethtool_stats_get_strings(u8 *data); ++u64 *page_pool_ethtool_stats_get(u64 *data, void *stats); ++ + /* + * Drivers that wish to harvest page pool stats and report them to users + * (perhaps via ethtool, debugfs, or another mechanism) can allocate a +@@ -122,6 +126,23 @@ struct page_pool_stats { + */ + bool page_pool_get_stats(struct page_pool *pool, + struct page_pool_stats *stats); ++#else ++ ++static inline int page_pool_ethtool_stats_get_count(void) ++{ ++ return 0; ++} ++ ++static inline u8 *page_pool_ethtool_stats_get_strings(u8 *data) ++{ ++ return data; ++} ++ ++static inline u64 *page_pool_ethtool_stats_get(u64 *data, void *stats) ++{ ++ return data; ++} ++ + #endif + + struct page_pool { +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -18,6 +18,7 @@ + #include + #include /* for __put_page() */ + #include ++#include + + #include + +@@ -42,6 +43,20 @@ + this_cpu_add(s->__stat, val); \ + } while (0) + ++static const char pp_stats[][ETH_GSTRING_LEN] = { ++ "rx_pp_alloc_fast", ++ "rx_pp_alloc_slow", ++ "rx_pp_alloc_slow_ho", ++ "rx_pp_alloc_empty", ++ "rx_pp_alloc_refill", ++ "rx_pp_alloc_waive", ++ "rx_pp_recycle_cached", ++ "rx_pp_recycle_cache_full", ++ "rx_pp_recycle_ring", ++ "rx_pp_recycle_ring_full", ++ "rx_pp_recycle_released_ref", ++}; ++ + bool page_pool_get_stats(struct page_pool *pool, + struct page_pool_stats *stats) + { +@@ -50,7 +65,13 @@ bool page_pool_get_stats(struct page_poo + if (!stats) + return false; + +- memcpy(&stats->alloc_stats, &pool->alloc_stats, sizeof(pool->alloc_stats)); ++ /* The caller is responsible to initialize stats. */ ++ stats->alloc_stats.fast += pool->alloc_stats.fast; ++ stats->alloc_stats.slow += pool->alloc_stats.slow; ++ stats->alloc_stats.slow_high_order += pool->alloc_stats.slow_high_order; ++ stats->alloc_stats.empty += pool->alloc_stats.empty; ++ stats->alloc_stats.refill += pool->alloc_stats.refill; ++ stats->alloc_stats.waive += pool->alloc_stats.waive; + + for_each_possible_cpu(cpu) { + const struct page_pool_recycle_stats *pcpu = +@@ -66,6 +87,46 @@ bool page_pool_get_stats(struct page_poo + return true; + } + EXPORT_SYMBOL(page_pool_get_stats); ++ ++u8 *page_pool_ethtool_stats_get_strings(u8 *data) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(pp_stats); i++) { ++ memcpy(data, pp_stats[i], ETH_GSTRING_LEN); ++ data += ETH_GSTRING_LEN; ++ } ++ ++ return data; ++} ++EXPORT_SYMBOL(page_pool_ethtool_stats_get_strings); ++ ++int page_pool_ethtool_stats_get_count(void) ++{ ++ return ARRAY_SIZE(pp_stats); ++} ++EXPORT_SYMBOL(page_pool_ethtool_stats_get_count); ++ ++u64 *page_pool_ethtool_stats_get(u64 *data, void *stats) ++{ ++ struct page_pool_stats *pool_stats = stats; ++ ++ *data++ = pool_stats->alloc_stats.fast; ++ *data++ = pool_stats->alloc_stats.slow; ++ *data++ = pool_stats->alloc_stats.slow_high_order; ++ *data++ = pool_stats->alloc_stats.empty; ++ *data++ = pool_stats->alloc_stats.refill; ++ *data++ = pool_stats->alloc_stats.waive; ++ *data++ = pool_stats->recycle_stats.cached; ++ *data++ = pool_stats->recycle_stats.cache_full; ++ *data++ = pool_stats->recycle_stats.ring; ++ *data++ = pool_stats->recycle_stats.ring_full; ++ *data++ = pool_stats->recycle_stats.released_refcnt; ++ ++ return data; ++} ++EXPORT_SYMBOL(page_pool_ethtool_stats_get); ++ + #else + #define alloc_stat_inc(pool, __stat) + #define recycle_stat_inc(pool, __stat) diff --git a/target/linux/generic/backport-5.15/605-v5.18-xdp-introduce-flags-field-in-xdp_buff-xdp_frame.patch b/target/linux/generic/backport-5.15/605-v5.18-xdp-introduce-flags-field-in-xdp_buff-xdp_frame.patch new file mode 100644 index 0000000000..9c5a14c41b --- /dev/null +++ b/target/linux/generic/backport-5.15/605-v5.18-xdp-introduce-flags-field-in-xdp_buff-xdp_frame.patch @@ -0,0 +1,97 @@ +commit 2e88d4ff03013937028f5397268b21e10cf68713 +Author: Lorenzo Bianconi +Date: Fri Jan 21 11:09:45 2022 +0100 + + xdp: introduce flags field in xdp_buff/xdp_frame + + Introduce flags field in xdp_frame and xdp_buffer data structures + to define additional buffer features. At the moment the only + supported buffer feature is frags bit (XDP_FLAGS_HAS_FRAGS). + frags bit is used to specify if this is a linear buffer + (XDP_FLAGS_HAS_FRAGS not set) or a frags frame (XDP_FLAGS_HAS_FRAGS + set). In the latter case the driver is expected to initialize the + skb_shared_info structure at the end of the first buffer to link together + subsequent buffers belonging to the same frame. + + Acked-by: Toke Hoiland-Jorgensen + Acked-by: John Fastabend + Acked-by: Jesper Dangaard Brouer + Signed-off-by: Lorenzo Bianconi + Link: https://lore.kernel.org/r/e389f14f3a162c0a5bc6a2e1aa8dd01a90be117d.1642758637.git.lorenzo@kernel.org + Signed-off-by: Alexei Starovoitov + +--- a/include/net/xdp.h ++++ b/include/net/xdp.h +@@ -66,6 +66,10 @@ struct xdp_txq_info { + struct net_device *dev; + }; + ++enum xdp_buff_flags { ++ XDP_FLAGS_HAS_FRAGS = BIT(0), /* non-linear xdp buff */ ++}; ++ + struct xdp_buff { + void *data; + void *data_end; +@@ -74,13 +78,30 @@ struct xdp_buff { + struct xdp_rxq_info *rxq; + struct xdp_txq_info *txq; + u32 frame_sz; /* frame size to deduce data_hard_end/reserved tailroom*/ ++ u32 flags; /* supported values defined in xdp_buff_flags */ + }; + ++static __always_inline bool xdp_buff_has_frags(struct xdp_buff *xdp) ++{ ++ return !!(xdp->flags & XDP_FLAGS_HAS_FRAGS); ++} ++ ++static __always_inline void xdp_buff_set_frags_flag(struct xdp_buff *xdp) ++{ ++ xdp->flags |= XDP_FLAGS_HAS_FRAGS; ++} ++ ++static __always_inline void xdp_buff_clear_frags_flag(struct xdp_buff *xdp) ++{ ++ xdp->flags &= ~XDP_FLAGS_HAS_FRAGS; ++} ++ + static __always_inline void + xdp_init_buff(struct xdp_buff *xdp, u32 frame_sz, struct xdp_rxq_info *rxq) + { + xdp->frame_sz = frame_sz; + xdp->rxq = rxq; ++ xdp->flags = 0; + } + + static __always_inline void +@@ -122,8 +143,14 @@ struct xdp_frame { + */ + struct xdp_mem_info mem; + struct net_device *dev_rx; /* used by cpumap */ ++ u32 flags; /* supported values defined in xdp_buff_flags */ + }; + ++static __always_inline bool xdp_frame_has_frags(struct xdp_frame *frame) ++{ ++ return !!(frame->flags & XDP_FLAGS_HAS_FRAGS); ++} ++ + #define XDP_BULK_QUEUE_SIZE 16 + struct xdp_frame_bulk { + int count; +@@ -180,6 +207,7 @@ void xdp_convert_frame_to_buff(struct xd + xdp->data_end = frame->data + frame->len; + xdp->data_meta = frame->data - frame->metasize; + xdp->frame_sz = frame->frame_sz; ++ xdp->flags = frame->flags; + } + + static inline +@@ -206,6 +234,7 @@ int xdp_update_frame_from_buff(struct xd + xdp_frame->headroom = headroom - sizeof(*xdp_frame); + xdp_frame->metasize = metasize; + xdp_frame->frame_sz = xdp->frame_sz; ++ xdp_frame->flags = xdp->flags; + + return 0; + } diff --git a/target/linux/generic/backport-5.15/606-v5.18-xdp-add-frags-support-to-xdp_return_-buff-frame.patch b/target/linux/generic/backport-5.15/606-v5.18-xdp-add-frags-support-to-xdp_return_-buff-frame.patch new file mode 100644 index 0000000000..5a04948002 --- /dev/null +++ b/target/linux/generic/backport-5.15/606-v5.18-xdp-add-frags-support-to-xdp_return_-buff-frame.patch @@ -0,0 +1,134 @@ +commit 7c48cb0176c6d6d3b55029f7ff4ffa05faee6446 +Author: Lorenzo Bianconi +Date: Fri Jan 21 11:09:50 2022 +0100 + + xdp: add frags support to xdp_return_{buff/frame} + + Take into account if the received xdp_buff/xdp_frame is non-linear + recycling/returning the frame memory to the allocator or into + xdp_frame_bulk. + + Acked-by: Toke Hoiland-Jorgensen + Acked-by: John Fastabend + Signed-off-by: Lorenzo Bianconi + Link: https://lore.kernel.org/r/a961069febc868508ce1bdf5e53a343eb4e57cb2.1642758637.git.lorenzo@kernel.org + Signed-off-by: Alexei Starovoitov + +--- a/include/net/xdp.h ++++ b/include/net/xdp.h +@@ -275,10 +275,24 @@ void __xdp_release_frame(void *data, str + static inline void xdp_release_frame(struct xdp_frame *xdpf) + { + struct xdp_mem_info *mem = &xdpf->mem; ++ struct skb_shared_info *sinfo; ++ int i; + + /* Curr only page_pool needs this */ +- if (mem->type == MEM_TYPE_PAGE_POOL) +- __xdp_release_frame(xdpf->data, mem); ++ if (mem->type != MEM_TYPE_PAGE_POOL) ++ return; ++ ++ if (likely(!xdp_frame_has_frags(xdpf))) ++ goto out; ++ ++ sinfo = xdp_get_shared_info_from_frame(xdpf); ++ for (i = 0; i < sinfo->nr_frags; i++) { ++ struct page *page = skb_frag_page(&sinfo->frags[i]); ++ ++ __xdp_release_frame(page_address(page), mem); ++ } ++out: ++ __xdp_release_frame(xdpf->data, mem); + } + + int xdp_rxq_info_reg(struct xdp_rxq_info *xdp_rxq, +--- a/net/core/xdp.c ++++ b/net/core/xdp.c +@@ -376,12 +376,38 @@ static void __xdp_return(void *data, str + + void xdp_return_frame(struct xdp_frame *xdpf) + { ++ struct skb_shared_info *sinfo; ++ int i; ++ ++ if (likely(!xdp_frame_has_frags(xdpf))) ++ goto out; ++ ++ sinfo = xdp_get_shared_info_from_frame(xdpf); ++ for (i = 0; i < sinfo->nr_frags; i++) { ++ struct page *page = skb_frag_page(&sinfo->frags[i]); ++ ++ __xdp_return(page_address(page), &xdpf->mem, false, NULL); ++ } ++out: + __xdp_return(xdpf->data, &xdpf->mem, false, NULL); + } + EXPORT_SYMBOL_GPL(xdp_return_frame); + + void xdp_return_frame_rx_napi(struct xdp_frame *xdpf) + { ++ struct skb_shared_info *sinfo; ++ int i; ++ ++ if (likely(!xdp_frame_has_frags(xdpf))) ++ goto out; ++ ++ sinfo = xdp_get_shared_info_from_frame(xdpf); ++ for (i = 0; i < sinfo->nr_frags; i++) { ++ struct page *page = skb_frag_page(&sinfo->frags[i]); ++ ++ __xdp_return(page_address(page), &xdpf->mem, true, NULL); ++ } ++out: + __xdp_return(xdpf->data, &xdpf->mem, true, NULL); + } + EXPORT_SYMBOL_GPL(xdp_return_frame_rx_napi); +@@ -417,7 +443,7 @@ void xdp_return_frame_bulk(struct xdp_fr + struct xdp_mem_allocator *xa; + + if (mem->type != MEM_TYPE_PAGE_POOL) { +- __xdp_return(xdpf->data, &xdpf->mem, false, NULL); ++ xdp_return_frame(xdpf); + return; + } + +@@ -436,12 +462,38 @@ void xdp_return_frame_bulk(struct xdp_fr + bq->xa = rhashtable_lookup(mem_id_ht, &mem->id, mem_id_rht_params); + } + ++ if (unlikely(xdp_frame_has_frags(xdpf))) { ++ struct skb_shared_info *sinfo; ++ int i; ++ ++ sinfo = xdp_get_shared_info_from_frame(xdpf); ++ for (i = 0; i < sinfo->nr_frags; i++) { ++ skb_frag_t *frag = &sinfo->frags[i]; ++ ++ bq->q[bq->count++] = skb_frag_address(frag); ++ if (bq->count == XDP_BULK_QUEUE_SIZE) ++ xdp_flush_frame_bulk(bq); ++ } ++ } + bq->q[bq->count++] = xdpf->data; + } + EXPORT_SYMBOL_GPL(xdp_return_frame_bulk); + + void xdp_return_buff(struct xdp_buff *xdp) + { ++ struct skb_shared_info *sinfo; ++ int i; ++ ++ if (likely(!xdp_buff_has_frags(xdp))) ++ goto out; ++ ++ sinfo = xdp_get_shared_info_from_buff(xdp); ++ for (i = 0; i < sinfo->nr_frags; i++) { ++ struct page *page = skb_frag_page(&sinfo->frags[i]); ++ ++ __xdp_return(page_address(page), &xdp->rxq->mem, true, xdp); ++ } ++out: + __xdp_return(xdp->data, &xdp->rxq->mem, true, xdp); + } + diff --git a/target/linux/generic/backport-5.15/607-v5.18-net-skbuff-add-size-metadata-to-skb_shared_info-for-.patch b/target/linux/generic/backport-5.15/607-v5.18-net-skbuff-add-size-metadata-to-skb_shared_info-for-.patch new file mode 100644 index 0000000000..5ded882f90 --- /dev/null +++ b/target/linux/generic/backport-5.15/607-v5.18-net-skbuff-add-size-metadata-to-skb_shared_info-for-.patch @@ -0,0 +1,29 @@ +commit d16697cb6261d4cc23422e6b1cb2759df8aa76d0 +Author: Lorenzo Bianconi +Date: Fri Jan 21 11:09:44 2022 +0100 + + net: skbuff: add size metadata to skb_shared_info for xdp + + Introduce xdp_frags_size field in skb_shared_info data structure + to store xdp_buff/xdp_frame frame paged size (xdp_frags_size will + be used in xdp frags support). In order to not increase + skb_shared_info size we will use a hole due to skb_shared_info + alignment. + + Acked-by: Toke Hoiland-Jorgensen + Acked-by: John Fastabend + Acked-by: Jesper Dangaard Brouer + Signed-off-by: Lorenzo Bianconi + Link: https://lore.kernel.org/r/8a849819a3e0a143d540f78a3a5add76e17e980d.1642758637.git.lorenzo@kernel.org + Signed-off-by: Alexei Starovoitov + +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -567,6 +567,7 @@ struct skb_shared_info { + * Warning : all fields before dataref are cleared in __alloc_skb() + */ + atomic_t dataref; ++ unsigned int xdp_frags_size; + + /* Intermediate layers must ensure that destructor_arg + * remains valid until skb destructor */ diff --git a/target/linux/generic/backport-5.15/608-v5.18-net-veth-Account-total-xdp_frame-len-running-ndo_xdp.patch b/target/linux/generic/backport-5.15/608-v5.18-net-veth-Account-total-xdp_frame-len-running-ndo_xdp.patch new file mode 100644 index 0000000000..9b16fc00b7 --- /dev/null +++ b/target/linux/generic/backport-5.15/608-v5.18-net-veth-Account-total-xdp_frame-len-running-ndo_xdp.patch @@ -0,0 +1,62 @@ +commit 5142239a22219921a7863cf00c9ab853c00689d8 +Author: Lorenzo Bianconi +Date: Fri Mar 11 10:14:18 2022 +0100 + + net: veth: Account total xdp_frame len running ndo_xdp_xmit + + Even if this is a theoretical issue since it is not possible to perform + XDP_REDIRECT on a non-linear xdp_frame, veth driver does not account + paged area in ndo_xdp_xmit function pointer. + Introduce xdp_get_frame_len utility routine to get the xdp_frame full + length and account total frame size running XDP_REDIRECT of a + non-linear xdp frame into a veth device. + + Signed-off-by: Lorenzo Bianconi + Signed-off-by: Daniel Borkmann + Acked-by: Toke Hoiland-Jorgensen + Acked-by: John Fastabend + Link: https://lore.kernel.org/bpf/54f9fd3bb65d190daf2c0bbae2f852ff16cfbaa0.1646989407.git.lorenzo@kernel.org + +--- a/drivers/net/veth.c ++++ b/drivers/net/veth.c +@@ -501,7 +501,7 @@ static int veth_xdp_xmit(struct net_devi + struct xdp_frame *frame = frames[i]; + void *ptr = veth_xdp_to_ptr(frame); + +- if (unlikely(frame->len > max_len || ++ if (unlikely(xdp_get_frame_len(frame) > max_len || + __ptr_ring_produce(&rq->xdp_ring, ptr))) + break; + nxmit++; +@@ -862,7 +862,7 @@ static int veth_xdp_rcv(struct veth_rq * + /* ndo_xdp_xmit */ + struct xdp_frame *frame = veth_ptr_to_xdp(ptr); + +- stats->xdp_bytes += frame->len; ++ stats->xdp_bytes += xdp_get_frame_len(frame); + frame = veth_xdp_rcv_one(rq, frame, bq, stats); + if (frame) { + /* XDP_PASS */ +--- a/include/net/xdp.h ++++ b/include/net/xdp.h +@@ -295,6 +295,20 @@ out: + __xdp_release_frame(xdpf->data, mem); + } + ++static __always_inline unsigned int xdp_get_frame_len(struct xdp_frame *xdpf) ++{ ++ struct skb_shared_info *sinfo; ++ unsigned int len = xdpf->len; ++ ++ if (likely(!xdp_frame_has_frags(xdpf))) ++ goto out; ++ ++ sinfo = xdp_get_shared_info_from_frame(xdpf); ++ len += sinfo->xdp_frags_size; ++out: ++ return len; ++} ++ + int xdp_rxq_info_reg(struct xdp_rxq_info *xdp_rxq, + struct net_device *dev, u32 queue_index, unsigned int napi_id); + void xdp_rxq_info_unreg(struct xdp_rxq_info *xdp_rxq); diff --git a/target/linux/generic/backport-5.15/609-v5.18-veth-Allow-jumbo-frames-in-xdp-mode.patch b/target/linux/generic/backport-5.15/609-v5.18-veth-Allow-jumbo-frames-in-xdp-mode.patch new file mode 100644 index 0000000000..8080d621da --- /dev/null +++ b/target/linux/generic/backport-5.15/609-v5.18-veth-Allow-jumbo-frames-in-xdp-mode.patch @@ -0,0 +1,35 @@ +commit 7cda76d858a4e71ac4a04066c093679a12e1312c +Author: Lorenzo Bianconi +Date: Fri Mar 11 10:14:20 2022 +0100 + + veth: Allow jumbo frames in xdp mode + + Allow increasing the MTU over page boundaries on veth devices + if the attached xdp program declares to support xdp fragments. + + Signed-off-by: Lorenzo Bianconi + Signed-off-by: Daniel Borkmann + Acked-by: Toke Høiland-Jørgensen + Acked-by: John Fastabend + Link: https://lore.kernel.org/bpf/d5dc039c3d4123426e7023a488c449181a7bc57f.1646989407.git.lorenzo@kernel.org + +--- a/drivers/net/veth.c ++++ b/drivers/net/veth.c +@@ -1470,9 +1470,14 @@ static int veth_xdp_set(struct net_devic + goto err; + } + +- max_mtu = PAGE_SIZE - VETH_XDP_HEADROOM - +- peer->hard_header_len - +- SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); ++ max_mtu = SKB_WITH_OVERHEAD(PAGE_SIZE - VETH_XDP_HEADROOM) - ++ peer->hard_header_len; ++ /* Allow increasing the max_mtu if the program supports ++ * XDP fragments. ++ */ ++ //if (prog->aux->xdp_has_frags) ++ max_mtu += PAGE_SIZE * MAX_SKB_FRAGS; ++ + if (peer->mtu > max_mtu) { + NL_SET_ERR_MSG_MOD(extack, "Peer MTU is too large to set XDP"); + err = -ERANGE; diff --git a/target/linux/generic/backport-5.15/706-00-v6.0-net-ethernet-mtk_eth_soc-rely-on-page_pool-for-singl.patch b/target/linux/generic/backport-5.15/706-00-v6.0-net-ethernet-mtk_eth_soc-rely-on-page_pool-for-singl.patch new file mode 100644 index 0000000000..f9aa6fb67b --- /dev/null +++ b/target/linux/generic/backport-5.15/706-00-v6.0-net-ethernet-mtk_eth_soc-rely-on-page_pool-for-singl.patch @@ -0,0 +1,330 @@ +From 23233e577ef973c2c5d0dd757a0a4605e34ecb57 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Fri, 22 Jul 2022 09:19:36 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: rely on page_pool for single page + buffers + +Rely on page_pool allocator for single page buffers in order to keep +them dma mapped and add skb recycling support. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/Kconfig | 1 + + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 185 +++++++++++++++----- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 10 ++ + 3 files changed, 156 insertions(+), 40 deletions(-) + +--- a/drivers/net/ethernet/mediatek/Kconfig ++++ b/drivers/net/ethernet/mediatek/Kconfig +@@ -16,6 +16,7 @@ config NET_MEDIATEK_SOC + depends on NET_DSA || !NET_DSA + select PHYLINK + select DIMLIB ++ select PAGE_POOL + help + This driver supports the gigabit ethernet MACs in the + MediaTek SoC family. +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1388,6 +1388,68 @@ static void mtk_update_rx_cpu_idx(struct + } + } + ++static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth, ++ struct xdp_rxq_info *xdp_q, ++ int id, int size) ++{ ++ struct page_pool_params pp_params = { ++ .order = 0, ++ .flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV, ++ .pool_size = size, ++ .nid = NUMA_NO_NODE, ++ .dev = eth->dma_dev, ++ .dma_dir = DMA_FROM_DEVICE, ++ .offset = MTK_PP_HEADROOM, ++ .max_len = MTK_PP_MAX_BUF_SIZE, ++ }; ++ struct page_pool *pp; ++ int err; ++ ++ pp = page_pool_create(&pp_params); ++ if (IS_ERR(pp)) ++ return pp; ++ ++ err = xdp_rxq_info_reg(xdp_q, ð->dummy_dev, id, ++ eth->rx_napi.napi_id); ++ if (err < 0) ++ goto err_free_pp; ++ ++ err = xdp_rxq_info_reg_mem_model(xdp_q, MEM_TYPE_PAGE_POOL, pp); ++ if (err) ++ goto err_unregister_rxq; ++ ++ return pp; ++ ++err_unregister_rxq: ++ xdp_rxq_info_unreg(xdp_q); ++err_free_pp: ++ page_pool_destroy(pp); ++ ++ return ERR_PTR(err); ++} ++ ++static void *mtk_page_pool_get_buff(struct page_pool *pp, dma_addr_t *dma_addr, ++ gfp_t gfp_mask) ++{ ++ struct page *page; ++ ++ page = page_pool_alloc_pages(pp, gfp_mask | __GFP_NOWARN); ++ if (!page) ++ return NULL; ++ ++ *dma_addr = page_pool_get_dma_addr(page) + MTK_PP_HEADROOM; ++ return page_address(page); ++} ++ ++static void mtk_rx_put_buff(struct mtk_rx_ring *ring, void *data, bool napi) ++{ ++ if (ring->page_pool) ++ page_pool_put_full_page(ring->page_pool, ++ virt_to_head_page(data), napi); ++ else ++ skb_free_frag(data); ++} ++ + static int mtk_poll_rx(struct napi_struct *napi, int budget, + struct mtk_eth *eth) + { +@@ -1401,9 +1463,9 @@ static int mtk_poll_rx(struct napi_struc + + while (done < budget) { + unsigned int pktlen, *rxdcsum; ++ u32 hash, reason, reserve_len; + struct net_device *netdev; + dma_addr_t dma_addr; +- u32 hash, reason; + int mac = 0; + + ring = mtk_get_rx_ring(eth); +@@ -1434,36 +1496,54 @@ static int mtk_poll_rx(struct napi_struc + goto release_desc; + + /* alloc new buffer */ +- if (ring->frag_size <= PAGE_SIZE) +- new_data = napi_alloc_frag(ring->frag_size); +- else +- new_data = mtk_max_lro_buf_alloc(GFP_ATOMIC); +- if (unlikely(!new_data)) { +- netdev->stats.rx_dropped++; +- goto release_desc; +- } +- dma_addr = dma_map_single(eth->dma_dev, +- new_data + NET_SKB_PAD + +- eth->ip_align, +- ring->buf_size, +- DMA_FROM_DEVICE); +- if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) { +- skb_free_frag(new_data); +- netdev->stats.rx_dropped++; +- goto release_desc; +- } ++ if (ring->page_pool) { ++ new_data = mtk_page_pool_get_buff(ring->page_pool, ++ &dma_addr, ++ GFP_ATOMIC); ++ if (unlikely(!new_data)) { ++ netdev->stats.rx_dropped++; ++ goto release_desc; ++ } ++ } else { ++ if (ring->frag_size <= PAGE_SIZE) ++ new_data = napi_alloc_frag(ring->frag_size); ++ else ++ new_data = mtk_max_lro_buf_alloc(GFP_ATOMIC); ++ ++ if (unlikely(!new_data)) { ++ netdev->stats.rx_dropped++; ++ goto release_desc; ++ } + +- dma_unmap_single(eth->dma_dev, trxd.rxd1, +- ring->buf_size, DMA_FROM_DEVICE); ++ dma_addr = dma_map_single(eth->dma_dev, ++ new_data + NET_SKB_PAD + eth->ip_align, ++ ring->buf_size, DMA_FROM_DEVICE); ++ if (unlikely(dma_mapping_error(eth->dma_dev, ++ dma_addr))) { ++ skb_free_frag(new_data); ++ netdev->stats.rx_dropped++; ++ goto release_desc; ++ } ++ ++ dma_unmap_single(eth->dma_dev, trxd.rxd1, ++ ring->buf_size, DMA_FROM_DEVICE); ++ } + + /* receive data */ + skb = build_skb(data, ring->frag_size); + if (unlikely(!skb)) { +- skb_free_frag(data); ++ mtk_rx_put_buff(ring, data, true); + netdev->stats.rx_dropped++; + goto skip_rx; + } +- skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); ++ ++ if (ring->page_pool) { ++ reserve_len = MTK_PP_HEADROOM; ++ skb_mark_for_recycle(skb); ++ } else { ++ reserve_len = NET_SKB_PAD + NET_IP_ALIGN; ++ } ++ skb_reserve(skb, reserve_len); + + pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); + skb->dev = netdev; +@@ -1517,7 +1597,6 @@ static int mtk_poll_rx(struct napi_struc + skip_rx: + ring->data[idx] = new_data; + rxd->rxd1 = (unsigned int)dma_addr; +- + release_desc: + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) + rxd->rxd2 = RX_DMA_LSO; +@@ -1525,7 +1604,6 @@ release_desc: + rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size); + + ring->calc_idx = idx; +- + done++; + } + +@@ -1889,13 +1967,15 @@ static int mtk_rx_alloc(struct mtk_eth * + if (!ring->data) + return -ENOMEM; + +- for (i = 0; i < rx_dma_size; i++) { +- if (ring->frag_size <= PAGE_SIZE) +- ring->data[i] = netdev_alloc_frag(ring->frag_size); +- else +- ring->data[i] = mtk_max_lro_buf_alloc(GFP_KERNEL); +- if (!ring->data[i]) +- return -ENOMEM; ++ if (!eth->hwlro) { ++ struct page_pool *pp; ++ ++ pp = mtk_create_page_pool(eth, &ring->xdp_q, ring_no, ++ rx_dma_size); ++ if (IS_ERR(pp)) ++ return PTR_ERR(pp); ++ ++ ring->page_pool = pp; + } + + ring->dma = dma_alloc_coherent(eth->dma_dev, +@@ -1906,16 +1986,33 @@ static int mtk_rx_alloc(struct mtk_eth * + + for (i = 0; i < rx_dma_size; i++) { + struct mtk_rx_dma_v2 *rxd; +- +- dma_addr_t dma_addr = dma_map_single(eth->dma_dev, +- ring->data[i] + NET_SKB_PAD + eth->ip_align, +- ring->buf_size, +- DMA_FROM_DEVICE); +- if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) +- return -ENOMEM; ++ dma_addr_t dma_addr; ++ void *data; + + rxd = ring->dma + i * eth->soc->txrx.rxd_size; ++ if (ring->page_pool) { ++ data = mtk_page_pool_get_buff(ring->page_pool, ++ &dma_addr, GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ } else { ++ if (ring->frag_size <= PAGE_SIZE) ++ data = netdev_alloc_frag(ring->frag_size); ++ else ++ data = mtk_max_lro_buf_alloc(GFP_KERNEL); ++ ++ if (!data) ++ return -ENOMEM; ++ ++ dma_addr = dma_map_single(eth->dma_dev, ++ data + NET_SKB_PAD + eth->ip_align, ++ ring->buf_size, DMA_FROM_DEVICE); ++ if (unlikely(dma_mapping_error(eth->dma_dev, ++ dma_addr))) ++ return -ENOMEM; ++ } + rxd->rxd1 = (unsigned int)dma_addr; ++ ring->data[i] = data; + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) + rxd->rxd2 = RX_DMA_LSO; +@@ -1931,6 +2028,7 @@ static int mtk_rx_alloc(struct mtk_eth * + rxd->rxd8 = 0; + } + } ++ + ring->dma_size = rx_dma_size; + ring->calc_idx_update = false; + ring->calc_idx = rx_dma_size - 1; +@@ -1982,7 +2080,7 @@ static void mtk_rx_clean(struct mtk_eth + + dma_unmap_single(eth->dma_dev, rxd->rxd1, + ring->buf_size, DMA_FROM_DEVICE); +- skb_free_frag(ring->data[i]); ++ mtk_rx_put_buff(ring, ring->data[i], false); + } + kfree(ring->data); + ring->data = NULL; +@@ -1994,6 +2092,13 @@ static void mtk_rx_clean(struct mtk_eth + ring->dma, ring->phys); + ring->dma = NULL; + } ++ ++ if (ring->page_pool) { ++ if (xdp_rxq_info_is_reg(&ring->xdp_q)) ++ xdp_rxq_info_unreg(&ring->xdp_q); ++ page_pool_destroy(ring->page_pool); ++ ring->page_pool = NULL; ++ } + } + + static int mtk_hwlro_rx_init(struct mtk_eth *eth) +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -18,6 +18,8 @@ + #include + #include + #include ++#include ++#include + #include "mtk_ppe.h" + + #define MTK_QDMA_PAGE_SIZE 2048 +@@ -49,6 +51,11 @@ + #define MTK_HW_FEATURES_MT7628 (NETIF_F_SG | NETIF_F_RXCSUM) + #define NEXT_DESP_IDX(X, Y) (((X) + 1) & ((Y) - 1)) + ++#define MTK_PP_HEADROOM XDP_PACKET_HEADROOM ++#define MTK_PP_PAD (MTK_PP_HEADROOM + \ ++ SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) ++#define MTK_PP_MAX_BUF_SIZE (PAGE_SIZE - MTK_PP_PAD) ++ + #define MTK_QRX_OFFSET 0x10 + + #define MTK_MAX_RX_RING_NUM 4 +@@ -742,6 +749,9 @@ struct mtk_rx_ring { + bool calc_idx_update; + u16 calc_idx; + u32 crx_idx_reg; ++ /* page_pool */ ++ struct page_pool *page_pool; ++ struct xdp_rxq_info xdp_q; + }; + + enum mkt_eth_capabilities { diff --git a/target/linux/generic/backport-5.15/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch b/target/linux/generic/backport-5.15/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch new file mode 100644 index 0000000000..b930152dd1 --- /dev/null +++ b/target/linux/generic/backport-5.15/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch @@ -0,0 +1,291 @@ +From 7c26c20da5d420cde55618263be4aa2f6de53056 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Fri, 22 Jul 2022 09:19:37 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: add basic XDP support + +Introduce basic XDP support to mtk_eth_soc driver. +Supported XDP verdicts: +- XDP_PASS +- XDP_DROP +- XDP_REDIRECT + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 162 +++++++++++++++++--- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 + + 2 files changed, 145 insertions(+), 19 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1388,6 +1388,11 @@ static void mtk_update_rx_cpu_idx(struct + } + } + ++static bool mtk_page_pool_enabled(struct mtk_eth *eth) ++{ ++ return !eth->hwlro; ++} ++ + static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth, + struct xdp_rxq_info *xdp_q, + int id, int size) +@@ -1450,11 +1455,52 @@ static void mtk_rx_put_buff(struct mtk_r + skb_free_frag(data); + } + ++static u32 mtk_xdp_run(struct mtk_eth *eth, struct mtk_rx_ring *ring, ++ struct xdp_buff *xdp, struct net_device *dev) ++{ ++ struct bpf_prog *prog; ++ u32 act = XDP_PASS; ++ ++ rcu_read_lock(); ++ ++ prog = rcu_dereference(eth->prog); ++ if (!prog) ++ goto out; ++ ++ act = bpf_prog_run_xdp(prog, xdp); ++ switch (act) { ++ case XDP_PASS: ++ goto out; ++ case XDP_REDIRECT: ++ if (unlikely(xdp_do_redirect(dev, xdp, prog))) { ++ act = XDP_DROP; ++ break; ++ } ++ goto out; ++ default: ++ bpf_warn_invalid_xdp_action(act); ++ fallthrough; ++ case XDP_ABORTED: ++ trace_xdp_exception(dev, prog, act); ++ fallthrough; ++ case XDP_DROP: ++ break; ++ } ++ ++ page_pool_put_full_page(ring->page_pool, ++ virt_to_head_page(xdp->data), true); ++out: ++ rcu_read_unlock(); ++ ++ return act; ++} ++ + static int mtk_poll_rx(struct napi_struct *napi, int budget, + struct mtk_eth *eth) + { + struct dim_sample dim_sample = {}; + struct mtk_rx_ring *ring; ++ bool xdp_flush = false; + int idx; + struct sk_buff *skb; + u8 *data, *new_data; +@@ -1463,9 +1509,9 @@ static int mtk_poll_rx(struct napi_struc + + while (done < budget) { + unsigned int pktlen, *rxdcsum; +- u32 hash, reason, reserve_len; + struct net_device *netdev; + dma_addr_t dma_addr; ++ u32 hash, reason; + int mac = 0; + + ring = mtk_get_rx_ring(eth); +@@ -1495,8 +1541,14 @@ static int mtk_poll_rx(struct napi_struc + if (unlikely(test_bit(MTK_RESETTING, ð->state))) + goto release_desc; + ++ pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); ++ + /* alloc new buffer */ + if (ring->page_pool) { ++ struct page *page = virt_to_head_page(data); ++ struct xdp_buff xdp; ++ u32 ret; ++ + new_data = mtk_page_pool_get_buff(ring->page_pool, + &dma_addr, + GFP_ATOMIC); +@@ -1504,6 +1556,34 @@ static int mtk_poll_rx(struct napi_struc + netdev->stats.rx_dropped++; + goto release_desc; + } ++ ++ dma_sync_single_for_cpu(eth->dma_dev, ++ page_pool_get_dma_addr(page) + MTK_PP_HEADROOM, ++ pktlen, page_pool_get_dma_dir(ring->page_pool)); ++ ++ xdp_init_buff(&xdp, PAGE_SIZE, &ring->xdp_q); ++ xdp_prepare_buff(&xdp, data, MTK_PP_HEADROOM, pktlen, ++ false); ++ xdp_buff_clear_frags_flag(&xdp); ++ ++ ret = mtk_xdp_run(eth, ring, &xdp, netdev); ++ if (ret == XDP_REDIRECT) ++ xdp_flush = true; ++ ++ if (ret != XDP_PASS) ++ goto skip_rx; ++ ++ skb = build_skb(data, PAGE_SIZE); ++ if (unlikely(!skb)) { ++ page_pool_put_full_page(ring->page_pool, ++ page, true); ++ netdev->stats.rx_dropped++; ++ goto skip_rx; ++ } ++ ++ skb_reserve(skb, xdp.data - xdp.data_hard_start); ++ skb_put(skb, xdp.data_end - xdp.data); ++ skb_mark_for_recycle(skb); + } else { + if (ring->frag_size <= PAGE_SIZE) + new_data = napi_alloc_frag(ring->frag_size); +@@ -1527,27 +1607,20 @@ static int mtk_poll_rx(struct napi_struc + + dma_unmap_single(eth->dma_dev, trxd.rxd1, + ring->buf_size, DMA_FROM_DEVICE); +- } + +- /* receive data */ +- skb = build_skb(data, ring->frag_size); +- if (unlikely(!skb)) { +- mtk_rx_put_buff(ring, data, true); +- netdev->stats.rx_dropped++; +- goto skip_rx; +- } ++ skb = build_skb(data, ring->frag_size); ++ if (unlikely(!skb)) { ++ netdev->stats.rx_dropped++; ++ skb_free_frag(data); ++ goto skip_rx; ++ } + +- if (ring->page_pool) { +- reserve_len = MTK_PP_HEADROOM; +- skb_mark_for_recycle(skb); +- } else { +- reserve_len = NET_SKB_PAD + NET_IP_ALIGN; ++ skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); ++ skb_put(skb, pktlen); + } +- skb_reserve(skb, reserve_len); + +- pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); + skb->dev = netdev; +- skb_put(skb, pktlen); ++ bytes += skb->len; + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) + rxdcsum = &trxd.rxd3; +@@ -1559,7 +1632,6 @@ static int mtk_poll_rx(struct napi_struc + else + skb_checksum_none_assert(skb); + skb->protocol = eth_type_trans(skb, netdev); +- bytes += pktlen; + + hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY; + if (hash != MTK_RXD4_FOE_ENTRY) { +@@ -1622,6 +1694,9 @@ rx_done: + &dim_sample); + net_dim(ð->rx_dim, dim_sample); + ++ if (xdp_flush) ++ xdp_do_flush_map(); ++ + return done; + } + +@@ -1967,7 +2042,7 @@ static int mtk_rx_alloc(struct mtk_eth * + if (!ring->data) + return -ENOMEM; + +- if (!eth->hwlro) { ++ if (mtk_page_pool_enabled(eth)) { + struct page_pool *pp; + + pp = mtk_create_page_pool(eth, &ring->xdp_q, ring_no, +@@ -2707,6 +2782,48 @@ static int mtk_stop(struct net_device *d + return 0; + } + ++static int mtk_xdp_setup(struct net_device *dev, struct bpf_prog *prog, ++ struct netlink_ext_ack *extack) ++{ ++ struct mtk_mac *mac = netdev_priv(dev); ++ struct mtk_eth *eth = mac->hw; ++ struct bpf_prog *old_prog; ++ bool need_update; ++ ++ if (eth->hwlro) { ++ NL_SET_ERR_MSG_MOD(extack, "XDP not supported with HWLRO"); ++ return -EOPNOTSUPP; ++ } ++ ++ if (dev->mtu > MTK_PP_MAX_BUF_SIZE) { ++ NL_SET_ERR_MSG_MOD(extack, "MTU too large for XDP"); ++ return -EOPNOTSUPP; ++ } ++ ++ need_update = !!eth->prog != !!prog; ++ if (netif_running(dev) && need_update) ++ mtk_stop(dev); ++ ++ old_prog = rcu_replace_pointer(eth->prog, prog, lockdep_rtnl_is_held()); ++ if (old_prog) ++ bpf_prog_put(old_prog); ++ ++ if (netif_running(dev) && need_update) ++ return mtk_open(dev); ++ ++ return 0; ++} ++ ++static int mtk_xdp(struct net_device *dev, struct netdev_bpf *xdp) ++{ ++ switch (xdp->command) { ++ case XDP_SETUP_PROG: ++ return mtk_xdp_setup(dev, xdp->prog, xdp->extack); ++ default: ++ return -EINVAL; ++ } ++} ++ + static void ethsys_reset(struct mtk_eth *eth, u32 reset_bits) + { + regmap_update_bits(eth->ethsys, ETHSYS_RSTCTRL, +@@ -3002,6 +3119,12 @@ static int mtk_change_mtu(struct net_dev + struct mtk_eth *eth = mac->hw; + u32 mcr_cur, mcr_new; + ++ if (rcu_access_pointer(eth->prog) && ++ length > MTK_PP_MAX_BUF_SIZE) { ++ netdev_err(dev, "Invalid MTU for XDP mode\n"); ++ return -EINVAL; ++ } ++ + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { + mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); + mcr_new = mcr_cur & ~MAC_MCR_MAX_RX_MASK; +@@ -3329,6 +3452,7 @@ static const struct net_device_ops mtk_n + .ndo_poll_controller = mtk_poll_controller, + #endif + .ndo_setup_tc = mtk_eth_setup_tc, ++ .ndo_bpf = mtk_xdp, + }; + + static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1085,6 +1085,8 @@ struct mtk_eth { + + struct mtk_ppe *ppe; + struct rhashtable flow_table; ++ ++ struct bpf_prog __rcu *prog; + }; + + /* struct mtk_mac - the structure that holds the info about the MACs of the diff --git a/target/linux/generic/backport-5.15/706-02-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-ethtool-count.patch b/target/linux/generic/backport-5.15/706-02-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-ethtool-count.patch new file mode 100644 index 0000000000..b68f44aae2 --- /dev/null +++ b/target/linux/generic/backport-5.15/706-02-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-ethtool-count.patch @@ -0,0 +1,110 @@ +From 916a6ee836d6b7b8ef1ed5f0515e256ca60e9968 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Fri, 22 Jul 2022 09:19:38 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: introduce xdp ethtool counters + +Report xdp stats through ethtool + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 26 +++++++++++++++++++-- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 12 ++++++++++ + 2 files changed, 36 insertions(+), 2 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -34,6 +34,10 @@ MODULE_PARM_DESC(msg_level, "Message lev + #define MTK_ETHTOOL_STAT(x) { #x, \ + offsetof(struct mtk_hw_stats, x) / sizeof(u64) } + ++#define MTK_ETHTOOL_XDP_STAT(x) { #x, \ ++ offsetof(struct mtk_hw_stats, xdp_stats.x) / \ ++ sizeof(u64) } ++ + static const struct mtk_reg_map mtk_reg_map = { + .tx_irq_mask = 0x1a1c, + .tx_irq_status = 0x1a18, +@@ -141,6 +145,13 @@ static const struct mtk_ethtool_stats { + MTK_ETHTOOL_STAT(rx_long_errors), + MTK_ETHTOOL_STAT(rx_checksum_errors), + MTK_ETHTOOL_STAT(rx_flow_control_packets), ++ MTK_ETHTOOL_XDP_STAT(rx_xdp_redirect), ++ MTK_ETHTOOL_XDP_STAT(rx_xdp_pass), ++ MTK_ETHTOOL_XDP_STAT(rx_xdp_drop), ++ MTK_ETHTOOL_XDP_STAT(rx_xdp_tx), ++ MTK_ETHTOOL_XDP_STAT(rx_xdp_tx_errors), ++ MTK_ETHTOOL_XDP_STAT(tx_xdp_xmit), ++ MTK_ETHTOOL_XDP_STAT(tx_xdp_xmit_errors), + }; + + static const char * const mtk_clks_source_name[] = { +@@ -1458,6 +1469,9 @@ static void mtk_rx_put_buff(struct mtk_r + static u32 mtk_xdp_run(struct mtk_eth *eth, struct mtk_rx_ring *ring, + struct xdp_buff *xdp, struct net_device *dev) + { ++ struct mtk_mac *mac = netdev_priv(dev); ++ struct mtk_hw_stats *hw_stats = mac->hw_stats; ++ u64 *count = &hw_stats->xdp_stats.rx_xdp_drop; + struct bpf_prog *prog; + u32 act = XDP_PASS; + +@@ -1470,13 +1484,16 @@ static u32 mtk_xdp_run(struct mtk_eth *e + act = bpf_prog_run_xdp(prog, xdp); + switch (act) { + case XDP_PASS: +- goto out; ++ count = &hw_stats->xdp_stats.rx_xdp_pass; ++ goto update_stats; + case XDP_REDIRECT: + if (unlikely(xdp_do_redirect(dev, xdp, prog))) { + act = XDP_DROP; + break; + } +- goto out; ++ ++ count = &hw_stats->xdp_stats.rx_xdp_redirect; ++ goto update_stats; + default: + bpf_warn_invalid_xdp_action(act); + fallthrough; +@@ -1489,6 +1506,11 @@ static u32 mtk_xdp_run(struct mtk_eth *e + + page_pool_put_full_page(ring->page_pool, + virt_to_head_page(xdp->data), true); ++ ++update_stats: ++ u64_stats_update_begin(&hw_stats->syncp); ++ *count = *count + 1; ++ u64_stats_update_end(&hw_stats->syncp); + out: + rcu_read_unlock(); + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -567,6 +567,16 @@ struct mtk_tx_dma_v2 { + struct mtk_eth; + struct mtk_mac; + ++struct mtk_xdp_stats { ++ u64 rx_xdp_redirect; ++ u64 rx_xdp_pass; ++ u64 rx_xdp_drop; ++ u64 rx_xdp_tx; ++ u64 rx_xdp_tx_errors; ++ u64 tx_xdp_xmit; ++ u64 tx_xdp_xmit_errors; ++}; ++ + /* struct mtk_hw_stats - the structure that holds the traffic statistics. + * @stats_lock: make sure that stats operations are atomic + * @reg_offset: the status register offset of the SoC +@@ -590,6 +600,8 @@ struct mtk_hw_stats { + u64 rx_checksum_errors; + u64 rx_flow_control_packets; + ++ struct mtk_xdp_stats xdp_stats; ++ + spinlock_t stats_lock; + u32 reg_offset; + struct u64_stats_sync syncp; diff --git a/target/linux/generic/backport-5.15/706-03-v6.0-net-ethernet-mtk_eth_soc-add-xmit-XDP-support.patch b/target/linux/generic/backport-5.15/706-03-v6.0-net-ethernet-mtk_eth_soc-add-xmit-XDP-support.patch new file mode 100644 index 0000000000..42b3ea215d --- /dev/null +++ b/target/linux/generic/backport-5.15/706-03-v6.0-net-ethernet-mtk_eth_soc-add-xmit-XDP-support.patch @@ -0,0 +1,340 @@ +From 5886d26fd25bbe26130e3e5f7474b9b3e98a3469 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Fri, 22 Jul 2022 09:19:39 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: add xmit XDP support + +Introduce XDP support for XDP_TX verdict and ndo_xdp_xmit function +pointer. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 192 +++++++++++++++++--- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 10 +- + 2 files changed, 180 insertions(+), 22 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -987,15 +987,26 @@ static void mtk_tx_unmap(struct mtk_eth + } + } + +- tx_buf->flags = 0; +- if (tx_buf->skb && +- (tx_buf->skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC)) { +- if (napi) +- napi_consume_skb(tx_buf->skb, napi); ++ if (tx_buf->type == MTK_TYPE_SKB) { ++ if (tx_buf->data && ++ tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { ++ struct sk_buff *skb = tx_buf->data; ++ ++ if (napi) ++ napi_consume_skb(skb, napi); ++ else ++ dev_kfree_skb_any(skb); ++ } ++ } else if (tx_buf->data) { ++ struct xdp_frame *xdpf = tx_buf->data; ++ ++ if (napi && tx_buf->type == MTK_TYPE_XDP_TX) ++ xdp_return_frame_rx_napi(xdpf); + else +- dev_kfree_skb_any(tx_buf->skb); ++ xdp_return_frame(xdpf); + } +- tx_buf->skb = NULL; ++ tx_buf->flags = 0; ++ tx_buf->data = NULL; + } + + static void setup_tx_buf(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, +@@ -1012,7 +1023,7 @@ static void setup_tx_buf(struct mtk_eth + dma_unmap_addr_set(tx_buf, dma_addr1, mapped_addr); + dma_unmap_len_set(tx_buf, dma_len1, size); + } else { +- tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC; ++ tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; + txd->txd1 = mapped_addr; + txd->txd2 = TX_DMA_PLEN0(size); + dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr); +@@ -1188,7 +1199,7 @@ static int mtk_tx_map(struct sk_buff *sk + soc->txrx.txd_size); + if (new_desc) + memset(tx_buf, 0, sizeof(*tx_buf)); +- tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC; ++ tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; + tx_buf->flags |= MTK_TX_FLAGS_PAGE0; + tx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 : + MTK_TX_FLAGS_FPORT1; +@@ -1202,7 +1213,8 @@ static int mtk_tx_map(struct sk_buff *sk + } + + /* store skb to cleanup */ +- itx_buf->skb = skb; ++ itx_buf->type = MTK_TYPE_SKB; ++ itx_buf->data = skb; + + if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { + if (k & 0x1) +@@ -1414,13 +1426,14 @@ static struct page_pool *mtk_create_page + .pool_size = size, + .nid = NUMA_NO_NODE, + .dev = eth->dma_dev, +- .dma_dir = DMA_FROM_DEVICE, + .offset = MTK_PP_HEADROOM, + .max_len = MTK_PP_MAX_BUF_SIZE, + }; + struct page_pool *pp; + int err; + ++ pp_params.dma_dir = rcu_access_pointer(eth->prog) ? DMA_BIDIRECTIONAL ++ : DMA_FROM_DEVICE; + pp = page_pool_create(&pp_params); + if (IS_ERR(pp)) + return pp; +@@ -1466,6 +1479,122 @@ static void mtk_rx_put_buff(struct mtk_r + skb_free_frag(data); + } + ++static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, ++ struct net_device *dev, bool dma_map) ++{ ++ const struct mtk_soc_data *soc = eth->soc; ++ struct mtk_tx_ring *ring = ð->tx_ring; ++ struct mtk_tx_dma_desc_info txd_info = { ++ .size = xdpf->len, ++ .first = true, ++ .last = true, ++ }; ++ struct mtk_mac *mac = netdev_priv(dev); ++ struct mtk_tx_dma *txd, *txd_pdma; ++ int err = 0, index = 0, n_desc = 1; ++ struct mtk_tx_buf *tx_buf; ++ ++ if (unlikely(test_bit(MTK_RESETTING, ð->state))) ++ return -EBUSY; ++ ++ if (unlikely(atomic_read(&ring->free_count) <= 1)) ++ return -EBUSY; ++ ++ spin_lock(ð->page_lock); ++ ++ txd = ring->next_free; ++ if (txd == ring->last_free) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->txrx.txd_size); ++ memset(tx_buf, 0, sizeof(*tx_buf)); ++ ++ if (dma_map) { /* ndo_xdp_xmit */ ++ txd_info.addr = dma_map_single(eth->dma_dev, xdpf->data, ++ txd_info.size, DMA_TO_DEVICE); ++ if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr))) { ++ err = -ENOMEM; ++ goto out; ++ } ++ tx_buf->flags |= MTK_TX_FLAGS_SINGLE0; ++ } else { ++ struct page *page = virt_to_head_page(xdpf->data); ++ ++ txd_info.addr = page_pool_get_dma_addr(page) + ++ sizeof(*xdpf) + xdpf->headroom; ++ dma_sync_single_for_device(eth->dma_dev, txd_info.addr, ++ txd_info.size, ++ DMA_BIDIRECTIONAL); ++ } ++ mtk_tx_set_dma_desc(dev, txd, &txd_info); ++ ++ tx_buf->flags |= !mac->id ? MTK_TX_FLAGS_FPORT0 : MTK_TX_FLAGS_FPORT1; ++ ++ txd_pdma = qdma_to_pdma(ring, txd); ++ setup_tx_buf(eth, tx_buf, txd_pdma, txd_info.addr, txd_info.size, ++ index++); ++ ++ /* store xdpf for cleanup */ ++ tx_buf->type = dma_map ? MTK_TYPE_XDP_NDO : MTK_TYPE_XDP_TX; ++ tx_buf->data = xdpf; ++ ++ if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { ++ if (index & 1) ++ txd_pdma->txd2 |= TX_DMA_LS0; ++ else ++ txd_pdma->txd2 |= TX_DMA_LS1; ++ } ++ ++ ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2); ++ atomic_sub(n_desc, &ring->free_count); ++ ++ /* make sure that all changes to the dma ring are flushed before we ++ * continue ++ */ ++ wmb(); ++ ++ if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { ++ mtk_w32(eth, txd->txd2, soc->reg_map->qdma.ctx_ptr); ++ } else { ++ int idx; ++ ++ idx = txd_to_idx(ring, txd, soc->txrx.txd_size); ++ mtk_w32(eth, NEXT_DESP_IDX(idx, ring->dma_size), ++ MT7628_TX_CTX_IDX0); ++ } ++out: ++ spin_unlock(ð->page_lock); ++ ++ return err; ++} ++ ++static int mtk_xdp_xmit(struct net_device *dev, int num_frame, ++ struct xdp_frame **frames, u32 flags) ++{ ++ struct mtk_mac *mac = netdev_priv(dev); ++ struct mtk_hw_stats *hw_stats = mac->hw_stats; ++ struct mtk_eth *eth = mac->hw; ++ int i, nxmit = 0; ++ ++ if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) ++ return -EINVAL; ++ ++ for (i = 0; i < num_frame; i++) { ++ if (mtk_xdp_submit_frame(eth, frames[i], dev, true)) ++ break; ++ nxmit++; ++ } ++ ++ u64_stats_update_begin(&hw_stats->syncp); ++ hw_stats->xdp_stats.tx_xdp_xmit += nxmit; ++ hw_stats->xdp_stats.tx_xdp_xmit_errors += num_frame - nxmit; ++ u64_stats_update_end(&hw_stats->syncp); ++ ++ return nxmit; ++} ++ + static u32 mtk_xdp_run(struct mtk_eth *eth, struct mtk_rx_ring *ring, + struct xdp_buff *xdp, struct net_device *dev) + { +@@ -1494,6 +1623,18 @@ static u32 mtk_xdp_run(struct mtk_eth *e + + count = &hw_stats->xdp_stats.rx_xdp_redirect; + goto update_stats; ++ case XDP_TX: { ++ struct xdp_frame *xdpf = xdp_convert_buff_to_frame(xdp); ++ ++ if (mtk_xdp_submit_frame(eth, xdpf, dev, false)) { ++ count = &hw_stats->xdp_stats.rx_xdp_tx_errors; ++ act = XDP_DROP; ++ break; ++ } ++ ++ count = &hw_stats->xdp_stats.rx_xdp_tx; ++ goto update_stats; ++ } + default: + bpf_warn_invalid_xdp_action(act); + fallthrough; +@@ -1727,9 +1868,8 @@ static int mtk_poll_tx_qdma(struct mtk_e + { + const struct mtk_reg_map *reg_map = eth->soc->reg_map; + struct mtk_tx_ring *ring = ð->tx_ring; +- struct mtk_tx_dma *desc; +- struct sk_buff *skb; + struct mtk_tx_buf *tx_buf; ++ struct mtk_tx_dma *desc; + u32 cpu, dma; + + cpu = ring->last_free_ptr; +@@ -1750,15 +1890,21 @@ static int mtk_poll_tx_qdma(struct mtk_e + if (tx_buf->flags & MTK_TX_FLAGS_FPORT1) + mac = 1; + +- skb = tx_buf->skb; +- if (!skb) ++ if (!tx_buf->data) + break; + +- if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) { ++ if (tx_buf->type == MTK_TYPE_SKB && ++ tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { ++ struct sk_buff *skb = tx_buf->data; ++ + bytes[mac] += skb->len; + done[mac]++; + budget--; ++ } else if (tx_buf->type == MTK_TYPE_XDP_TX || ++ tx_buf->type == MTK_TYPE_XDP_NDO) { ++ budget--; + } ++ + mtk_tx_unmap(eth, tx_buf, true); + + ring->last_free = desc; +@@ -1777,9 +1923,8 @@ static int mtk_poll_tx_pdma(struct mtk_e + unsigned int *done, unsigned int *bytes) + { + struct mtk_tx_ring *ring = ð->tx_ring; +- struct mtk_tx_dma *desc; +- struct sk_buff *skb; + struct mtk_tx_buf *tx_buf; ++ struct mtk_tx_dma *desc; + u32 cpu, dma; + + cpu = ring->cpu_idx; +@@ -1787,14 +1932,18 @@ static int mtk_poll_tx_pdma(struct mtk_e + + while ((cpu != dma) && budget) { + tx_buf = &ring->buf[cpu]; +- skb = tx_buf->skb; +- if (!skb) ++ if (!tx_buf->data) + break; + +- if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) { ++ if (tx_buf->type == MTK_TYPE_SKB && ++ tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { ++ struct sk_buff *skb = tx_buf->data; + bytes[0] += skb->len; + done[0]++; + budget--; ++ } else if (tx_buf->type == MTK_TYPE_XDP_TX || ++ tx_buf->type == MTK_TYPE_XDP_NDO) { ++ budget--; + } + + mtk_tx_unmap(eth, tx_buf, true); +@@ -3475,6 +3624,7 @@ static const struct net_device_ops mtk_n + #endif + .ndo_setup_tc = mtk_eth_setup_tc, + .ndo_bpf = mtk_xdp, ++ .ndo_xdp_xmit = mtk_xdp_xmit, + }; + + static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -693,6 +693,12 @@ enum mtk_dev_state { + MTK_RESETTING + }; + ++enum mtk_tx_buf_type { ++ MTK_TYPE_SKB, ++ MTK_TYPE_XDP_TX, ++ MTK_TYPE_XDP_NDO, ++}; ++ + /* struct mtk_tx_buf - This struct holds the pointers to the memory pointed at + * by the TX descriptor s + * @skb: The SKB pointer of the packet being sent +@@ -702,7 +708,9 @@ enum mtk_dev_state { + * @dma_len1: The length of the second segment + */ + struct mtk_tx_buf { +- struct sk_buff *skb; ++ enum mtk_tx_buf_type type; ++ void *data; ++ + u32 flags; + DEFINE_DMA_UNMAP_ADDR(dma_addr0); + DEFINE_DMA_UNMAP_LEN(dma_len0); diff --git a/target/linux/generic/backport-5.15/706-04-v6.0-net-ethernet-mtk_eth_soc-add-support-for-page_pool_g.patch b/target/linux/generic/backport-5.15/706-04-v6.0-net-ethernet-mtk_eth_soc-add-support-for-page_pool_g.patch new file mode 100644 index 0000000000..d372f022c7 --- /dev/null +++ b/target/linux/generic/backport-5.15/706-04-v6.0-net-ethernet-mtk_eth_soc-add-support-for-page_pool_g.patch @@ -0,0 +1,95 @@ +From 84b9cd389036d4a262d8cee794d56c04095358a7 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Fri, 22 Jul 2022 09:19:40 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: add support for + page_pool_get_stats + +Introduce support for the page_pool stats API into mtk_eth_soc driver. +Report page_pool stats through ethtool. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/Kconfig | 1 + + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 37 +++++++++++++++++++-- + 2 files changed, 35 insertions(+), 3 deletions(-) + +--- a/drivers/net/ethernet/mediatek/Kconfig ++++ b/drivers/net/ethernet/mediatek/Kconfig +@@ -17,6 +17,7 @@ config NET_MEDIATEK_SOC + select PHYLINK + select DIMLIB + select PAGE_POOL ++ select PAGE_POOL_STATS + help + This driver supports the gigabit ethernet MACs in the + MediaTek SoC family. +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3485,11 +3485,18 @@ static void mtk_get_strings(struct net_d + int i; + + switch (stringset) { +- case ETH_SS_STATS: ++ case ETH_SS_STATS: { ++ struct mtk_mac *mac = netdev_priv(dev); ++ + for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++) { + memcpy(data, mtk_ethtool_stats[i].str, ETH_GSTRING_LEN); + data += ETH_GSTRING_LEN; + } ++ if (mtk_page_pool_enabled(mac->hw)) ++ page_pool_ethtool_stats_get_strings(data); ++ break; ++ } ++ default: + break; + } + } +@@ -3497,13 +3504,35 @@ static void mtk_get_strings(struct net_d + static int mtk_get_sset_count(struct net_device *dev, int sset) + { + switch (sset) { +- case ETH_SS_STATS: +- return ARRAY_SIZE(mtk_ethtool_stats); ++ case ETH_SS_STATS: { ++ int count = ARRAY_SIZE(mtk_ethtool_stats); ++ struct mtk_mac *mac = netdev_priv(dev); ++ ++ if (mtk_page_pool_enabled(mac->hw)) ++ count += page_pool_ethtool_stats_get_count(); ++ return count; ++ } + default: + return -EOPNOTSUPP; + } + } + ++static void mtk_ethtool_pp_stats(struct mtk_eth *eth, u64 *data) ++{ ++ struct page_pool_stats stats = {}; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(eth->rx_ring); i++) { ++ struct mtk_rx_ring *ring = ð->rx_ring[i]; ++ ++ if (!ring->page_pool) ++ continue; ++ ++ page_pool_get_stats(ring->page_pool, &stats); ++ } ++ page_pool_ethtool_stats_get(data, &stats); ++} ++ + static void mtk_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) + { +@@ -3531,6 +3560,8 @@ static void mtk_get_ethtool_stats(struct + + for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++) + *data_dst++ = *(data_src + mtk_ethtool_stats[i].offset); ++ if (mtk_page_pool_enabled(mac->hw)) ++ mtk_ethtool_pp_stats(mac->hw, data_dst); + } while (u64_stats_fetch_retry_irq(&hwstats->syncp, start)); + } + diff --git a/target/linux/generic/backport-5.15/706-05-v6.0-net-ethernet-mtk_eth_soc-introduce-mtk_xdp_frame_map.patch b/target/linux/generic/backport-5.15/706-05-v6.0-net-ethernet-mtk_eth_soc-introduce-mtk_xdp_frame_map.patch new file mode 100644 index 0000000000..33a7616652 --- /dev/null +++ b/target/linux/generic/backport-5.15/706-05-v6.0-net-ethernet-mtk_eth_soc-introduce-mtk_xdp_frame_map.patch @@ -0,0 +1,113 @@ +From b16fe6d82b71fa0dd5c957bc22d66a694976d6eb Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Wed, 27 Jul 2022 23:20:50 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: introduce mtk_xdp_frame_map + utility routine + +This is a preliminary patch to add xdp multi-frag support to mtk_eth_soc +driver + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 68 +++++++++++++-------- + 1 file changed, 42 insertions(+), 26 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1479,6 +1479,41 @@ static void mtk_rx_put_buff(struct mtk_r + skb_free_frag(data); + } + ++static int mtk_xdp_frame_map(struct mtk_eth *eth, struct net_device *dev, ++ struct mtk_tx_dma_desc_info *txd_info, ++ struct mtk_tx_dma *txd, struct mtk_tx_buf *tx_buf, ++ void *data, u16 headroom, int index, bool dma_map) ++{ ++ struct mtk_tx_ring *ring = ð->tx_ring; ++ struct mtk_mac *mac = netdev_priv(dev); ++ struct mtk_tx_dma *txd_pdma; ++ ++ if (dma_map) { /* ndo_xdp_xmit */ ++ txd_info->addr = dma_map_single(eth->dma_dev, data, ++ txd_info->size, DMA_TO_DEVICE); ++ if (unlikely(dma_mapping_error(eth->dma_dev, txd_info->addr))) ++ return -ENOMEM; ++ ++ tx_buf->flags |= MTK_TX_FLAGS_SINGLE0; ++ } else { ++ struct page *page = virt_to_head_page(data); ++ ++ txd_info->addr = page_pool_get_dma_addr(page) + ++ sizeof(struct xdp_frame) + headroom; ++ dma_sync_single_for_device(eth->dma_dev, txd_info->addr, ++ txd_info->size, DMA_BIDIRECTIONAL); ++ } ++ mtk_tx_set_dma_desc(dev, txd, txd_info); ++ ++ tx_buf->flags |= !mac->id ? MTK_TX_FLAGS_FPORT0 : MTK_TX_FLAGS_FPORT1; ++ ++ txd_pdma = qdma_to_pdma(ring, txd); ++ setup_tx_buf(eth, tx_buf, txd_pdma, txd_info->addr, txd_info->size, ++ index); ++ ++ return 0; ++} ++ + static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, + struct net_device *dev, bool dma_map) + { +@@ -1489,9 +1524,8 @@ static int mtk_xdp_submit_frame(struct m + .first = true, + .last = true, + }; +- struct mtk_mac *mac = netdev_priv(dev); +- struct mtk_tx_dma *txd, *txd_pdma; + int err = 0, index = 0, n_desc = 1; ++ struct mtk_tx_dma *txd, *txd_pdma; + struct mtk_tx_buf *tx_buf; + + if (unlikely(test_bit(MTK_RESETTING, ð->state))) +@@ -1511,36 +1545,18 @@ static int mtk_xdp_submit_frame(struct m + tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->txrx.txd_size); + memset(tx_buf, 0, sizeof(*tx_buf)); + +- if (dma_map) { /* ndo_xdp_xmit */ +- txd_info.addr = dma_map_single(eth->dma_dev, xdpf->data, +- txd_info.size, DMA_TO_DEVICE); +- if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr))) { +- err = -ENOMEM; +- goto out; +- } +- tx_buf->flags |= MTK_TX_FLAGS_SINGLE0; +- } else { +- struct page *page = virt_to_head_page(xdpf->data); +- +- txd_info.addr = page_pool_get_dma_addr(page) + +- sizeof(*xdpf) + xdpf->headroom; +- dma_sync_single_for_device(eth->dma_dev, txd_info.addr, +- txd_info.size, +- DMA_BIDIRECTIONAL); +- } +- mtk_tx_set_dma_desc(dev, txd, &txd_info); +- +- tx_buf->flags |= !mac->id ? MTK_TX_FLAGS_FPORT0 : MTK_TX_FLAGS_FPORT1; +- +- txd_pdma = qdma_to_pdma(ring, txd); +- setup_tx_buf(eth, tx_buf, txd_pdma, txd_info.addr, txd_info.size, +- index++); ++ err = mtk_xdp_frame_map(eth, dev, &txd_info, txd, tx_buf, ++ xdpf->data, xdpf->headroom, index, ++ dma_map); ++ if (err < 0) ++ goto out; + + /* store xdpf for cleanup */ + tx_buf->type = dma_map ? MTK_TYPE_XDP_NDO : MTK_TYPE_XDP_TX; + tx_buf->data = xdpf; + + if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { ++ txd_pdma = qdma_to_pdma(ring, txd); + if (index & 1) + txd_pdma->txd2 |= TX_DMA_LS0; + else diff --git a/target/linux/generic/backport-5.15/706-06-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-multi-frag-su.patch b/target/linux/generic/backport-5.15/706-06-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-multi-frag-su.patch new file mode 100644 index 0000000000..e75861bc82 --- /dev/null +++ b/target/linux/generic/backport-5.15/706-06-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-multi-frag-su.patch @@ -0,0 +1,218 @@ +From 155738a4f319538a09f734ce1f5a2eac3ada1de2 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Wed, 27 Jul 2022 23:20:51 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: introduce xdp multi-frag support + +Add the capability to map non-linear xdp frames in XDP_TX and +ndo_xdp_xmit callback. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 125 +++++++++++++------- + 1 file changed, 82 insertions(+), 43 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -987,23 +987,22 @@ static void mtk_tx_unmap(struct mtk_eth + } + } + +- if (tx_buf->type == MTK_TYPE_SKB) { +- if (tx_buf->data && +- tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { ++ if (tx_buf->data && tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { ++ if (tx_buf->type == MTK_TYPE_SKB) { + struct sk_buff *skb = tx_buf->data; + + if (napi) + napi_consume_skb(skb, napi); + else + dev_kfree_skb_any(skb); +- } +- } else if (tx_buf->data) { +- struct xdp_frame *xdpf = tx_buf->data; ++ } else { ++ struct xdp_frame *xdpf = tx_buf->data; + +- if (napi && tx_buf->type == MTK_TYPE_XDP_TX) +- xdp_return_frame_rx_napi(xdpf); +- else +- xdp_return_frame(xdpf); ++ if (napi && tx_buf->type == MTK_TYPE_XDP_TX) ++ xdp_return_frame_rx_napi(xdpf); ++ else ++ xdp_return_frame(xdpf); ++ } + } + tx_buf->flags = 0; + tx_buf->data = NULL; +@@ -1506,6 +1505,8 @@ static int mtk_xdp_frame_map(struct mtk_ + mtk_tx_set_dma_desc(dev, txd, txd_info); + + tx_buf->flags |= !mac->id ? MTK_TX_FLAGS_FPORT0 : MTK_TX_FLAGS_FPORT1; ++ tx_buf->type = dma_map ? MTK_TYPE_XDP_NDO : MTK_TYPE_XDP_TX; ++ tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; + + txd_pdma = qdma_to_pdma(ring, txd); + setup_tx_buf(eth, tx_buf, txd_pdma, txd_info->addr, txd_info->size, +@@ -1517,43 +1518,69 @@ static int mtk_xdp_frame_map(struct mtk_ + static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, + struct net_device *dev, bool dma_map) + { ++ struct skb_shared_info *sinfo = xdp_get_shared_info_from_frame(xdpf); + const struct mtk_soc_data *soc = eth->soc; + struct mtk_tx_ring *ring = ð->tx_ring; + struct mtk_tx_dma_desc_info txd_info = { + .size = xdpf->len, + .first = true, +- .last = true, ++ .last = !xdp_frame_has_frags(xdpf), + }; +- int err = 0, index = 0, n_desc = 1; +- struct mtk_tx_dma *txd, *txd_pdma; +- struct mtk_tx_buf *tx_buf; ++ int err, index = 0, n_desc = 1, nr_frags; ++ struct mtk_tx_dma *htxd, *txd, *txd_pdma; ++ struct mtk_tx_buf *htx_buf, *tx_buf; ++ void *data = xdpf->data; + + if (unlikely(test_bit(MTK_RESETTING, ð->state))) + return -EBUSY; + +- if (unlikely(atomic_read(&ring->free_count) <= 1)) ++ nr_frags = unlikely(xdp_frame_has_frags(xdpf)) ? sinfo->nr_frags : 0; ++ if (unlikely(atomic_read(&ring->free_count) <= 1 + nr_frags)) + return -EBUSY; + + spin_lock(ð->page_lock); + + txd = ring->next_free; + if (txd == ring->last_free) { +- err = -ENOMEM; +- goto out; ++ spin_unlock(ð->page_lock); ++ return -ENOMEM; + } ++ htxd = txd; + + tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->txrx.txd_size); + memset(tx_buf, 0, sizeof(*tx_buf)); ++ htx_buf = tx_buf; + +- err = mtk_xdp_frame_map(eth, dev, &txd_info, txd, tx_buf, +- xdpf->data, xdpf->headroom, index, +- dma_map); +- if (err < 0) +- goto out; ++ for (;;) { ++ err = mtk_xdp_frame_map(eth, dev, &txd_info, txd, tx_buf, ++ data, xdpf->headroom, index, dma_map); ++ if (err < 0) ++ goto unmap; ++ ++ if (txd_info.last) ++ break; + ++ if (MTK_HAS_CAPS(soc->caps, MTK_QDMA) || (index & 0x1)) { ++ txd = mtk_qdma_phys_to_virt(ring, txd->txd2); ++ txd_pdma = qdma_to_pdma(ring, txd); ++ if (txd == ring->last_free) ++ goto unmap; ++ ++ tx_buf = mtk_desc_to_tx_buf(ring, txd, ++ soc->txrx.txd_size); ++ memset(tx_buf, 0, sizeof(*tx_buf)); ++ n_desc++; ++ } ++ ++ memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info)); ++ txd_info.size = skb_frag_size(&sinfo->frags[index]); ++ txd_info.last = index + 1 == nr_frags; ++ data = skb_frag_address(&sinfo->frags[index]); ++ ++ index++; ++ } + /* store xdpf for cleanup */ +- tx_buf->type = dma_map ? MTK_TYPE_XDP_NDO : MTK_TYPE_XDP_TX; +- tx_buf->data = xdpf; ++ htx_buf->data = xdpf; + + if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { + txd_pdma = qdma_to_pdma(ring, txd); +@@ -1580,7 +1607,24 @@ static int mtk_xdp_submit_frame(struct m + mtk_w32(eth, NEXT_DESP_IDX(idx, ring->dma_size), + MT7628_TX_CTX_IDX0); + } +-out: ++ ++ spin_unlock(ð->page_lock); ++ ++ return 0; ++ ++unmap: ++ while (htxd != txd) { ++ txd_pdma = qdma_to_pdma(ring, htxd); ++ tx_buf = mtk_desc_to_tx_buf(ring, htxd, soc->txrx.txd_size); ++ mtk_tx_unmap(eth, tx_buf, false); ++ ++ htxd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; ++ if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) ++ txd_pdma->txd2 = TX_DMA_DESP2_DEF; ++ ++ htxd = mtk_qdma_phys_to_virt(ring, htxd->txd2); ++ } ++ + spin_unlock(ð->page_lock); + + return err; +@@ -1909,18 +1953,15 @@ static int mtk_poll_tx_qdma(struct mtk_e + if (!tx_buf->data) + break; + +- if (tx_buf->type == MTK_TYPE_SKB && +- tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { +- struct sk_buff *skb = tx_buf->data; ++ if (tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { ++ if (tx_buf->type == MTK_TYPE_SKB) { ++ struct sk_buff *skb = tx_buf->data; + +- bytes[mac] += skb->len; +- done[mac]++; +- budget--; +- } else if (tx_buf->type == MTK_TYPE_XDP_TX || +- tx_buf->type == MTK_TYPE_XDP_NDO) { ++ bytes[mac] += skb->len; ++ done[mac]++; ++ } + budget--; + } +- + mtk_tx_unmap(eth, tx_buf, true); + + ring->last_free = desc; +@@ -1951,17 +1992,15 @@ static int mtk_poll_tx_pdma(struct mtk_e + if (!tx_buf->data) + break; + +- if (tx_buf->type == MTK_TYPE_SKB && +- tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { +- struct sk_buff *skb = tx_buf->data; +- bytes[0] += skb->len; +- done[0]++; +- budget--; +- } else if (tx_buf->type == MTK_TYPE_XDP_TX || +- tx_buf->type == MTK_TYPE_XDP_NDO) { ++ if (tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { ++ if (tx_buf->type == MTK_TYPE_SKB) { ++ struct sk_buff *skb = tx_buf->data; ++ ++ bytes[0] += skb->len; ++ done[0]++; ++ } + budget--; + } +- + mtk_tx_unmap(eth, tx_buf, true); + + desc = ring->dma + cpu * eth->soc->txrx.txd_size; diff --git a/target/linux/generic/backport-5.15/710-v6.0-net-ethernet-mtk_eth_soc-fix-hw-hash-reporting-for-M.patch b/target/linux/generic/backport-5.15/710-v6.0-net-ethernet-mtk_eth_soc-fix-hw-hash-reporting-for-M.patch index 87941ef766..a3842d35f5 100644 --- a/target/linux/generic/backport-5.15/710-v6.0-net-ethernet-mtk_eth_soc-fix-hw-hash-reporting-for-M.patch +++ b/target/linux/generic/backport-5.15/710-v6.0-net-ethernet-mtk_eth_soc-fix-hw-hash-reporting-for-M.patch @@ -18,9 +18,9 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1469,10 +1469,19 @@ static int mtk_poll_rx(struct napi_struc +@@ -1845,10 +1845,19 @@ static int mtk_poll_rx(struct napi_struc skb->dev = netdev; - skb_put(skb, pktlen); + bytes += skb->len; - if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { @@ -40,9 +40,9 @@ Signed-off-by: Paolo Abeni if (*rxdcsum & eth->soc->txrx.rx_dma_l4_valid) skb->ip_summed = CHECKSUM_UNNECESSARY; -@@ -1481,16 +1490,9 @@ static int mtk_poll_rx(struct napi_struc +@@ -1856,16 +1865,9 @@ static int mtk_poll_rx(struct napi_struc + skb_checksum_none_assert(skb); skb->protocol = eth_type_trans(skb, netdev); - bytes += pktlen; - hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY; - if (hash != MTK_RXD4_FOE_ENTRY) { @@ -60,7 +60,7 @@ Signed-off-by: Paolo Abeni if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -307,6 +307,11 @@ +@@ -314,6 +314,11 @@ #define RX_DMA_L4_VALID_PDMA BIT(30) /* when PDMA is used */ #define RX_DMA_SPECIAL_TAG BIT(22) diff --git a/target/linux/generic/backport-5.15/711-v6.0-04-net-ethernet-mtk_eth_soc-remove-mtk_foe_entry_timest.patch b/target/linux/generic/backport-5.15/711-v6.0-04-net-ethernet-mtk_eth_soc-remove-mtk_foe_entry_timest.patch new file mode 100644 index 0000000000..3c28e83551 --- /dev/null +++ b/target/linux/generic/backport-5.15/711-v6.0-04-net-ethernet-mtk_eth_soc-remove-mtk_foe_entry_timest.patch @@ -0,0 +1,33 @@ +From c9daab322313087afde8c46f41df3c628410ae20 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Mon, 5 Sep 2022 14:46:01 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: remove mtk_foe_entry_timestamp + +Get rid of mtk_foe_entry_timestamp routine since it is no longer used. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_ppe.h | 11 ----------- + 1 file changed, 11 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -302,17 +302,6 @@ mtk_ppe_check_skb(struct mtk_ppe *ppe, s + __mtk_ppe_check_skb(ppe, skb, hash); + } + +-static inline int +-mtk_foe_entry_timestamp(struct mtk_ppe *ppe, u16 hash) +-{ +- u32 ib1 = READ_ONCE(ppe->foe_table[hash].ib1); +- +- if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND) +- return -1; +- +- return FIELD_GET(MTK_FOE_IB1_BIND_TIMESTAMP, ib1); +-} +- + int mtk_foe_entry_prepare(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_foe_entry *entry, u8 port); diff --git a/target/linux/generic/backport-5.15/712-v6.0-net-ethernet-mtk_eth_soc-enable-XDP-support-just-for.patch b/target/linux/generic/backport-5.15/712-v6.0-net-ethernet-mtk_eth_soc-enable-XDP-support-just-for.patch new file mode 100644 index 0000000000..f4eb030ef6 --- /dev/null +++ b/target/linux/generic/backport-5.15/712-v6.0-net-ethernet-mtk_eth_soc-enable-XDP-support-just-for.patch @@ -0,0 +1,35 @@ +From 5e69163d3b9931098922b3fc2f8e786af8c1f37e Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Tue, 13 Sep 2022 15:03:05 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: enable XDP support just for + MT7986 SoC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Disable page_pool/XDP support for MT7621 SoC in order fix a regression +introduce adding XDP for MT7986 SoC. There is no a real use case for XDP +on MT7621 since it is a low-end cpu. Moreover this patch reduces the +memory footprint. + +Tested-by: Sergio Paracuellos +Tested-by: Arınç ÜNAL +Fixes: 23233e577ef9 ("net: ethernet: mtk_eth_soc: rely on page_pool for single page buffers") +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/2bf31e27b888c43228b0d84dd2ef5033338269e2.1663074002.git.lorenzo@kernel.org +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1412,7 +1412,7 @@ static void mtk_update_rx_cpu_idx(struct + + static bool mtk_page_pool_enabled(struct mtk_eth *eth) + { +- return !eth->hwlro; ++ return MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2); + } + + static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth, diff --git a/target/linux/generic/hack-5.15/721-net-add-packet-mangeling.patch b/target/linux/generic/hack-5.15/721-net-add-packet-mangeling.patch index 237933a4df..206e16cb17 100644 --- a/target/linux/generic/hack-5.15/721-net-add-packet-mangeling.patch +++ b/target/linux/generic/hack-5.15/721-net-add-packet-mangeling.patch @@ -71,7 +71,7 @@ Signed-off-by: Felix Fietkau */ --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h -@@ -2851,6 +2851,10 @@ static inline int pskb_trim(struct sk_bu +@@ -2852,6 +2852,10 @@ static inline int pskb_trim(struct sk_bu return (len < skb->len) ? __pskb_trim(skb, len) : 0; } @@ -82,7 +82,7 @@ Signed-off-by: Felix Fietkau /** * pskb_trim_unique - remove end from a paged unique (not cloned) buffer * @skb: buffer to alter -@@ -3001,16 +3005,6 @@ static inline struct sk_buff *dev_alloc_ +@@ -3002,16 +3006,6 @@ static inline struct sk_buff *dev_alloc_ } diff --git a/target/linux/generic/pending-5.15/655-increase_skb_pad.patch b/target/linux/generic/pending-5.15/655-increase_skb_pad.patch index bb8b7d982d..7fc1c588b3 100644 --- a/target/linux/generic/pending-5.15/655-increase_skb_pad.patch +++ b/target/linux/generic/pending-5.15/655-increase_skb_pad.patch @@ -9,7 +9,7 @@ Signed-off-by: Felix Fietkau --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h -@@ -2817,7 +2817,7 @@ static inline int pskb_network_may_pull( +@@ -2818,7 +2818,7 @@ static inline int pskb_network_may_pull( * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8) */ #ifndef NET_SKB_PAD diff --git a/target/linux/generic/pending-5.15/680-NET-skip-GRO-for-foreign-MAC-addresses.patch b/target/linux/generic/pending-5.15/680-NET-skip-GRO-for-foreign-MAC-addresses.patch index 233d7b6563..41190fcfd4 100644 --- a/target/linux/generic/pending-5.15/680-NET-skip-GRO-for-foreign-MAC-addresses.patch +++ b/target/linux/generic/pending-5.15/680-NET-skip-GRO-for-foreign-MAC-addresses.patch @@ -22,7 +22,7 @@ Signed-off-by: Felix Fietkau #endif --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h -@@ -890,6 +890,7 @@ struct sk_buff { +@@ -891,6 +891,7 @@ struct sk_buff { #ifdef CONFIG_IPV6_NDISC_NODETYPE __u8 ndisc_nodetype:2; #endif diff --git a/target/linux/generic/pending-5.15/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch b/target/linux/generic/pending-5.15/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch index 298122375f..49c6ea1c03 100644 --- a/target/linux/generic/pending-5.15/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch +++ b/target/linux/generic/pending-5.15/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch @@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -2383,8 +2383,8 @@ static irqreturn_t mtk_handle_irq_rx(int +@@ -2789,8 +2789,8 @@ static irqreturn_t mtk_handle_irq_rx(int eth->rx_events++; if (likely(napi_schedule_prep(ð->rx_napi))) { @@ -20,7 +20,7 @@ Signed-off-by: Felix Fietkau } return IRQ_HANDLED; -@@ -2396,8 +2396,8 @@ static irqreturn_t mtk_handle_irq_tx(int +@@ -2802,8 +2802,8 @@ static irqreturn_t mtk_handle_irq_tx(int eth->tx_events++; if (likely(napi_schedule_prep(ð->tx_napi))) { @@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau } return IRQ_HANDLED; -@@ -3587,6 +3587,8 @@ static int mtk_probe(struct platform_dev +@@ -4074,6 +4074,8 @@ static int mtk_probe(struct platform_dev * for NAPI to work */ init_dummy_netdev(ð->dummy_dev); diff --git a/target/linux/generic/pending-5.15/781-net-ethernet-mtk_eth_soc-move-gdma_to_ppe-and-ppe_ba.patch b/target/linux/generic/pending-5.15/781-net-ethernet-mtk_eth_soc-move-gdma_to_ppe-and-ppe_ba.patch new file mode 100644 index 0000000000..008e20416d --- /dev/null +++ b/target/linux/generic/pending-5.15/781-net-ethernet-mtk_eth_soc-move-gdma_to_ppe-and-ppe_ba.patch @@ -0,0 +1,127 @@ +From patchwork Thu Sep 8 19:33:38 2022 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Lorenzo Bianconi +X-Patchwork-Id: 12970556 +X-Patchwork-Delegate: kuba@kernel.org +From: Lorenzo Bianconi +To: netdev@vger.kernel.org +Cc: nbd@nbd.name, john@phrozen.org, sean.wang@mediatek.com, + Mark-MC.Lee@mediatek.com, davem@davemloft.net, edumazet@google.com, + kuba@kernel.org, pabeni@redhat.com, matthias.bgg@gmail.com, + linux-mediatek@lists.infradead.org, lorenzo.bianconi@redhat.com, + Bo.Jiao@mediatek.com, sujuan.chen@mediatek.com, + ryder.Lee@mediatek.com, evelyn.tsai@mediatek.com, + devicetree@vger.kernel.org, robh@kernel.org +Subject: [PATCH net-next 03/12] net: ethernet: mtk_eth_soc: move gdma_to_ppe + and ppe_base definitions in mtk register map +Date: Thu, 8 Sep 2022 21:33:37 +0200 +Message-Id: + <95938fc9cbe0223714be2658a49ca58e9baace00.1662661555.git.lorenzo@kernel.org> +X-Mailer: git-send-email 2.37.3 +In-Reply-To: +References: +MIME-Version: 1.0 +Precedence: bulk +List-ID: +X-Mailing-List: netdev@vger.kernel.org +X-Patchwork-Delegate: kuba@kernel.org + +This is a preliminary patch to introduce mt7986 hw packet engine. + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 15 +++++++++++---- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 3 ++- + drivers/net/ethernet/mediatek/mtk_ppe.h | 2 -- + 3 files changed, 13 insertions(+), 7 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -73,6 +73,8 @@ static const struct mtk_reg_map mtk_reg_ + .fq_blen = 0x1b2c, + }, + .gdm1_cnt = 0x2400, ++ .gdma_to_ppe0 = 0x4444, ++ .ppe_base = 0x0c00, + }; + + static const struct mtk_reg_map mt7628_reg_map = { +@@ -126,6 +128,8 @@ static const struct mtk_reg_map mt7986_r + .fq_blen = 0x472c, + }, + .gdm1_cnt = 0x1c00, ++ .gdma_to_ppe0 = 0x3333, ++ .ppe_base = 0x2000, + }; + + /* strings used by ethtool */ +@@ -2924,6 +2928,7 @@ static int mtk_open(struct net_device *d + + /* we run 2 netdevs on the same dma ring so we only bring it up once */ + if (!refcount_read(ð->dma_refcnt)) { ++ const struct mtk_soc_data *soc = eth->soc; + u32 gdm_config = MTK_GDMA_TO_PDMA; + int err; + +@@ -2931,15 +2936,15 @@ static int mtk_open(struct net_device *d + if (err) + return err; + +- if (eth->soc->offload_version && mtk_ppe_start(eth->ppe) == 0) +- gdm_config = MTK_GDMA_TO_PPE; ++ if (soc->offload_version && mtk_ppe_start(eth->ppe) == 0) ++ gdm_config = soc->reg_map->gdma_to_ppe0; + + mtk_gdm_config(eth, gdm_config); + + napi_enable(ð->tx_napi); + napi_enable(ð->rx_napi); + mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); +- mtk_rx_irq_enable(eth, eth->soc->txrx.rx_irq_done_mask); ++ mtk_rx_irq_enable(eth, soc->txrx.rx_irq_done_mask); + refcount_set(ð->dma_refcnt, 1); + } + else +@@ -4045,7 +4050,9 @@ static int mtk_probe(struct platform_dev + } + + if (eth->soc->offload_version) { +- eth->ppe = mtk_ppe_init(eth, eth->base + MTK_ETH_PPE_BASE, 2); ++ u32 ppe_addr = eth->soc->reg_map->ppe_base; ++ ++ eth->ppe = mtk_ppe_init(eth, eth->base + ppe_addr, 2); + if (!eth->ppe) { + err = -ENOMEM; + goto err_free_dev; +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -105,7 +105,6 @@ + #define MTK_GDMA_TCS_EN BIT(21) + #define MTK_GDMA_UCS_EN BIT(20) + #define MTK_GDMA_TO_PDMA 0x0 +-#define MTK_GDMA_TO_PPE 0x4444 + #define MTK_GDMA_DROP_ALL 0x7777 + + /* Unicast Filter MAC Address Register - Low */ +@@ -952,6 +951,8 @@ struct mtk_reg_map { + u32 fq_blen; /* fq free page buffer length */ + } qdma; + u32 gdm1_cnt; ++ u32 gdma_to_ppe0; ++ u32 ppe_base; + }; + + /* struct mtk_eth_data - This is the structure holding all differences +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -8,8 +8,6 @@ + #include + #include + +-#define MTK_ETH_PPE_BASE 0xc00 +- + #define MTK_PPE_ENTRIES_SHIFT 3 + #define MTK_PPE_ENTRIES (1024 << MTK_PPE_ENTRIES_SHIFT) + #define MTK_PPE_HASH_MASK (MTK_PPE_ENTRIES - 1) diff --git a/target/linux/generic/pending-5.15/782-net-ethernet-mtk_eth_soc-move-ppe-table-hash-offset-.patch b/target/linux/generic/pending-5.15/782-net-ethernet-mtk_eth_soc-move-ppe-table-hash-offset-.patch new file mode 100644 index 0000000000..89a3aa9893 --- /dev/null +++ b/target/linux/generic/pending-5.15/782-net-ethernet-mtk_eth_soc-move-ppe-table-hash-offset-.patch @@ -0,0 +1,199 @@ +From patchwork Thu Sep 8 19:33:38 2022 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Lorenzo Bianconi +X-Patchwork-Id: 12970557 +X-Patchwork-Delegate: kuba@kernel.org +From: Lorenzo Bianconi +To: netdev@vger.kernel.org +Cc: nbd@nbd.name, john@phrozen.org, sean.wang@mediatek.com, + Mark-MC.Lee@mediatek.com, davem@davemloft.net, edumazet@google.com, + kuba@kernel.org, pabeni@redhat.com, matthias.bgg@gmail.com, + linux-mediatek@lists.infradead.org, lorenzo.bianconi@redhat.com, + Bo.Jiao@mediatek.com, sujuan.chen@mediatek.com, + ryder.Lee@mediatek.com, evelyn.tsai@mediatek.com, + devicetree@vger.kernel.org, robh@kernel.org +Subject: [PATCH net-next 04/12] net: ethernet: mtk_eth_soc: move ppe table + hash offset to mtk_soc_data structure +Date: Thu, 8 Sep 2022 21:33:38 +0200 +Message-Id: + +X-Mailer: git-send-email 2.37.3 +In-Reply-To: +References: +MIME-Version: 1.0 +Precedence: bulk +List-ID: +X-Mailing-List: netdev@vger.kernel.org +X-Patchwork-Delegate: kuba@kernel.org + +This is a preliminary patch to introduce mt7986 hw packet engine. + +Co-developed-by: Bo Jiao +Signed-off-by: Bo Jiao +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++++ + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 ++ + drivers/net/ethernet/mediatek/mtk_ppe.c | 24 +++++++++++++++------ + drivers/net/ethernet/mediatek/mtk_ppe.h | 2 +- + 4 files changed, 25 insertions(+), 7 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4150,6 +4150,7 @@ static const struct mtk_soc_data mt7621_ + .required_clks = MT7621_CLKS_BITMAP, + .required_pctl = false, + .offload_version = 2, ++ .hash_offset = 2, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +@@ -4168,6 +4169,7 @@ static const struct mtk_soc_data mt7622_ + .required_clks = MT7622_CLKS_BITMAP, + .required_pctl = false, + .offload_version = 2, ++ .hash_offset = 2, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +@@ -4185,6 +4187,7 @@ static const struct mtk_soc_data mt7623_ + .required_clks = MT7623_CLKS_BITMAP, + .required_pctl = true, + .offload_version = 2, ++ .hash_offset = 2, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +@@ -4218,6 +4221,7 @@ static const struct mtk_soc_data mt7986_ + .caps = MT7986_CAPS, + .required_clks = MT7986_CLKS_BITMAP, + .required_pctl = false, ++ .hash_offset = 4, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma_v2), + .rxd_size = sizeof(struct mtk_rx_dma_v2), +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -966,6 +966,7 @@ struct mtk_reg_map { + * the target SoC + * @required_pctl A bool value to show whether the SoC requires + * the extra setup for those pins used by GMAC. ++ * @hash_offset Flow table hash offset. + * @txd_size Tx DMA descriptor size. + * @rxd_size Rx DMA descriptor size. + * @rx_irq_done_mask Rx irq done register mask. +@@ -980,6 +981,7 @@ struct mtk_soc_data { + u32 required_clks; + bool required_pctl; + u8 offload_version; ++ u8 hash_offset; + netdev_features_t hw_features; + struct { + u32 txd_size; +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -88,7 +88,7 @@ static void mtk_ppe_cache_enable(struct + enable * MTK_PPE_CACHE_CTL_EN); + } + +-static u32 mtk_ppe_hash_entry(struct mtk_foe_entry *e) ++static u32 mtk_ppe_hash_entry(struct mtk_eth *eth, struct mtk_foe_entry *e) + { + u32 hv1, hv2, hv3; + u32 hash; +@@ -122,7 +122,7 @@ static u32 mtk_ppe_hash_entry(struct mtk + hash = (hash >> 24) | ((hash & 0xffffff) << 8); + hash ^= hv1 ^ hv2 ^ hv3; + hash ^= hash >> 16; +- hash <<= 1; ++ hash <<= (ffs(eth->soc->hash_offset) - 1); + hash &= MTK_PPE_ENTRIES - 1; + + return hash; +@@ -540,15 +540,16 @@ mtk_foe_entry_commit_l2(struct mtk_ppe * + int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { + int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->data.ib1); ++ const struct mtk_soc_data *soc = ppe->eth->soc; + u32 hash; + + if (type == MTK_PPE_PKT_TYPE_BRIDGE) + return mtk_foe_entry_commit_l2(ppe, entry); + +- hash = mtk_ppe_hash_entry(&entry->data); ++ hash = mtk_ppe_hash_entry(ppe->eth, &entry->data); + entry->hash = 0xffff; + spin_lock_bh(&ppe_lock); +- hlist_add_head(&entry->list, &ppe->foe_flow[hash / 2]); ++ hlist_add_head(&entry->list, &ppe->foe_flow[hash / soc->hash_offset]); + spin_unlock_bh(&ppe_lock); + + return 0; +@@ -558,6 +559,7 @@ static void + mtk_foe_entry_commit_subflow(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, + u16 hash) + { ++ const struct mtk_soc_data *soc = ppe->eth->soc; + struct mtk_flow_entry *flow_info; + struct mtk_foe_entry foe, *hwe; + struct mtk_foe_mac_info *l2; +@@ -572,7 +574,8 @@ mtk_foe_entry_commit_subflow(struct mtk_ + flow_info->l2_data.base_flow = entry; + flow_info->type = MTK_FLOW_TYPE_L2_SUBFLOW; + flow_info->hash = hash; +- hlist_add_head(&flow_info->list, &ppe->foe_flow[hash / 2]); ++ hlist_add_head(&flow_info->list, ++ &ppe->foe_flow[hash / soc->hash_offset]); + hlist_add_head(&flow_info->l2_data.list, &entry->l2_flows); + + hwe = &ppe->foe_table[hash]; +@@ -596,7 +599,8 @@ mtk_foe_entry_commit_subflow(struct mtk_ + + void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) + { +- struct hlist_head *head = &ppe->foe_flow[hash / 2]; ++ const struct mtk_soc_data *soc = ppe->eth->soc; ++ struct hlist_head *head = &ppe->foe_flow[hash / soc->hash_offset]; + struct mtk_foe_entry *hwe = &ppe->foe_table[hash]; + struct mtk_flow_entry *entry; + struct mtk_foe_bridge key = {}; +@@ -680,9 +684,11 @@ int mtk_foe_entry_idle_time(struct mtk_p + struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, + int version) + { ++ const struct mtk_soc_data *soc = eth->soc; + struct device *dev = eth->dev; + struct mtk_foe_entry *foe; + struct mtk_ppe *ppe; ++ u32 foe_flow_size; + + ppe = devm_kzalloc(dev, sizeof(*ppe), GFP_KERNEL); + if (!ppe) +@@ -705,6 +711,12 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ + + ppe->foe_table = foe; + ++ foe_flow_size = (MTK_PPE_ENTRIES / soc->hash_offset) * ++ sizeof(*ppe->foe_flow); ++ ppe->foe_flow = devm_kzalloc(dev, foe_flow_size, GFP_KERNEL); ++ if (!ppe->foe_flow) ++ return NULL; ++ + mtk_ppe_debugfs_init(ppe); + + return ppe; +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -270,7 +270,7 @@ struct mtk_ppe { + dma_addr_t foe_phys; + + u16 foe_check_time[MTK_PPE_ENTRIES]; +- struct hlist_head foe_flow[MTK_PPE_ENTRIES / 2]; ++ struct hlist_head *foe_flow; + + struct rhashtable l2_flows; + diff --git a/target/linux/generic/pending-5.15/790-net-ethernet-mtk_eth_soc-add-the-capability-to-run-m.patch b/target/linux/generic/pending-5.15/790-net-ethernet-mtk_eth_soc-add-the-capability-to-run-m.patch new file mode 100644 index 0000000000..0b207ff6a1 --- /dev/null +++ b/target/linux/generic/pending-5.15/790-net-ethernet-mtk_eth_soc-add-the-capability-to-run-m.patch @@ -0,0 +1,317 @@ +From patchwork Thu Sep 8 19:33:39 2022 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Lorenzo Bianconi +X-Patchwork-Id: 12970559 +X-Patchwork-Delegate: kuba@kernel.org +Return-Path: +From: Lorenzo Bianconi +To: netdev@vger.kernel.org +Cc: nbd@nbd.name, john@phrozen.org, sean.wang@mediatek.com, + Mark-MC.Lee@mediatek.com, davem@davemloft.net, edumazet@google.com, + kuba@kernel.org, pabeni@redhat.com, matthias.bgg@gmail.com, + linux-mediatek@lists.infradead.org, lorenzo.bianconi@redhat.com, + Bo.Jiao@mediatek.com, sujuan.chen@mediatek.com, + ryder.Lee@mediatek.com, evelyn.tsai@mediatek.com, + devicetree@vger.kernel.org, robh@kernel.org +Subject: [PATCH net-next 05/12] net: ethernet: mtk_eth_soc: add the capability + to run multiple ppe +Date: Thu, 8 Sep 2022 21:33:39 +0200 +Message-Id: + +X-Mailer: git-send-email 2.37.3 +In-Reply-To: +References: +MIME-Version: 1.0 +Precedence: bulk +List-ID: +X-Mailing-List: netdev@vger.kernel.org +X-Patchwork-Delegate: kuba@kernel.org + +mt7986 chipset support multiple packet engines for wlan <-> eth +packet forwarding. + +Co-developed-by: Bo Jiao +Signed-off-by: Bo Jiao +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 35 ++++++++++++------- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 +- + drivers/net/ethernet/mediatek/mtk_ppe.c | 14 +++++--- + drivers/net/ethernet/mediatek/mtk_ppe.h | 9 +++-- + .../net/ethernet/mediatek/mtk_ppe_debugfs.c | 8 ++--- + .../net/ethernet/mediatek/mtk_ppe_offload.c | 13 +++---- + 6 files changed, 48 insertions(+), 33 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1871,7 +1871,7 @@ static int mtk_poll_rx(struct napi_struc + + reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4); + if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) +- mtk_ppe_check_skb(eth->ppe, skb, hash); ++ mtk_ppe_check_skb(eth->ppe[0], skb, hash); + + if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { +@@ -2929,15 +2929,19 @@ static int mtk_open(struct net_device *d + /* we run 2 netdevs on the same dma ring so we only bring it up once */ + if (!refcount_read(ð->dma_refcnt)) { + const struct mtk_soc_data *soc = eth->soc; +- u32 gdm_config = MTK_GDMA_TO_PDMA; ++ u32 gdm_config; ++ int i; + int err; + + err = mtk_start_dma(eth); + if (err) + return err; + +- if (soc->offload_version && mtk_ppe_start(eth->ppe) == 0) +- gdm_config = soc->reg_map->gdma_to_ppe0; ++ for (i = 0; i < ARRAY_SIZE(eth->ppe); i++) ++ mtk_ppe_start(eth->ppe[i]); ++ ++ gdm_config = soc->offload_version ? soc->reg_map->gdma_to_ppe0 ++ : MTK_GDMA_TO_PDMA; + + mtk_gdm_config(eth, gdm_config); + +@@ -2982,6 +2986,7 @@ static int mtk_stop(struct net_device *d + { + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; ++ int i; + + phylink_stop(mac->phylink); + +@@ -3009,8 +3014,8 @@ static int mtk_stop(struct net_device *d + + mtk_dma_free(eth); + +- if (eth->soc->offload_version) +- mtk_ppe_stop(eth->ppe); ++ for (i = 0; i < ARRAY_SIZE(eth->ppe); i++) ++ mtk_ppe_stop(eth->ppe[i]); + + return 0; + } +@@ -4050,12 +4055,19 @@ static int mtk_probe(struct platform_dev + } + + if (eth->soc->offload_version) { +- u32 ppe_addr = eth->soc->reg_map->ppe_base; ++ u32 num_ppe; + +- eth->ppe = mtk_ppe_init(eth, eth->base + ppe_addr, 2); +- if (!eth->ppe) { +- err = -ENOMEM; +- goto err_free_dev; ++ num_ppe = MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ? 2 : 1; ++ num_ppe = min_t(u32, ARRAY_SIZE(eth->ppe), num_ppe); ++ for (i = 0; i < num_ppe; i++) { ++ u32 ppe_addr = eth->soc->reg_map->ppe_base + i * 0x400; ++ ++ eth->ppe[i] = mtk_ppe_init(eth, eth->base + ppe_addr, ++ eth->soc->offload_version, i); ++ if (!eth->ppe[i]) { ++ err = -ENOMEM; ++ goto err_free_dev; ++ } + } + + err = mtk_eth_offload_init(eth); +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1111,7 +1111,7 @@ struct mtk_eth { + + int ip_align; + +- struct mtk_ppe *ppe; ++ struct mtk_ppe *ppe[2]; + struct rhashtable flow_table; + + struct bpf_prog __rcu *prog; +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -682,7 +682,7 @@ int mtk_foe_entry_idle_time(struct mtk_p + } + + struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, +- int version) ++ int version, int index) + { + const struct mtk_soc_data *soc = eth->soc; + struct device *dev = eth->dev; +@@ -717,7 +717,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ + if (!ppe->foe_flow) + return NULL; + +- mtk_ppe_debugfs_init(ppe); ++ mtk_ppe_debugfs_init(ppe, index); + + return ppe; + } +@@ -738,10 +738,13 @@ static void mtk_ppe_init_foe_table(struc + ppe->foe_table[i + skip[k]].ib1 |= MTK_FOE_IB1_STATIC; + } + +-int mtk_ppe_start(struct mtk_ppe *ppe) ++void mtk_ppe_start(struct mtk_ppe *ppe) + { + u32 val; + ++ if (!ppe) ++ return; ++ + mtk_ppe_init_foe_table(ppe); + ppe_w32(ppe, MTK_PPE_TB_BASE, ppe->foe_phys); + +@@ -809,8 +812,6 @@ int mtk_ppe_start(struct mtk_ppe *ppe) + ppe_w32(ppe, MTK_PPE_GLO_CFG, val); + + ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT, 0); +- +- return 0; + } + + int mtk_ppe_stop(struct mtk_ppe *ppe) +@@ -818,6 +819,9 @@ int mtk_ppe_stop(struct mtk_ppe *ppe) + u32 val; + int i; + ++ if (!ppe) ++ return 0; ++ + for (i = 0; i < MTK_PPE_ENTRIES; i++) + ppe->foe_table[i].ib1 = FIELD_PREP(MTK_FOE_IB1_STATE, + MTK_FOE_STATE_INVALID); +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -247,6 +247,7 @@ struct mtk_flow_entry { + }; + u8 type; + s8 wed_index; ++ u8 ppe_index; + u16 hash; + union { + struct mtk_foe_entry data; +@@ -265,6 +266,7 @@ struct mtk_ppe { + struct device *dev; + void __iomem *base; + int version; ++ char dirname[5]; + + struct mtk_foe_entry *foe_table; + dma_addr_t foe_phys; +@@ -277,8 +279,9 @@ struct mtk_ppe { + void *acct_table; + }; + +-struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int version); +-int mtk_ppe_start(struct mtk_ppe *ppe); ++struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, ++ int version, int index); ++void mtk_ppe_start(struct mtk_ppe *ppe); + int mtk_ppe_stop(struct mtk_ppe *ppe); + + void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash); +@@ -317,6 +320,6 @@ int mtk_foe_entry_set_wdma(struct mtk_fo + 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 mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index); + + #endif +--- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c +@@ -187,7 +187,7 @@ mtk_ppe_debugfs_foe_open_bind(struct ino + inode->i_private); + } + +-int mtk_ppe_debugfs_init(struct mtk_ppe *ppe) ++int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index) + { + static const struct file_operations fops_all = { + .open = mtk_ppe_debugfs_foe_open_all, +@@ -195,17 +195,17 @@ int mtk_ppe_debugfs_init(struct mtk_ppe + .llseek = seq_lseek, + .release = single_release, + }; +- + static const struct file_operations fops_bind = { + .open = mtk_ppe_debugfs_foe_open_bind, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + }; +- + struct dentry *root; + +- root = debugfs_create_dir("mtk_ppe", NULL); ++ snprintf(ppe->dirname, sizeof(ppe->dirname), "ppe%d", index); ++ ++ root = debugfs_create_dir(ppe->dirname, NULL); + if (!root) + return -ENOMEM; + +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -434,7 +434,7 @@ mtk_flow_offload_replace(struct mtk_eth + memcpy(&entry->data, &foe, sizeof(entry->data)); + entry->wed_index = wed_index; + +- err = mtk_foe_entry_commit(eth->ppe, entry); ++ err = mtk_foe_entry_commit(eth->ppe[entry->ppe_index], entry); + if (err < 0) + goto free; + +@@ -446,7 +446,7 @@ mtk_flow_offload_replace(struct mtk_eth + return 0; + + clear: +- mtk_foe_entry_clear(eth->ppe, entry); ++ mtk_foe_entry_clear(eth->ppe[entry->ppe_index], entry); + free: + kfree(entry); + if (wed_index >= 0) +@@ -464,7 +464,7 @@ mtk_flow_offload_destroy(struct mtk_eth + if (!entry) + return -ENOENT; + +- mtk_foe_entry_clear(eth->ppe, entry); ++ mtk_foe_entry_clear(eth->ppe[entry->ppe_index], entry); + rhashtable_remove_fast(ð->flow_table, &entry->node, + mtk_flow_ht_params); + if (entry->wed_index >= 0) +@@ -485,7 +485,7 @@ mtk_flow_offload_stats(struct mtk_eth *e + if (!entry) + return -ENOENT; + +- idle = mtk_foe_entry_idle_time(eth->ppe, entry); ++ idle = mtk_foe_entry_idle_time(eth->ppe[entry->ppe_index], entry); + f->stats.lastused = jiffies - idle * HZ; + + return 0; +@@ -537,7 +537,7 @@ mtk_eth_setup_tc_block(struct net_device + struct flow_block_cb *block_cb; + flow_setup_cb_t *cb; + +- if (!eth->ppe || !eth->ppe->foe_table) ++ if (!eth->soc->offload_version) + return -EOPNOTSUPP; + + if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) +@@ -589,8 +589,5 @@ int mtk_eth_setup_tc(struct net_device * + + int mtk_eth_offload_init(struct mtk_eth *eth) + { +- if (!eth->ppe || !eth->ppe->foe_table) +- return 0; +- + return rhashtable_init(ð->flow_table, &mtk_flow_ht_params); + } diff --git a/target/linux/generic/pending-5.15/791-net-ethernet-mtk_eth_soc-move-wdma_base-definitions-.patch b/target/linux/generic/pending-5.15/791-net-ethernet-mtk_eth_soc-move-wdma_base-definitions-.patch new file mode 100644 index 0000000000..e984f4b68b --- /dev/null +++ b/target/linux/generic/pending-5.15/791-net-ethernet-mtk_eth_soc-move-wdma_base-definitions-.patch @@ -0,0 +1,80 @@ +From 0dcbe607cec32ccae23b02a641b8bd6191a328ae Mon Sep 17 00:00:00 2001 +Message-Id: <0dcbe607cec32ccae23b02a641b8bd6191a328ae.1662243796.git.lorenzo@kernel.org> +In-Reply-To: <43a21841ce0175d29f23c34a65ceaaf9dd7eb8b7.1662243796.git.lorenzo@kernel.org> +References: <43a21841ce0175d29f23c34a65ceaaf9dd7eb8b7.1662243796.git.lorenzo@kernel.org> +From: Lorenzo Bianconi +Date: Tue, 23 Aug 2022 23:09:05 +0200 +Subject: [PATCH net-next 2/4] net: ethernet: mtk_eth_soc: move wdma_base + definitions in mtk register map + +This is a preliminary patch to introduce mt7986 wed support. + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 16 ++++++++++------ + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 +--- + 2 files changed, 11 insertions(+), 9 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -75,6 +75,10 @@ static const struct mtk_reg_map mtk_reg_ + .gdm1_cnt = 0x2400, + .gdma_to_ppe0 = 0x4444, + .ppe_base = 0x0c00, ++ .wdma_base = { ++ [0] = 0x2800, ++ [1] = 0x2c00, ++ }, + }; + + static const struct mtk_reg_map mt7628_reg_map = { +@@ -130,6 +134,10 @@ static const struct mtk_reg_map mt7986_r + .gdm1_cnt = 0x1c00, + .gdma_to_ppe0 = 0x3333, + .ppe_base = 0x2000, ++ .wdma_base = { ++ [0] = 0x4800, ++ [1] = 0x4c00, ++ }, + }; + + /* strings used by ethtool */ +@@ -3967,16 +3975,12 @@ static int mtk_probe(struct platform_dev + for (i = 0;; i++) { + struct device_node *np = of_parse_phandle(pdev->dev.of_node, + "mediatek,wed", i); +- static const u32 wdma_regs[] = { +- MTK_WDMA0_BASE, +- MTK_WDMA1_BASE +- }; + void __iomem *wdma; + +- if (!np || i >= ARRAY_SIZE(wdma_regs)) ++ if (!np || i >= ARRAY_SIZE(eth->soc->reg_map->wdma_base)) + break; + +- wdma = eth->base + wdma_regs[i]; ++ wdma = eth->base + eth->soc->reg_map->wdma_base[i]; + mtk_wed_add_hw(np, eth, wdma, i); + } + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -268,9 +268,6 @@ + #define TX_DMA_FPORT_MASK_V2 0xf + #define TX_DMA_SWC_V2 BIT(30) + +-#define MTK_WDMA0_BASE 0x2800 +-#define MTK_WDMA1_BASE 0x2c00 +- + /* QDMA descriptor txd4 */ + #define TX_DMA_CHKSUM (0x7 << 29) + #define TX_DMA_TSO BIT(28) +@@ -953,6 +950,7 @@ struct mtk_reg_map { + u32 gdm1_cnt; + u32 gdma_to_ppe0; + u32 ppe_base; ++ u32 wdma_base[2]; + }; + + /* struct mtk_eth_data - This is the structure holding all differences diff --git a/target/linux/generic/pending-5.15/792-net-ethernet-mtk_eth_soc-add-foe_entry_size-to-mtk_e.patch b/target/linux/generic/pending-5.15/792-net-ethernet-mtk_eth_soc-add-foe_entry_size-to-mtk_e.patch new file mode 100644 index 0000000000..16bc8e29fc --- /dev/null +++ b/target/linux/generic/pending-5.15/792-net-ethernet-mtk_eth_soc-add-foe_entry_size-to-mtk_e.patch @@ -0,0 +1,251 @@ +From e3c27d869fccc1f2b8d0b4cde4763ab223874e8c Mon Sep 17 00:00:00 2001 +Message-Id: +In-Reply-To: <43a21841ce0175d29f23c34a65ceaaf9dd7eb8b7.1662243796.git.lorenzo@kernel.org> +References: <43a21841ce0175d29f23c34a65ceaaf9dd7eb8b7.1662243796.git.lorenzo@kernel.org> +From: Lorenzo Bianconi +Date: Sun, 21 Aug 2022 17:51:17 +0200 +Subject: [PATCH net-next 3/4] net: ethernet: mtk_eth_soc: add foe_entry_size + to mtk_eth_soc + +Introduce foe_entry_size to mtk_eth_soc data structure since mt7986 +relies on a bigger mtk_foe_entry data structure. + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 + + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 10 ++++ + drivers/net/ethernet/mediatek/mtk_ppe.c | 55 +++++++++++-------- + drivers/net/ethernet/mediatek/mtk_ppe.h | 2 +- + .../net/ethernet/mediatek/mtk_ppe_debugfs.c | 2 +- + 5 files changed, 48 insertions(+), 24 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4167,6 +4167,7 @@ static const struct mtk_soc_data mt7621_ + .required_pctl = false, + .offload_version = 2, + .hash_offset = 2, ++ .foe_entry_size = sizeof(struct mtk_foe_entry), + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +@@ -4186,6 +4187,7 @@ static const struct mtk_soc_data mt7622_ + .required_pctl = false, + .offload_version = 2, + .hash_offset = 2, ++ .foe_entry_size = sizeof(struct mtk_foe_entry), + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +@@ -4204,6 +4206,7 @@ static const struct mtk_soc_data mt7623_ + .required_pctl = true, + .offload_version = 2, + .hash_offset = 2, ++ .foe_entry_size = sizeof(struct mtk_foe_entry), + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -965,6 +965,7 @@ struct mtk_reg_map { + * @required_pctl A bool value to show whether the SoC requires + * the extra setup for those pins used by GMAC. + * @hash_offset Flow table hash offset. ++ * @foe_entry_size Foe table entry size. + * @txd_size Tx DMA descriptor size. + * @rxd_size Rx DMA descriptor size. + * @rx_irq_done_mask Rx irq done register mask. +@@ -980,6 +981,7 @@ struct mtk_soc_data { + bool required_pctl; + u8 offload_version; + u8 hash_offset; ++ u16 foe_entry_size; + netdev_features_t hw_features; + struct { + u32 txd_size; +@@ -1140,6 +1142,14 @@ struct mtk_mac { + /* the struct describing the SoC. these are declared in the soc_xyz.c files */ + extern const struct of_device_id of_mtk_match[]; + ++static inline struct mtk_foe_entry * ++mtk_foe_get_entry(struct mtk_ppe *ppe, u16 hash) ++{ ++ const struct mtk_soc_data *soc = ppe->eth->soc; ++ ++ return ppe->foe_table + hash * soc->foe_entry_size; ++} ++ + /* read the hardware status register */ + void mtk_stats_update_mac(struct mtk_mac *mac); + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -410,9 +410,10 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp + + hlist_del_init(&entry->list); + if (entry->hash != 0xffff) { +- ppe->foe_table[entry->hash].ib1 &= ~MTK_FOE_IB1_STATE; +- ppe->foe_table[entry->hash].ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, +- MTK_FOE_STATE_BIND); ++ struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, entry->hash); ++ ++ hwe->ib1 &= ~MTK_FOE_IB1_STATE; ++ hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND); + dma_wmb(); + } + entry->hash = 0xffff; +@@ -451,7 +452,7 @@ mtk_flow_entry_update_l2(struct mtk_ppe + int cur_idle; + u32 ib1; + +- hwe = &ppe->foe_table[cur->hash]; ++ hwe = mtk_foe_get_entry(ppe, cur->hash); + ib1 = READ_ONCE(hwe->ib1); + + if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND) { +@@ -473,8 +474,8 @@ mtk_flow_entry_update_l2(struct mtk_ppe + static void + mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { ++ struct mtk_foe_entry foe = {}; + struct mtk_foe_entry *hwe; +- struct mtk_foe_entry foe; + + spin_lock_bh(&ppe_lock); + +@@ -486,8 +487,8 @@ mtk_flow_entry_update(struct mtk_ppe *pp + if (entry->hash == 0xffff) + goto out; + +- hwe = &ppe->foe_table[entry->hash]; +- memcpy(&foe, hwe, sizeof(foe)); ++ hwe = mtk_foe_get_entry(ppe, entry->hash); ++ memcpy(&foe, hwe, ppe->eth->soc->foe_entry_size); + if (!mtk_flow_entry_match(entry, &foe)) { + entry->hash = 0xffff; + goto out; +@@ -511,8 +512,8 @@ __mtk_foe_entry_commit(struct mtk_ppe *p + entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP; + entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP, timestamp); + +- hwe = &ppe->foe_table[hash]; +- memcpy(&hwe->data, &entry->data, sizeof(hwe->data)); ++ hwe = mtk_foe_get_entry(ppe, hash); ++ memcpy(&hwe->data, &entry->data, ppe->eth->soc->foe_entry_size); + wmb(); + hwe->ib1 = entry->ib1; + +@@ -561,7 +562,7 @@ mtk_foe_entry_commit_subflow(struct mtk_ + { + const struct mtk_soc_data *soc = ppe->eth->soc; + struct mtk_flow_entry *flow_info; +- struct mtk_foe_entry foe, *hwe; ++ struct mtk_foe_entry foe = {}, *hwe; + struct mtk_foe_mac_info *l2; + u32 ib1_mask = MTK_FOE_IB1_PACKET_TYPE | MTK_FOE_IB1_UDP; + int type; +@@ -578,8 +579,8 @@ mtk_foe_entry_commit_subflow(struct mtk_ + &ppe->foe_flow[hash / soc->hash_offset]); + hlist_add_head(&flow_info->l2_data.list, &entry->l2_flows); + +- hwe = &ppe->foe_table[hash]; +- memcpy(&foe, hwe, sizeof(foe)); ++ hwe = mtk_foe_get_entry(ppe, hash); ++ memcpy(&foe, hwe, soc->foe_entry_size); + foe.ib1 &= ib1_mask; + foe.ib1 |= entry->data.ib1 & ~ib1_mask; + +@@ -601,7 +602,7 @@ void __mtk_ppe_check_skb(struct mtk_ppe + { + const struct mtk_soc_data *soc = ppe->eth->soc; + struct hlist_head *head = &ppe->foe_flow[hash / soc->hash_offset]; +- struct mtk_foe_entry *hwe = &ppe->foe_table[hash]; ++ struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, hash); + struct mtk_flow_entry *entry; + struct mtk_foe_bridge key = {}; + struct hlist_node *n; +@@ -686,9 +687,9 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ + { + const struct mtk_soc_data *soc = eth->soc; + struct device *dev = eth->dev; +- struct mtk_foe_entry *foe; + struct mtk_ppe *ppe; + u32 foe_flow_size; ++ void *foe; + + ppe = devm_kzalloc(dev, sizeof(*ppe), GFP_KERNEL); + if (!ppe) +@@ -704,7 +705,8 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ + ppe->dev = dev; + ppe->version = version; + +- foe = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*foe), ++ foe = dmam_alloc_coherent(ppe->dev, ++ MTK_PPE_ENTRIES * soc->foe_entry_size, + &ppe->foe_phys, GFP_KERNEL); + if (!foe) + return NULL; +@@ -727,15 +729,21 @@ static void mtk_ppe_init_foe_table(struc + static const u8 skip[] = { 12, 25, 38, 51, 76, 89, 102 }; + int i, k; + +- memset(ppe->foe_table, 0, MTK_PPE_ENTRIES * sizeof(*ppe->foe_table)); ++ memset(ppe->foe_table, 0, ++ MTK_PPE_ENTRIES * ppe->eth->soc->foe_entry_size); + + if (!IS_ENABLED(CONFIG_SOC_MT7621)) + return; + + /* skip all entries that cross the 1024 byte boundary */ +- for (i = 0; i < MTK_PPE_ENTRIES; i += 128) +- for (k = 0; k < ARRAY_SIZE(skip); k++) +- ppe->foe_table[i + skip[k]].ib1 |= MTK_FOE_IB1_STATIC; ++ for (i = 0; i < MTK_PPE_ENTRIES; i += 128) { ++ for (k = 0; k < ARRAY_SIZE(skip); k++) { ++ struct mtk_foe_entry *hwe; ++ ++ hwe = mtk_foe_get_entry(ppe, i + skip[k]); ++ hwe->ib1 |= MTK_FOE_IB1_STATIC; ++ } ++ } + } + + void mtk_ppe_start(struct mtk_ppe *ppe) +@@ -822,9 +830,12 @@ int mtk_ppe_stop(struct mtk_ppe *ppe) + if (!ppe) + return 0; + +- for (i = 0; i < MTK_PPE_ENTRIES; i++) +- ppe->foe_table[i].ib1 = FIELD_PREP(MTK_FOE_IB1_STATE, +- MTK_FOE_STATE_INVALID); ++ for (i = 0; i < MTK_PPE_ENTRIES; i++) { ++ struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, i); ++ ++ hwe->ib1 = FIELD_PREP(MTK_FOE_IB1_STATE, ++ MTK_FOE_STATE_INVALID); ++ } + + mtk_ppe_cache_enable(ppe, false); + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -268,7 +268,7 @@ struct mtk_ppe { + int version; + char dirname[5]; + +- struct mtk_foe_entry *foe_table; ++ void *foe_table; + dma_addr_t foe_phys; + + u16 foe_check_time[MTK_PPE_ENTRIES]; +--- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c +@@ -79,7 +79,7 @@ mtk_ppe_debugfs_foe_show(struct seq_file + int i; + + for (i = 0; i < MTK_PPE_ENTRIES; i++) { +- struct mtk_foe_entry *entry = &ppe->foe_table[i]; ++ struct mtk_foe_entry *entry = mtk_foe_get_entry(ppe, i); + struct mtk_foe_mac_info *l2; + struct mtk_flow_addr_info ai = {}; + unsigned char h_source[ETH_ALEN]; diff --git a/target/linux/generic/pending-5.15/793-net-ethernet-mtk_eth_soc-fix-typo-in-__mtk_foe_entry.patch b/target/linux/generic/pending-5.15/793-net-ethernet-mtk_eth_soc-fix-typo-in-__mtk_foe_entry.patch new file mode 100644 index 0000000000..77daf6c8bf --- /dev/null +++ b/target/linux/generic/pending-5.15/793-net-ethernet-mtk_eth_soc-fix-typo-in-__mtk_foe_entry.patch @@ -0,0 +1,27 @@ +From 12ff69304c83c679ca01ef3db963ab0db9de19fb Mon Sep 17 00:00:00 2001 +Message-Id: <12ff69304c83c679ca01ef3db963ab0db9de19fb.1662332102.git.lorenzo@kernel.org> +In-Reply-To: <2a60545635c2705312299384f4e9fec2f2a3acd6.1662332102.git.lorenzo@kernel.org> +References: <2a60545635c2705312299384f4e9fec2f2a3acd6.1662332102.git.lorenzo@kernel.org> +From: Lorenzo Bianconi +Date: Mon, 5 Sep 2022 00:43:43 +0200 +Subject: [PATCH net-next 2/6] net: ethernet: mtk_eth_soc: fix typo in + __mtk_foe_entry_clear + +Set ib1 state to MTK_FOE_STATE_UNBIND in __mtk_foe_entry_clear routine. + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_ppe.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -413,7 +413,7 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp + struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, entry->hash); + + hwe->ib1 &= ~MTK_FOE_IB1_STATE; +- hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND); ++ hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_UNBIND); + dma_wmb(); + } + entry->hash = 0xffff; diff --git a/target/linux/generic/pending-5.15/794-net-ethernet-mtk_eth_soc-check-max-allowed-value-in-.patch b/target/linux/generic/pending-5.15/794-net-ethernet-mtk_eth_soc-check-max-allowed-value-in-.patch new file mode 100644 index 0000000000..7ab6d486b2 --- /dev/null +++ b/target/linux/generic/pending-5.15/794-net-ethernet-mtk_eth_soc-check-max-allowed-value-in-.patch @@ -0,0 +1,28 @@ +From 4253e6e2b795a18ab534adcd5c313d3fc4150975 Mon Sep 17 00:00:00 2001 +Message-Id: <4253e6e2b795a18ab534adcd5c313d3fc4150975.1662332102.git.lorenzo@kernel.org> +In-Reply-To: <2a60545635c2705312299384f4e9fec2f2a3acd6.1662332102.git.lorenzo@kernel.org> +References: <2a60545635c2705312299384f4e9fec2f2a3acd6.1662332102.git.lorenzo@kernel.org> +From: Lorenzo Bianconi +Date: Mon, 5 Sep 2022 00:48:52 +0200 +Subject: [PATCH net-next 3/6] net: ethernet: mtk_eth_soc: check max allowed + value in mtk_ppe_check_skb + +Check theoretical OOB accesses in mtk_ppe_check_skb routine + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_ppe.h | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -294,6 +294,9 @@ mtk_ppe_check_skb(struct mtk_ppe *ppe, s + if (!ppe) + return; + ++ if (hash > MTK_PPE_HASH_MASK) ++ return; ++ + now = (u16)jiffies; + diff = now - ppe->foe_check_time[hash]; + if (diff < HZ / 10) diff --git a/target/linux/generic/pending-5.15/795-net-ethernet-mtk_eth_wed-add-mtk_wed_configure_irq-a.patch b/target/linux/generic/pending-5.15/795-net-ethernet-mtk_eth_wed-add-mtk_wed_configure_irq-a.patch new file mode 100644 index 0000000000..a8c88daf1f --- /dev/null +++ b/target/linux/generic/pending-5.15/795-net-ethernet-mtk_eth_wed-add-mtk_wed_configure_irq-a.patch @@ -0,0 +1,189 @@ +From e5ecb4f619197b93fa682d722452dc8412864cdb Mon Sep 17 00:00:00 2001 +Message-Id: +From: Lorenzo Bianconi +Date: Fri, 26 Aug 2022 01:12:57 +0200 +Subject: [PATCH net-next 1/5] net: ethernet: mtk_eth_wed: add + mtk_wed_configure_irq and mtk_wed_dma_{enable/disable} + +Introduce mtk_wed_configure_irq, mtk_wed_dma_enable and mtk_wed_dma_disable +utility routines. +This is a preliminary patch to introduce mt7986 wed support. + +Co-developed-by: Bo Jiao +Signed-off-by: Bo Jiao +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_wed.c | 87 +++++++++++++------- + drivers/net/ethernet/mediatek/mtk_wed_regs.h | 6 +- + 2 files changed, 64 insertions(+), 29 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -237,9 +237,30 @@ mtk_wed_set_ext_int(struct mtk_wed_devic + } + + static void +-mtk_wed_stop(struct mtk_wed_device *dev) ++mtk_wed_dma_disable(struct mtk_wed_device *dev) + { ++ wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, ++ MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN | ++ MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN); ++ ++ wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_RX_DRV_EN); ++ ++ wed_clr(dev, MTK_WED_GLO_CFG, ++ MTK_WED_GLO_CFG_TX_DMA_EN | ++ MTK_WED_GLO_CFG_RX_DMA_EN); ++ + regmap_write(dev->hw->mirror, dev->hw->index * 4, 0); ++ wdma_m32(dev, MTK_WDMA_GLO_CFG, ++ MTK_WDMA_GLO_CFG_TX_DMA_EN | ++ MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | ++ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | ++ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES, 0); ++} ++ ++static void ++mtk_wed_stop(struct mtk_wed_device *dev) ++{ ++ mtk_wed_dma_disable(dev); + mtk_wed_set_ext_int(dev, false); + + wed_clr(dev, MTK_WED_CTRL, +@@ -252,15 +273,6 @@ mtk_wed_stop(struct mtk_wed_device *dev) + wdma_w32(dev, MTK_WDMA_INT_MASK, 0); + wdma_w32(dev, MTK_WDMA_INT_GRP2, 0); + wed_w32(dev, MTK_WED_WPDMA_INT_MASK, 0); +- +- wed_clr(dev, MTK_WED_GLO_CFG, +- MTK_WED_GLO_CFG_TX_DMA_EN | +- MTK_WED_GLO_CFG_RX_DMA_EN); +- wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, +- MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN | +- MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN); +- wed_clr(dev, MTK_WED_WDMA_GLO_CFG, +- MTK_WED_WDMA_GLO_CFG_RX_DRV_EN); + } + + static void +@@ -313,7 +325,10 @@ mtk_wed_hw_init_early(struct mtk_wed_dev + MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY; + wed_m32(dev, MTK_WED_WDMA_GLO_CFG, mask, set); + +- wdma_set(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_RX_INFO_PRERES); ++ wdma_set(dev, MTK_WDMA_GLO_CFG, ++ MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | ++ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | ++ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); + + offset = dev->hw->index ? 0x04000400 : 0; + wed_w32(dev, MTK_WED_WDMA_OFFSET0, 0x2a042a20 + offset); +@@ -520,43 +535,38 @@ mtk_wed_wdma_ring_setup(struct mtk_wed_d + } + + static void +-mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask) ++mtk_wed_configure_irq(struct mtk_wed_device *dev, u32 irq_mask) + { +- u32 wdma_mask; +- u32 val; +- int i; +- +- for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) +- if (!dev->tx_wdma[i].desc) +- mtk_wed_wdma_ring_setup(dev, i, 16); +- +- wdma_mask = FIELD_PREP(MTK_WDMA_INT_MASK_RX_DONE, GENMASK(1, 0)); +- +- mtk_wed_hw_init(dev); ++ u32 wdma_mask = FIELD_PREP(MTK_WDMA_INT_MASK_RX_DONE, GENMASK(1, 0)); + ++ /* wed control cr set */ + wed_set(dev, MTK_WED_CTRL, + MTK_WED_CTRL_WDMA_INT_AGENT_EN | + MTK_WED_CTRL_WPDMA_INT_AGENT_EN | + MTK_WED_CTRL_WED_TX_BM_EN | + MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); + +- wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, MTK_WED_PCIE_INT_TRIGGER_STATUS); ++ wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, ++ MTK_WED_PCIE_INT_TRIGGER_STATUS); + + wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, + MTK_WED_WPDMA_INT_TRIGGER_RX_DONE | + MTK_WED_WPDMA_INT_TRIGGER_TX_DONE); + +- wed_set(dev, MTK_WED_WPDMA_INT_CTRL, +- MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV); +- ++ /* initail wdma interrupt agent */ + wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, wdma_mask); + wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask); + + wdma_w32(dev, MTK_WDMA_INT_MASK, wdma_mask); + wdma_w32(dev, MTK_WDMA_INT_GRP2, wdma_mask); +- + wed_w32(dev, MTK_WED_WPDMA_INT_MASK, irq_mask); + wed_w32(dev, MTK_WED_INT_MASK, irq_mask); ++} ++ ++static void ++mtk_wed_dma_enable(struct mtk_wed_device *dev) ++{ ++ wed_set(dev, MTK_WED_WPDMA_INT_CTRL, MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV); + + wed_set(dev, MTK_WED_GLO_CFG, + MTK_WED_GLO_CFG_TX_DMA_EN | +@@ -567,6 +577,26 @@ mtk_wed_start(struct mtk_wed_device *dev + wed_set(dev, MTK_WED_WDMA_GLO_CFG, + MTK_WED_WDMA_GLO_CFG_RX_DRV_EN); + ++ wdma_set(dev, MTK_WDMA_GLO_CFG, ++ MTK_WDMA_GLO_CFG_TX_DMA_EN | ++ MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | ++ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | ++ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); ++} ++ ++static void ++mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask) ++{ ++ u32 val; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) ++ if (!dev->tx_wdma[i].desc) ++ mtk_wed_wdma_ring_setup(dev, i, 16); ++ ++ mtk_wed_hw_init(dev); ++ mtk_wed_configure_irq(dev, irq_mask); ++ + mtk_wed_set_ext_int(dev, true); + val = dev->wlan.wpdma_phys | + MTK_PCIE_MIRROR_MAP_EN | +@@ -577,6 +607,7 @@ mtk_wed_start(struct mtk_wed_device *dev + val |= BIT(0); + regmap_write(dev->hw->mirror, dev->hw->index * 4, val); + ++ mtk_wed_dma_enable(dev); + dev->running = true; + } + +--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h +@@ -224,7 +224,11 @@ struct mtk_wdma_desc { + #define MTK_WDMA_RING_RX(_n) (0x100 + (_n) * 0x10) + + #define MTK_WDMA_GLO_CFG 0x204 +-#define MTK_WDMA_GLO_CFG_RX_INFO_PRERES GENMASK(28, 26) ++#define MTK_WDMA_GLO_CFG_TX_DMA_EN BIT(0) ++#define MTK_WDMA_GLO_CFG_RX_DMA_EN BIT(2) ++#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) diff --git a/target/linux/generic/pending-5.15/796-net-ethernet-mtk_eth_wed-add-wed-support-for-mt7986-.patch b/target/linux/generic/pending-5.15/796-net-ethernet-mtk_eth_wed-add-wed-support-for-mt7986-.patch new file mode 100644 index 0000000000..71bfcdbac8 --- /dev/null +++ b/target/linux/generic/pending-5.15/796-net-ethernet-mtk_eth_wed-add-wed-support-for-mt7986-.patch @@ -0,0 +1,942 @@ +From 463a71af080fbc77339bee2037fb1e081e3824f7 Mon Sep 17 00:00:00 2001 +Message-Id: <463a71af080fbc77339bee2037fb1e081e3824f7.1662886034.git.lorenzo@kernel.org> +In-Reply-To: +References: +From: Lorenzo Bianconi +Date: Sat, 27 Aug 2022 16:15:14 +0200 +Subject: [PATCH net-next 2/5] net: ethernet: mtk_eth_wed: add wed support for + mt7986 chipset + +Introduce Wireless Etherne Dispatcher support on transmission side +for mt7986 chipset + +Co-developed-by: Bo Jiao +Signed-off-by: Bo Jiao +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 34 +- + drivers/net/ethernet/mediatek/mtk_wed.c | 371 ++++++++++++++---- + drivers/net/ethernet/mediatek/mtk_wed.h | 8 +- + .../net/ethernet/mediatek/mtk_wed_debugfs.c | 3 + + drivers/net/ethernet/mediatek/mtk_wed_regs.h | 81 +++- + include/linux/soc/mediatek/mtk_wed.h | 8 + + 6 files changed, 408 insertions(+), 97 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3892,6 +3892,7 @@ void mtk_eth_set_dma_device(struct mtk_e + + static int mtk_probe(struct platform_device *pdev) + { ++ struct resource *res = NULL; + struct device_node *mac_np; + struct mtk_eth *eth; + int err, i; +@@ -3972,16 +3973,31 @@ static int mtk_probe(struct platform_dev + } + } + +- for (i = 0;; i++) { +- struct device_node *np = of_parse_phandle(pdev->dev.of_node, +- "mediatek,wed", i); +- void __iomem *wdma; +- +- if (!np || i >= ARRAY_SIZE(eth->soc->reg_map->wdma_base)) +- break; +- +- wdma = eth->base + eth->soc->reg_map->wdma_base[i]; +- mtk_wed_add_hw(np, eth, wdma, i); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -EINVAL; ++ } ++ ++ if (eth->soc->offload_version) { ++ for (i = 0;; i++) { ++ struct device_node *np; ++ phys_addr_t wdma_phy; ++ u32 wdma_base; ++ ++ if (i >= ARRAY_SIZE(eth->soc->reg_map->wdma_base)) ++ break; ++ ++ np = of_parse_phandle(pdev->dev.of_node, ++ "mediatek,wed", i); ++ if (!np) ++ break; ++ ++ wdma_base = eth->soc->reg_map->wdma_base[i]; ++ wdma_phy = res ? res->start + wdma_base : 0; ++ mtk_wed_add_hw(np, eth, eth->base + wdma_base, ++ wdma_phy, i); ++ } + } + + for (i = 0; i < 3; i++) { +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -25,6 +25,11 @@ + + #define MTK_WED_TX_RING_SIZE 2048 + #define MTK_WED_WDMA_RING_SIZE 1024 ++#define MTK_WED_MAX_GROUP_SIZE 0x100 ++#define MTK_WED_VLD_GROUP_SIZE 0x40 ++#define MTK_WED_PER_GROUP_PKT 128 ++ ++#define MTK_WED_FBUF_SIZE 128 + + static struct mtk_wed_hw *hw_list[2]; + static DEFINE_MUTEX(hw_lock); +@@ -150,10 +155,17 @@ mtk_wed_buffer_alloc(struct mtk_wed_devi + + desc->buf0 = cpu_to_le32(buf_phys); + desc->buf1 = cpu_to_le32(buf_phys + txd_size); +- ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) | +- FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1, +- MTK_WED_BUF_SIZE - txd_size) | +- MTK_WDMA_DESC_CTRL_LAST_SEG1; ++ ++ if (dev->hw->version == 1) ++ ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) | ++ FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1, ++ MTK_WED_BUF_SIZE - txd_size) | ++ MTK_WDMA_DESC_CTRL_LAST_SEG1; ++ else ++ ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) | ++ FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1_V2, ++ MTK_WED_BUF_SIZE - txd_size) | ++ MTK_WDMA_DESC_CTRL_LAST_SEG0; + desc->ctrl = cpu_to_le32(ctrl); + desc->info = 0; + desc++; +@@ -209,7 +221,7 @@ mtk_wed_free_ring(struct mtk_wed_device + if (!ring->desc) + return; + +- dma_free_coherent(dev->hw->dev, ring->size * sizeof(*ring->desc), ++ dma_free_coherent(dev->hw->dev, ring->size * ring->desc_size, + ring->desc, ring->desc_phys); + } + +@@ -229,6 +241,14 @@ mtk_wed_set_ext_int(struct mtk_wed_devic + { + u32 mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK; + ++ if (dev->hw->version == 1) ++ mask |= MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR; ++ else ++ mask |= MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH | ++ MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH | ++ MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT | ++ MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR; ++ + if (!dev->hw->num_flows) + mask &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD; + +@@ -237,6 +257,20 @@ mtk_wed_set_ext_int(struct mtk_wed_devic + } + + static void ++mtk_wed_set_512_support(struct mtk_wed_device *dev, bool enable) ++{ ++ if (enable) { ++ wed_w32(dev, MTK_WED_TXDP_CTRL, MTK_WED_TXDP_DW9_OVERWR); ++ wed_w32(dev, MTK_WED_TXP_DW1, ++ FIELD_PREP(MTK_WED_WPDMA_WRITE_TXP, 0x0103)); ++ } else { ++ wed_w32(dev, MTK_WED_TXP_DW1, ++ FIELD_PREP(MTK_WED_WPDMA_WRITE_TXP, 0x0100)); ++ wed_clr(dev, MTK_WED_TXDP_CTRL, MTK_WED_TXDP_DW9_OVERWR); ++ } ++} ++ ++static void + mtk_wed_dma_disable(struct mtk_wed_device *dev) + { + wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, +@@ -249,12 +283,22 @@ mtk_wed_dma_disable(struct mtk_wed_devic + MTK_WED_GLO_CFG_TX_DMA_EN | + MTK_WED_GLO_CFG_RX_DMA_EN); + +- regmap_write(dev->hw->mirror, dev->hw->index * 4, 0); + wdma_m32(dev, MTK_WDMA_GLO_CFG, + MTK_WDMA_GLO_CFG_TX_DMA_EN | + MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | +- MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | +- MTK_WDMA_GLO_CFG_RX_INFO3_PRERES, 0); ++ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES, 0); ++ ++ if (dev->hw->version == 1) { ++ regmap_write(dev->hw->mirror, dev->hw->index * 4, 0); ++ wdma_m32(dev, MTK_WDMA_GLO_CFG, ++ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES, 0); ++ } else { ++ wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, ++ MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC | ++ MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC); ++ ++ mtk_wed_set_512_support(dev, false); ++ } + } + + static void +@@ -293,7 +337,7 @@ mtk_wed_detach(struct mtk_wed_device *de + mtk_wed_free_buffer(dev); + mtk_wed_free_tx_rings(dev); + +- if (of_dma_is_coherent(wlan_node)) ++ if (of_dma_is_coherent(wlan_node) && hw->hifsys) + regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, + BIT(hw->index), BIT(hw->index)); + +@@ -308,14 +352,69 @@ mtk_wed_detach(struct mtk_wed_device *de + mutex_unlock(&hw_lock); + } + ++#define PCIE_BASE_ADDR0 0x11280000 ++static void ++mtk_wed_bus_init(struct mtk_wed_device *dev) ++{ ++ struct device_node *np = dev->hw->eth->dev->of_node; ++ struct regmap *regs; ++ u32 val; ++ ++ regs = syscon_regmap_lookup_by_phandle(np, "mediatek,wed-pcie"); ++ if (IS_ERR(regs)) ++ return; ++ ++ regmap_update_bits(regs, 0, BIT(0), BIT(0)); ++ ++ wed_w32(dev, MTK_WED_PCIE_INT_CTRL, ++ FIELD_PREP(MTK_WED_PCIE_INT_CTRL_POLL_EN, 2)); ++ ++ /* pcie interrupt control: pola/source selection */ ++ wed_set(dev, MTK_WED_PCIE_INT_CTRL, ++ MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA | ++ FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL, 1)); ++ wed_r32(dev, MTK_WED_PCIE_INT_CTRL); ++ ++ val = wed_r32(dev, MTK_WED_PCIE_CFG_INTM); ++ val = wed_r32(dev, MTK_WED_PCIE_CFG_BASE); ++ wed_w32(dev, MTK_WED_PCIE_CFG_INTM, PCIE_BASE_ADDR0 | 0x180); ++ wed_w32(dev, MTK_WED_PCIE_CFG_BASE, PCIE_BASE_ADDR0 | 0x184); ++ ++ val = wed_r32(dev, MTK_WED_PCIE_CFG_INTM); ++ val = wed_r32(dev, MTK_WED_PCIE_CFG_BASE); ++ ++ /* pcie interrupt status trigger register */ ++ wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24)); ++ wed_r32(dev, MTK_WED_PCIE_INT_TRIGGER); ++ ++ /* pola setting */ ++ val = wed_r32(dev, MTK_WED_PCIE_INT_CTRL); ++ wed_set(dev, MTK_WED_PCIE_INT_CTRL, MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA); ++} ++ ++static void ++mtk_wed_set_wpdma(struct mtk_wed_device *dev) ++{ ++ if (dev->hw->version == 1) { ++ wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_phys); ++ } else { ++ mtk_wed_bus_init(dev); ++ ++ wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_int); ++ wed_w32(dev, MTK_WED_WPDMA_CFG_INT_MASK, dev->wlan.wpdma_mask); ++ wed_w32(dev, MTK_WED_WPDMA_CFG_TX, dev->wlan.wpdma_tx); ++ wed_w32(dev, MTK_WED_WPDMA_CFG_TX_FREE, dev->wlan.wpdma_txfree); ++ } ++} ++ + static void + mtk_wed_hw_init_early(struct mtk_wed_device *dev) + { + u32 mask, set; +- u32 offset; + + mtk_wed_stop(dev); + mtk_wed_reset(dev, MTK_WED_RESET_WED); ++ mtk_wed_set_wpdma(dev); + + mask = MTK_WED_WDMA_GLO_CFG_BT_SIZE | + MTK_WED_WDMA_GLO_CFG_DYNAMIC_DMAD_RECYCLE | +@@ -325,17 +424,33 @@ mtk_wed_hw_init_early(struct mtk_wed_dev + MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY; + wed_m32(dev, MTK_WED_WDMA_GLO_CFG, mask, set); + +- wdma_set(dev, MTK_WDMA_GLO_CFG, +- MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | +- MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | +- MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); +- +- offset = dev->hw->index ? 0x04000400 : 0; +- wed_w32(dev, MTK_WED_WDMA_OFFSET0, 0x2a042a20 + offset); +- wed_w32(dev, MTK_WED_WDMA_OFFSET1, 0x29002800 + offset); ++ if (dev->hw->version == 1) { ++ u32 offset = dev->hw->index ? 0x04000400 : 0; + +- wed_w32(dev, MTK_WED_PCIE_CFG_BASE, MTK_PCIE_BASE(dev->hw->index)); +- wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_phys); ++ wdma_set(dev, MTK_WDMA_GLO_CFG, ++ MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | ++ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | ++ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); ++ ++ wed_w32(dev, MTK_WED_WDMA_OFFSET0, 0x2a042a20 + offset); ++ wed_w32(dev, MTK_WED_WDMA_OFFSET1, 0x29002800 + offset); ++ wed_w32(dev, MTK_WED_PCIE_CFG_BASE, ++ MTK_PCIE_BASE(dev->hw->index)); ++ } else { ++ wed_w32(dev, MTK_WED_WDMA_CFG_BASE, dev->hw->wdma_phy); ++ wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_ETH_DMAD_FMT); ++ wed_w32(dev, MTK_WED_WDMA_OFFSET0, ++ FIELD_PREP(MTK_WED_WDMA_OFST0_GLO_INTS, ++ MTK_WDMA_INT_STATUS) | ++ FIELD_PREP(MTK_WED_WDMA_OFST0_GLO_CFG, ++ MTK_WDMA_GLO_CFG)); ++ ++ wed_w32(dev, MTK_WED_WDMA_OFFSET1, ++ FIELD_PREP(MTK_WED_WDMA_OFST1_TX_CTRL, ++ MTK_WDMA_RING_TX(0)) | ++ FIELD_PREP(MTK_WED_WDMA_OFST1_RX_CTRL, ++ MTK_WDMA_RING_RX(0))); ++ } + } + + static void +@@ -355,37 +470,65 @@ mtk_wed_hw_init(struct mtk_wed_device *d + + wed_w32(dev, MTK_WED_TX_BM_BASE, dev->buf_ring.desc_phys); + +- wed_w32(dev, MTK_WED_TX_BM_TKID, +- FIELD_PREP(MTK_WED_TX_BM_TKID_START, +- dev->wlan.token_start) | +- FIELD_PREP(MTK_WED_TX_BM_TKID_END, +- dev->wlan.token_start + dev->wlan.nbuf - 1)); +- + wed_w32(dev, MTK_WED_TX_BM_BUF_LEN, MTK_WED_PKT_SIZE); + +- wed_w32(dev, MTK_WED_TX_BM_DYN_THR, +- FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, 1) | +- MTK_WED_TX_BM_DYN_THR_HI); ++ if (dev->hw->version == 1) { ++ wed_w32(dev, MTK_WED_TX_BM_TKID, ++ FIELD_PREP(MTK_WED_TX_BM_TKID_START, ++ dev->wlan.token_start) | ++ FIELD_PREP(MTK_WED_TX_BM_TKID_END, ++ dev->wlan.token_start + ++ dev->wlan.nbuf - 1)); ++ wed_w32(dev, MTK_WED_TX_BM_DYN_THR, ++ FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, 1) | ++ MTK_WED_TX_BM_DYN_THR_HI); ++ } else { ++ wed_w32(dev, MTK_WED_TX_BM_TKID_V2, ++ FIELD_PREP(MTK_WED_TX_BM_TKID_START, ++ dev->wlan.token_start) | ++ FIELD_PREP(MTK_WED_TX_BM_TKID_END, ++ dev->wlan.token_start + ++ dev->wlan.nbuf - 1)); ++ wed_w32(dev, MTK_WED_TX_BM_DYN_THR, ++ FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO_V2, 0) | ++ MTK_WED_TX_BM_DYN_THR_HI_V2); ++ wed_w32(dev, MTK_WED_TX_TKID_CTRL, ++ MTK_WED_TX_TKID_CTRL_PAUSE | ++ FIELD_PREP(MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM, ++ dev->buf_ring.size / 128) | ++ FIELD_PREP(MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM, ++ dev->buf_ring.size / 128)); ++ wed_w32(dev, MTK_WED_TX_TKID_DYN_THR, ++ FIELD_PREP(MTK_WED_TX_TKID_DYN_THR_LO, 0) | ++ MTK_WED_TX_TKID_DYN_THR_HI); ++ } + + mtk_wed_reset(dev, MTK_WED_RESET_TX_BM); + +- wed_set(dev, MTK_WED_CTRL, +- MTK_WED_CTRL_WED_TX_BM_EN | +- MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); ++ if (dev->hw->version == 1) ++ wed_set(dev, MTK_WED_CTRL, ++ MTK_WED_CTRL_WED_TX_BM_EN | ++ MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); ++ else ++ wed_clr(dev, MTK_WED_TX_TKID_CTRL, MTK_WED_TX_TKID_CTRL_PAUSE); + + wed_clr(dev, MTK_WED_TX_BM_CTRL, MTK_WED_TX_BM_CTRL_PAUSE); + } + + static void +-mtk_wed_ring_reset(struct mtk_wdma_desc *desc, int size) ++mtk_wed_ring_reset(struct mtk_wed_ring *ring, int size) + { ++ void *head = (void *)ring->desc; + int i; + + for (i = 0; i < size; i++) { +- desc[i].buf0 = 0; +- desc[i].ctrl = cpu_to_le32(MTK_WDMA_DESC_CTRL_DMA_DONE); +- desc[i].buf1 = 0; +- desc[i].info = 0; ++ struct mtk_wdma_desc *desc; ++ ++ desc = (struct mtk_wdma_desc *)(head + i * ring->desc_size); ++ desc->buf0 = 0; ++ desc->ctrl = cpu_to_le32(MTK_WDMA_DESC_CTRL_DMA_DONE); ++ desc->buf1 = 0; ++ desc->info = 0; + } + } + +@@ -436,12 +579,10 @@ mtk_wed_reset_dma(struct mtk_wed_device + int i; + + for (i = 0; i < ARRAY_SIZE(dev->tx_ring); i++) { +- struct mtk_wdma_desc *desc = dev->tx_ring[i].desc; +- +- if (!desc) ++ if (!dev->tx_ring[i].desc) + continue; + +- mtk_wed_ring_reset(desc, MTK_WED_TX_RING_SIZE); ++ mtk_wed_ring_reset(&dev->tx_ring[i], MTK_WED_TX_RING_SIZE); + } + + if (mtk_wed_poll_busy(dev)) +@@ -498,16 +639,16 @@ mtk_wed_reset_dma(struct mtk_wed_device + + static int + mtk_wed_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring, +- int size) ++ int size, u32 desc_size) + { +- ring->desc = dma_alloc_coherent(dev->hw->dev, +- size * sizeof(*ring->desc), ++ ring->desc = dma_alloc_coherent(dev->hw->dev, size * desc_size, + &ring->desc_phys, GFP_KERNEL); + if (!ring->desc) + return -ENOMEM; + ++ ring->desc_size = desc_size; + ring->size = size; +- mtk_wed_ring_reset(ring->desc, size); ++ mtk_wed_ring_reset(ring, size); + + return 0; + } +@@ -515,9 +656,10 @@ mtk_wed_ring_alloc(struct mtk_wed_device + static int + mtk_wed_wdma_ring_setup(struct mtk_wed_device *dev, int idx, int size) + { ++ u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version; + struct mtk_wed_ring *wdma = &dev->tx_wdma[idx]; + +- if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE)) ++ if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, desc_size)) + return -ENOMEM; + + wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE, +@@ -546,16 +688,41 @@ mtk_wed_configure_irq(struct mtk_wed_dev + MTK_WED_CTRL_WED_TX_BM_EN | + MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); + +- wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, +- MTK_WED_PCIE_INT_TRIGGER_STATUS); ++ if (dev->hw->version == 1) { ++ wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, ++ MTK_WED_PCIE_INT_TRIGGER_STATUS); ++ ++ wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, ++ MTK_WED_WPDMA_INT_TRIGGER_RX_DONE | ++ MTK_WED_WPDMA_INT_TRIGGER_TX_DONE); + +- wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, +- MTK_WED_WPDMA_INT_TRIGGER_RX_DONE | +- MTK_WED_WPDMA_INT_TRIGGER_TX_DONE); ++ wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask); ++ } else { ++ /* initail tx interrupt trigger */ ++ wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX, ++ MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN | ++ MTK_WED_WPDMA_INT_CTRL_TX0_DONE_CLR | ++ MTK_WED_WPDMA_INT_CTRL_TX1_DONE_EN | ++ MTK_WED_WPDMA_INT_CTRL_TX1_DONE_CLR | ++ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX0_DONE_TRIG, ++ dev->wlan.tx_tbit[0]) | ++ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX1_DONE_TRIG, ++ dev->wlan.tx_tbit[1])); ++ ++ /* initail txfree interrupt trigger */ ++ wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX_FREE, ++ MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_EN | ++ MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_CLR | ++ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_TRIG, ++ dev->wlan.txfree_tbit)); ++ ++ wed_w32(dev, MTK_WED_WDMA_INT_CLR, wdma_mask); ++ wed_set(dev, MTK_WED_WDMA_INT_CTRL, ++ FIELD_PREP(MTK_WED_WDMA_INT_CTRL_POLL_SRC_SEL, ++ dev->wdma_idx)); ++ } + +- /* initail wdma interrupt agent */ + wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, wdma_mask); +- wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask); + + wdma_w32(dev, MTK_WDMA_INT_MASK, wdma_mask); + wdma_w32(dev, MTK_WDMA_INT_GRP2, wdma_mask); +@@ -580,14 +747,28 @@ mtk_wed_dma_enable(struct mtk_wed_device + wdma_set(dev, MTK_WDMA_GLO_CFG, + MTK_WDMA_GLO_CFG_TX_DMA_EN | + MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | +- MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | +- MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); ++ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES); ++ ++ if (dev->hw->version == 1) { ++ wdma_set(dev, MTK_WDMA_GLO_CFG, ++ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); ++ } else { ++ wed_set(dev, MTK_WED_WPDMA_CTRL, ++ MTK_WED_WPDMA_CTRL_SDL1_FIXED); ++ ++ wed_set(dev, MTK_WED_WPDMA_GLO_CFG, ++ MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC | ++ MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC); ++ ++ wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, ++ MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP | ++ MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV); ++ } + } + + static void + mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask) + { +- u32 val; + int i; + + for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) +@@ -598,14 +779,17 @@ mtk_wed_start(struct mtk_wed_device *dev + mtk_wed_configure_irq(dev, irq_mask); + + mtk_wed_set_ext_int(dev, true); +- val = dev->wlan.wpdma_phys | +- MTK_PCIE_MIRROR_MAP_EN | +- FIELD_PREP(MTK_PCIE_MIRROR_MAP_WED_ID, dev->hw->index); +- +- if (dev->hw->index) +- val |= BIT(1); +- val |= BIT(0); +- regmap_write(dev->hw->mirror, dev->hw->index * 4, val); ++ ++ if (dev->hw->version == 1) { ++ u32 val = dev->wlan.wpdma_phys | MTK_PCIE_MIRROR_MAP_EN | ++ FIELD_PREP(MTK_PCIE_MIRROR_MAP_WED_ID, ++ dev->hw->index); ++ ++ val |= BIT(0) | (BIT(1) * !!dev->hw->index); ++ regmap_write(dev->hw->mirror, dev->hw->index * 4, val); ++ } else { ++ mtk_wed_set_512_support(dev, true); ++ } + + mtk_wed_dma_enable(dev); + dev->running = true; +@@ -639,7 +823,9 @@ mtk_wed_attach(struct mtk_wed_device *de + goto out; + } + +- dev_info(&dev->wlan.pci_dev->dev, "attaching wed device %d\n", hw->index); ++ dev_info(&dev->wlan.pci_dev->dev, ++ "attaching wed device %d version %d\n", ++ hw->index, hw->version); + + dev->hw = hw; + dev->dev = hw->dev; +@@ -657,7 +843,9 @@ mtk_wed_attach(struct mtk_wed_device *de + } + + mtk_wed_hw_init_early(dev); +- regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, BIT(hw->index), 0); ++ if (hw->hifsys) ++ regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, ++ BIT(hw->index), 0); + + out: + mutex_unlock(&hw_lock); +@@ -684,7 +872,8 @@ mtk_wed_tx_ring_setup(struct mtk_wed_dev + + BUG_ON(idx >= ARRAY_SIZE(dev->tx_ring)); + +- if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE)) ++ if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE, ++ sizeof(*ring->desc))) + return -ENOMEM; + + if (mtk_wed_wdma_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE)) +@@ -711,21 +900,21 @@ static int + mtk_wed_txfree_ring_setup(struct mtk_wed_device *dev, void __iomem *regs) + { + struct mtk_wed_ring *ring = &dev->txfree_ring; +- int i; ++ int i, index = dev->hw->version == 1; + + /* + * For txfree event handling, the same DMA ring is shared between WED + * and WLAN. The WLAN driver accesses the ring index registers through + * WED + */ +- ring->reg_base = MTK_WED_RING_RX(1); ++ ring->reg_base = MTK_WED_RING_RX(index); + ring->wpdma = regs; + + for (i = 0; i < 12; i += 4) { + u32 val = readl(regs + i); + +- wed_w32(dev, MTK_WED_RING_RX(1) + i, val); +- wed_w32(dev, MTK_WED_WPDMA_RING_RX(1) + i, val); ++ wed_w32(dev, MTK_WED_RING_RX(index) + i, val); ++ wed_w32(dev, MTK_WED_WPDMA_RING_RX(index) + i, val); + } + + return 0; +@@ -734,11 +923,19 @@ mtk_wed_txfree_ring_setup(struct mtk_wed + static u32 + mtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask) + { +- u32 val; ++ u32 val, ext_mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK; ++ ++ if (dev->hw->version == 1) ++ ext_mask |= MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR; ++ else ++ ext_mask |= MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH | ++ MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH | ++ MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT | ++ MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR; + + val = wed_r32(dev, MTK_WED_EXT_INT_STATUS); + wed_w32(dev, MTK_WED_EXT_INT_STATUS, val); +- val &= MTK_WED_EXT_INT_STATUS_ERROR_MASK; ++ val &= ext_mask; + if (!dev->hw->num_flows) + val &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD; + if (val && net_ratelimit()) +@@ -813,7 +1010,8 @@ out: + } + + void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, +- void __iomem *wdma, int index) ++ void __iomem *wdma, phys_addr_t wdma_phy, ++ int index) + { + static const struct mtk_wed_ops wed_ops = { + .attach = mtk_wed_attach, +@@ -860,26 +1058,33 @@ void mtk_wed_add_hw(struct device_node * + hw = kzalloc(sizeof(*hw), GFP_KERNEL); + if (!hw) + goto unlock; ++ + hw->node = np; + hw->regs = regs; + hw->eth = eth; + hw->dev = &pdev->dev; ++ hw->wdma_phy = wdma_phy; + hw->wdma = wdma; + hw->index = index; + hw->irq = irq; +- hw->mirror = syscon_regmap_lookup_by_phandle(eth_np, +- "mediatek,pcie-mirror"); +- hw->hifsys = syscon_regmap_lookup_by_phandle(eth_np, +- "mediatek,hifsys"); +- if (IS_ERR(hw->mirror) || IS_ERR(hw->hifsys)) { +- kfree(hw); +- goto unlock; +- } ++ hw->version = MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ? 2 : 1; + +- if (!index) { +- regmap_write(hw->mirror, 0, 0); +- regmap_write(hw->mirror, 4, 0); ++ if (hw->version == 1) { ++ hw->mirror = syscon_regmap_lookup_by_phandle(eth_np, ++ "mediatek,pcie-mirror"); ++ hw->hifsys = syscon_regmap_lookup_by_phandle(eth_np, ++ "mediatek,hifsys"); ++ if (IS_ERR(hw->mirror) || IS_ERR(hw->hifsys)) { ++ kfree(hw); ++ goto unlock; ++ } ++ ++ if (!index) { ++ regmap_write(hw->mirror, 0, 0); ++ regmap_write(hw->mirror, 4, 0); ++ } + } ++ + mtk_wed_hw_add_debugfs(hw); + + hw_list[index] = hw; +--- a/drivers/net/ethernet/mediatek/mtk_wed.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed.h +@@ -18,11 +18,13 @@ struct mtk_wed_hw { + 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; + u32 debugfs_reg; + u32 num_flows; ++ u8 version; + char dirname[5]; + int irq; + int index; +@@ -101,14 +103,16 @@ wpdma_txfree_w32(struct mtk_wed_device * + } + + void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, +- void __iomem *wdma, int index); ++ 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); + #else + static inline void + mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, +- void __iomem *wdma, int index) ++ void __iomem *wdma, phys_addr_t wdma_phy, ++ int index) + { + } + static inline void +--- a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c +@@ -116,6 +116,9 @@ wed_txinfo_show(struct seq_file *s, void + DUMP_WDMA(WDMA_GLO_CFG), + DUMP_WDMA_RING(WDMA_RING_RX(0)), + DUMP_WDMA_RING(WDMA_RING_RX(1)), ++ ++ DUMP_STR("TX FREE"), ++ DUMP_WED(WED_RX_MIB(0)), + }; + struct mtk_wed_hw *hw = s->private; + struct mtk_wed_device *dev = hw->wed_dev; +--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h +@@ -5,6 +5,7 @@ + #define __MTK_WED_REGS_H + + #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) +@@ -41,6 +42,7 @@ struct mtk_wdma_desc { + #define MTK_WED_CTRL_RESERVE_EN BIT(12) + #define MTK_WED_CTRL_RESERVE_BUSY BIT(13) + #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_EXT_INT_STATUS 0x020 +@@ -57,7 +59,8 @@ struct mtk_wdma_desc { + #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_DRV_W_RESP_ERR BIT(22) ++#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_ERROR_MASK (MTK_WED_EXT_INT_STATUS_TF_LEN_ERR | \ + MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD | \ +@@ -65,8 +68,7 @@ struct mtk_wdma_desc { + 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_DRV_R_RESP_ERR | \ +- MTK_WED_EXT_INT_STATUS_TX_DRV_W_RESP_ERR) ++ MTK_WED_EXT_INT_STATUS_TX_DMA_R_RESP_ERR) + + #define MTK_WED_EXT_INT_MASK 0x028 + +@@ -81,6 +83,7 @@ struct mtk_wdma_desc { + #define MTK_WED_TX_BM_BASE 0x084 + + #define MTK_WED_TX_BM_TKID 0x088 ++#define MTK_WED_TX_BM_TKID_V2 0x0c8 + #define MTK_WED_TX_BM_TKID_START GENMASK(15, 0) + #define MTK_WED_TX_BM_TKID_END GENMASK(31, 16) + +@@ -94,7 +97,25 @@ struct mtk_wdma_desc { + + #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_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 +@@ -125,6 +146,7 @@ struct mtk_wdma_desc { + #define MTK_WED_RESET_IDX_RX GENMASK(17, 16) + + #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) + +@@ -155,21 +177,62 @@ struct mtk_wdma_desc { + #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(18, 16) ++#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNSUPPORT_FMT BIT(19) ++#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UEVENT_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_DMAD_DW3_PREV BIT(28) ++ + #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_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_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_MSK_EN_POLA BIT(20) ++#define MTK_WED_PCIE_INT_CTRL_SRC_SEL GENMASK(17, 16) ++#define MTK_WED_PCIE_INT_CTRL_POLL_EN GENMASK(13, 12) ++ + #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) +@@ -203,15 +266,24 @@ struct mtk_wdma_desc { + #define MTK_WED_WDMA_RESET_IDX_RX GENMASK(17, 16) + #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_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) +@@ -221,6 +293,7 @@ struct mtk_wdma_desc { + #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 +@@ -234,6 +307,8 @@ struct mtk_wdma_desc { + #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) +--- a/include/linux/soc/mediatek/mtk_wed.h ++++ b/include/linux/soc/mediatek/mtk_wed.h +@@ -14,6 +14,7 @@ struct mtk_wdma_desc; + struct mtk_wed_ring { + struct mtk_wdma_desc *desc; + dma_addr_t desc_phys; ++ u32 desc_size; + int size; + + u32 reg_base; +@@ -45,10 +46,17 @@ struct mtk_wed_device { + struct pci_dev *pci_dev; + + u32 wpdma_phys; ++ u32 wpdma_int; ++ u32 wpdma_mask; ++ u32 wpdma_tx; ++ u32 wpdma_txfree; + + u16 token_start; + unsigned int nbuf; + ++ u8 tx_tbit[MTK_WED_TX_QUEUES]; ++ u8 txfree_tbit; ++ + u32 (*init_buf)(void *ptr, dma_addr_t phys, int token_id); + int (*offload_enable)(struct mtk_wed_device *wed); + void (*offload_disable)(struct mtk_wed_device *wed); diff --git a/target/linux/generic/pending-5.15/797-net-ethernet-mtk_eth_wed-add-axi-bus-support.patch b/target/linux/generic/pending-5.15/797-net-ethernet-mtk_eth_wed-add-axi-bus-support.patch new file mode 100644 index 0000000000..70b7bad31f --- /dev/null +++ b/target/linux/generic/pending-5.15/797-net-ethernet-mtk_eth_wed-add-axi-bus-support.patch @@ -0,0 +1,237 @@ +From 6e1df49f330dce7c58a39d6772f1385b6887bb03 Mon Sep 17 00:00:00 2001 +Message-Id: <6e1df49f330dce7c58a39d6772f1385b6887bb03.1662990860.git.lorenzo@kernel.org> +From: Lorenzo Bianconi +Date: Thu, 8 Sep 2022 11:26:10 +0200 +Subject: [PATCH net-next] net: ethernet: mtk_eth_wed: add axi bus support + +Other than pcie bus, introduce support for axi bus to mtk wed driver. +Axi bus is used to connect mt7986-wmac soc chip available on mt7986 +device. + +Co-developed-by: Bo Jiao +Signed-off-by: Bo Jiao +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_wed.c | 116 +++++++++++++------ + drivers/net/ethernet/mediatek/mtk_wed_regs.h | 2 + + include/linux/soc/mediatek/mtk_wed.h | 11 +- + 3 files changed, 91 insertions(+), 38 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -85,11 +85,31 @@ static struct mtk_wed_hw * + mtk_wed_assign(struct mtk_wed_device *dev) + { + struct mtk_wed_hw *hw; ++ int i; ++ ++ if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) { ++ hw = hw_list[pci_domain_nr(dev->wlan.pci_dev->bus)]; ++ if (!hw) ++ return NULL; ++ ++ if (!hw->wed_dev) ++ goto out; ++ ++ if (hw->version == 1) ++ return NULL; ++ ++ /* MT7986 WED devices do not have any pcie slot restrictions */ ++ } ++ /* MT7986 PCIE or AXI */ ++ for (i = 0; i < ARRAY_SIZE(hw_list); i++) { ++ hw = hw_list[i]; ++ if (hw && !hw->wed_dev) ++ goto out; ++ } + +- hw = hw_list[pci_domain_nr(dev->wlan.pci_dev->bus)]; +- if (!hw || hw->wed_dev) +- return NULL; ++ return NULL; + ++out: + hw->wed_dev = dev; + return hw; + } +@@ -322,7 +342,6 @@ mtk_wed_stop(struct mtk_wed_device *dev) + static void + mtk_wed_detach(struct mtk_wed_device *dev) + { +- struct device_node *wlan_node = dev->wlan.pci_dev->dev.of_node; + struct mtk_wed_hw *hw = dev->hw; + + mutex_lock(&hw_lock); +@@ -337,9 +356,14 @@ mtk_wed_detach(struct mtk_wed_device *de + mtk_wed_free_buffer(dev); + mtk_wed_free_tx_rings(dev); + +- if (of_dma_is_coherent(wlan_node) && hw->hifsys) +- regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, +- BIT(hw->index), BIT(hw->index)); ++ if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) { ++ struct device_node *wlan_node; ++ ++ wlan_node = dev->wlan.pci_dev->dev.of_node; ++ if (of_dma_is_coherent(wlan_node) && hw->hifsys) ++ regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, ++ BIT(hw->index), BIT(hw->index)); ++ } + + if (!hw_list[!hw->index]->wed_dev && + hw->eth->dma_dev != hw->eth->dev) +@@ -356,40 +380,54 @@ mtk_wed_detach(struct mtk_wed_device *de + static void + mtk_wed_bus_init(struct mtk_wed_device *dev) + { +- struct device_node *np = dev->hw->eth->dev->of_node; +- struct regmap *regs; +- u32 val; +- +- regs = syscon_regmap_lookup_by_phandle(np, "mediatek,wed-pcie"); +- if (IS_ERR(regs)) +- return; ++ switch (dev->wlan.bus_type) { ++ case MTK_WED_BUS_PCIE: { ++ struct device_node *np = dev->hw->eth->dev->of_node; ++ struct regmap *regs; ++ u32 val; ++ ++ regs = syscon_regmap_lookup_by_phandle(np, ++ "mediatek,wed-pcie"); ++ if (IS_ERR(regs)) ++ break; + +- regmap_update_bits(regs, 0, BIT(0), BIT(0)); ++ regmap_update_bits(regs, 0, BIT(0), BIT(0)); + +- wed_w32(dev, MTK_WED_PCIE_INT_CTRL, +- FIELD_PREP(MTK_WED_PCIE_INT_CTRL_POLL_EN, 2)); ++ wed_w32(dev, MTK_WED_PCIE_INT_CTRL, ++ FIELD_PREP(MTK_WED_PCIE_INT_CTRL_POLL_EN, 2)); + +- /* pcie interrupt control: pola/source selection */ +- wed_set(dev, MTK_WED_PCIE_INT_CTRL, +- MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA | +- FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL, 1)); +- wed_r32(dev, MTK_WED_PCIE_INT_CTRL); +- +- val = wed_r32(dev, MTK_WED_PCIE_CFG_INTM); +- val = wed_r32(dev, MTK_WED_PCIE_CFG_BASE); +- wed_w32(dev, MTK_WED_PCIE_CFG_INTM, PCIE_BASE_ADDR0 | 0x180); +- wed_w32(dev, MTK_WED_PCIE_CFG_BASE, PCIE_BASE_ADDR0 | 0x184); +- +- val = wed_r32(dev, MTK_WED_PCIE_CFG_INTM); +- val = wed_r32(dev, MTK_WED_PCIE_CFG_BASE); +- +- /* pcie interrupt status trigger register */ +- wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24)); +- wed_r32(dev, MTK_WED_PCIE_INT_TRIGGER); +- +- /* pola setting */ +- val = wed_r32(dev, MTK_WED_PCIE_INT_CTRL); +- wed_set(dev, MTK_WED_PCIE_INT_CTRL, MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA); ++ /* pcie interrupt control: pola/source selection */ ++ wed_set(dev, MTK_WED_PCIE_INT_CTRL, ++ MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA | ++ FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL, 1)); ++ wed_r32(dev, MTK_WED_PCIE_INT_CTRL); ++ ++ val = wed_r32(dev, MTK_WED_PCIE_CFG_INTM); ++ val = wed_r32(dev, MTK_WED_PCIE_CFG_BASE); ++ wed_w32(dev, MTK_WED_PCIE_CFG_INTM, PCIE_BASE_ADDR0 | 0x180); ++ wed_w32(dev, MTK_WED_PCIE_CFG_BASE, PCIE_BASE_ADDR0 | 0x184); ++ ++ val = wed_r32(dev, MTK_WED_PCIE_CFG_INTM); ++ val = wed_r32(dev, MTK_WED_PCIE_CFG_BASE); ++ ++ /* pcie interrupt status trigger register */ ++ wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24)); ++ wed_r32(dev, MTK_WED_PCIE_INT_TRIGGER); ++ ++ /* pola setting */ ++ val = wed_r32(dev, MTK_WED_PCIE_INT_CTRL); ++ wed_set(dev, MTK_WED_PCIE_INT_CTRL, ++ MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA); ++ break; ++ } ++ case MTK_WED_BUS_AXI: ++ wed_set(dev, MTK_WED_WPDMA_INT_CTRL, ++ MTK_WED_WPDMA_INT_CTRL_SIG_SRC | ++ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_SRC_SEL, 0)); ++ break; ++ default: ++ break; ++ } + } + + static void +@@ -800,12 +838,14 @@ mtk_wed_attach(struct mtk_wed_device *de + __releases(RCU) + { + struct mtk_wed_hw *hw; ++ struct device *device; + int ret = 0; + + RCU_LOCKDEP_WARN(!rcu_read_lock_held(), + "mtk_wed_attach without holding the RCU read lock"); + +- if (pci_domain_nr(dev->wlan.pci_dev->bus) > 1 || ++ if ((dev->wlan.bus_type == MTK_WED_BUS_PCIE && ++ pci_domain_nr(dev->wlan.pci_dev->bus) > 1) || + !try_module_get(THIS_MODULE)) + ret = -ENODEV; + +@@ -823,8 +863,10 @@ mtk_wed_attach(struct mtk_wed_device *de + goto out; + } + +- dev_info(&dev->wlan.pci_dev->dev, +- "attaching wed device %d version %d\n", ++ device = dev->wlan.bus_type == MTK_WED_BUS_PCIE ++ ? &dev->wlan.pci_dev->dev ++ : &dev->wlan.platform_dev->dev; ++ dev_info(device, "attaching wed device %d version %d\n", + hw->index, hw->version); + + dev->hw = hw; +--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h +@@ -198,6 +198,8 @@ struct mtk_wdma_desc { + + #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 + +--- a/include/linux/soc/mediatek/mtk_wed.h ++++ b/include/linux/soc/mediatek/mtk_wed.h +@@ -11,6 +11,11 @@ + struct mtk_wed_hw; + struct mtk_wdma_desc; + ++enum mtk_wed_bus_tye { ++ MTK_WED_BUS_PCIE, ++ MTK_WED_BUS_AXI, ++}; ++ + struct mtk_wed_ring { + struct mtk_wdma_desc *desc; + dma_addr_t desc_phys; +@@ -43,7 +48,11 @@ struct mtk_wed_device { + + /* filled by driver: */ + struct { +- struct pci_dev *pci_dev; ++ union { ++ struct platform_device *platform_dev; ++ struct pci_dev *pci_dev; ++ }; ++ enum mtk_wed_bus_tye bus_type; + + u32 wpdma_phys; + u32 wpdma_int; diff --git a/target/linux/generic/pending-5.15/798-net-ethernet-mtk_eth_soc-introduce-flow-offloading-s.patch b/target/linux/generic/pending-5.15/798-net-ethernet-mtk_eth_soc-introduce-flow-offloading-s.patch new file mode 100644 index 0000000000..2fb0b1dfd6 --- /dev/null +++ b/target/linux/generic/pending-5.15/798-net-ethernet-mtk_eth_soc-introduce-flow-offloading-s.patch @@ -0,0 +1,882 @@ +From 93408c858e5dc01d97c55efa721268f63fde2ae5 Mon Sep 17 00:00:00 2001 +Message-Id: <93408c858e5dc01d97c55efa721268f63fde2ae5.1662886034.git.lorenzo@kernel.org> +In-Reply-To: +References: +From: Lorenzo Bianconi +Date: Sat, 3 Sep 2022 18:34:09 +0200 +Subject: [PATCH net-next 4/5] net: ethernet: mtk_eth_soc: introduce flow + offloading support for mt7986 + +Introduce hw flow offload support for mt7986 chipset. PPE is not enabled +yet in mt7986 since mt76 support is not available yet. + +Co-developed-by: Bo Jiao +Signed-off-by: Bo Jiao +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 11 +- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 72 ++++++ + drivers/net/ethernet/mediatek/mtk_ppe.c | 213 +++++++++++------- + drivers/net/ethernet/mediatek/mtk_ppe.h | 52 ++++- + .../net/ethernet/mediatek/mtk_ppe_offload.c | 49 ++-- + drivers/net/ethernet/mediatek/mtk_ppe_regs.h | 8 + + 6 files changed, 289 insertions(+), 116 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1858,12 +1858,14 @@ static int mtk_poll_rx(struct napi_struc + bytes += skb->len; + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON, trxd.rxd5); + hash = trxd.rxd5 & MTK_RXD5_FOE_ENTRY; + if (hash != MTK_RXD5_FOE_ENTRY) + skb_set_hash(skb, jhash_1word(hash, 0), + PKT_HASH_TYPE_L4); + rxdcsum = &trxd.rxd3; + } else { ++ reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4); + hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY; + if (hash != MTK_RXD4_FOE_ENTRY) + skb_set_hash(skb, jhash_1word(hash, 0), +@@ -1877,7 +1879,6 @@ static int mtk_poll_rx(struct napi_struc + skb_checksum_none_assert(skb); + skb->protocol = eth_type_trans(skb, netdev); + +- reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4); + if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) + mtk_ppe_check_skb(eth->ppe[0], skb, hash); + +@@ -4183,7 +4184,7 @@ static const struct mtk_soc_data mt7621_ + .required_pctl = false, + .offload_version = 2, + .hash_offset = 2, +- .foe_entry_size = sizeof(struct mtk_foe_entry), ++ .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +@@ -4203,7 +4204,7 @@ static const struct mtk_soc_data mt7622_ + .required_pctl = false, + .offload_version = 2, + .hash_offset = 2, +- .foe_entry_size = sizeof(struct mtk_foe_entry), ++ .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +@@ -4222,7 +4223,7 @@ static const struct mtk_soc_data mt7623_ + .required_pctl = true, + .offload_version = 2, + .hash_offset = 2, +- .foe_entry_size = sizeof(struct mtk_foe_entry), ++ .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +@@ -4254,9 +4255,11 @@ static const struct mtk_soc_data mt7986_ + .reg_map = &mt7986_reg_map, + .ana_rgc3 = 0x128, + .caps = MT7986_CAPS, ++ .hw_features = MTK_HW_FEATURES, + .required_clks = MT7986_CLKS_BITMAP, + .required_pctl = false, + .hash_offset = 4, ++ .foe_entry_size = sizeof(struct mtk_foe_entry), + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma_v2), + .rxd_size = sizeof(struct mtk_rx_dma_v2), +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1150,6 +1150,78 @@ mtk_foe_get_entry(struct mtk_ppe *ppe, u + return ppe->foe_table + hash * soc->foe_entry_size; + } + ++static inline u32 mtk_get_ib1_ts_mask(struct mtk_eth *eth) ++{ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ return MTK_FOE_IB1_BIND_TIMESTAMP_V2; ++ ++ return MTK_FOE_IB1_BIND_TIMESTAMP; ++} ++ ++static inline u32 mtk_get_ib1_ppoe_mask(struct mtk_eth *eth) ++{ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ return MTK_FOE_IB1_BIND_PPPOE_V2; ++ ++ return MTK_FOE_IB1_BIND_PPPOE; ++} ++ ++static inline u32 mtk_get_ib1_vlan_tag_mask(struct mtk_eth *eth) ++{ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ return MTK_FOE_IB1_BIND_VLAN_TAG_V2; ++ ++ return MTK_FOE_IB1_BIND_VLAN_TAG; ++} ++ ++static inline u32 mtk_get_ib1_vlan_layer_mask(struct mtk_eth *eth) ++{ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ return MTK_FOE_IB1_BIND_VLAN_LAYER_V2; ++ ++ return MTK_FOE_IB1_BIND_VLAN_LAYER; ++} ++ ++static inline u32 mtk_prep_ib1_vlan_layer(struct mtk_eth *eth, u32 val) ++{ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ return FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER_V2, val); ++ ++ return FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, val); ++} ++ ++static inline u32 mtk_get_ib1_vlan_layer(struct mtk_eth *eth, u32 val) ++{ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ return FIELD_GET(MTK_FOE_IB1_BIND_VLAN_LAYER_V2, val); ++ ++ return FIELD_GET(MTK_FOE_IB1_BIND_VLAN_LAYER, val); ++} ++ ++static inline u32 mtk_get_ib1_pkt_type_mask(struct mtk_eth *eth) ++{ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ return MTK_FOE_IB1_PACKET_TYPE_V2; ++ ++ return MTK_FOE_IB1_PACKET_TYPE; ++} ++ ++static inline u32 mtk_get_ib1_pkt_type(struct mtk_eth *eth, u32 val) ++{ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ return FIELD_GET(MTK_FOE_IB1_PACKET_TYPE_V2, val); ++ ++ return FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, val); ++} ++ ++static inline u32 mtk_get_ib2_multicast_mask(struct mtk_eth *eth) ++{ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ return MTK_FOE_IB2_MULTICAST_V2; ++ ++ return MTK_FOE_IB2_MULTICAST; ++} ++ + /* read the hardware status register */ + void mtk_stats_update_mac(struct mtk_mac *mac); + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -56,7 +56,7 @@ static u32 ppe_clear(struct mtk_ppe *ppe + + static u32 mtk_eth_timestamp(struct mtk_eth *eth) + { +- return mtk_r32(eth, 0x0010) & MTK_FOE_IB1_BIND_TIMESTAMP; ++ return mtk_r32(eth, 0x0010) & mtk_get_ib1_ts_mask(eth); + } + + static int mtk_ppe_wait_busy(struct mtk_ppe *ppe) +@@ -93,7 +93,7 @@ static u32 mtk_ppe_hash_entry(struct mtk + u32 hv1, hv2, hv3; + u32 hash; + +- switch (FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, e->ib1)) { ++ switch (mtk_get_ib1_pkt_type(eth, e->ib1)) { + case MTK_PPE_PKT_TYPE_IPV4_ROUTE: + case MTK_PPE_PKT_TYPE_IPV4_HNAPT: + hv1 = e->ipv4.orig.ports; +@@ -129,9 +129,9 @@ static u32 mtk_ppe_hash_entry(struct mtk + } + + static inline struct mtk_foe_mac_info * +-mtk_foe_entry_l2(struct mtk_foe_entry *entry) ++mtk_foe_entry_l2(struct mtk_eth *eth, struct mtk_foe_entry *entry) + { +- int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); ++ int type = mtk_get_ib1_pkt_type(eth, entry->ib1); + + if (type == MTK_PPE_PKT_TYPE_BRIDGE) + return &entry->bridge.l2; +@@ -143,9 +143,9 @@ mtk_foe_entry_l2(struct mtk_foe_entry *e + } + + static inline u32 * +-mtk_foe_entry_ib2(struct mtk_foe_entry *entry) ++mtk_foe_entry_ib2(struct mtk_eth *eth, struct mtk_foe_entry *entry) + { +- int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); ++ int type = mtk_get_ib1_pkt_type(eth, entry->ib1); + + if (type == MTK_PPE_PKT_TYPE_BRIDGE) + return &entry->bridge.ib2; +@@ -156,27 +156,38 @@ mtk_foe_entry_ib2(struct mtk_foe_entry * + return &entry->ipv4.ib2; + } + +-int mtk_foe_entry_prepare(struct mtk_foe_entry *entry, int type, int l4proto, +- u8 pse_port, u8 *src_mac, u8 *dest_mac) ++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) + { + struct mtk_foe_mac_info *l2; + u32 ports_pad, val; + + memset(entry, 0, sizeof(*entry)); + +- val = FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND) | +- FIELD_PREP(MTK_FOE_IB1_PACKET_TYPE, type) | +- FIELD_PREP(MTK_FOE_IB1_UDP, l4proto == IPPROTO_UDP) | +- MTK_FOE_IB1_BIND_TTL | +- MTK_FOE_IB1_BIND_CACHE; +- entry->ib1 = val; +- +- val = FIELD_PREP(MTK_FOE_IB2_PORT_MG, 0x3f) | +- FIELD_PREP(MTK_FOE_IB2_PORT_AG, 0x1f) | +- FIELD_PREP(MTK_FOE_IB2_DEST_PORT, pse_port); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ val = FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND) | ++ FIELD_PREP(MTK_FOE_IB1_PACKET_TYPE_V2, type) | ++ FIELD_PREP(MTK_FOE_IB1_UDP, l4proto == IPPROTO_UDP) | ++ MTK_FOE_IB1_BIND_CACHE_V2 | MTK_FOE_IB1_BIND_TTL_V2; ++ entry->ib1 = val; ++ ++ val = FIELD_PREP(MTK_FOE_IB2_DEST_PORT_V2, pse_port) | ++ FIELD_PREP(MTK_FOE_IB2_PORT_AG_V2, 0xf); ++ } else { ++ val = FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND) | ++ FIELD_PREP(MTK_FOE_IB1_PACKET_TYPE, type) | ++ FIELD_PREP(MTK_FOE_IB1_UDP, l4proto == IPPROTO_UDP) | ++ MTK_FOE_IB1_BIND_CACHE | MTK_FOE_IB1_BIND_TTL; ++ entry->ib1 = val; ++ ++ val = FIELD_PREP(MTK_FOE_IB2_DEST_PORT, pse_port) | ++ FIELD_PREP(MTK_FOE_IB2_PORT_MG, 0x3f) | ++ FIELD_PREP(MTK_FOE_IB2_PORT_AG, 0x1f); ++ } + + if (is_multicast_ether_addr(dest_mac)) +- val |= MTK_FOE_IB2_MULTICAST; ++ val |= mtk_get_ib2_multicast_mask(eth); + + ports_pad = 0xa5a5a500 | (l4proto & 0xff); + if (type == MTK_PPE_PKT_TYPE_IPV4_ROUTE) +@@ -210,24 +221,30 @@ int mtk_foe_entry_prepare(struct mtk_foe + return 0; + } + +-int mtk_foe_entry_set_pse_port(struct mtk_foe_entry *entry, u8 port) ++int mtk_foe_entry_set_pse_port(struct mtk_eth *eth, ++ struct mtk_foe_entry *entry, u8 port) + { +- u32 *ib2 = mtk_foe_entry_ib2(entry); +- u32 val; ++ u32 *ib2 = mtk_foe_entry_ib2(eth, entry); ++ u32 val = *ib2; + +- val = *ib2; +- val &= ~MTK_FOE_IB2_DEST_PORT; +- val |= FIELD_PREP(MTK_FOE_IB2_DEST_PORT, port); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ val &= ~MTK_FOE_IB2_DEST_PORT_V2; ++ val |= FIELD_PREP(MTK_FOE_IB2_DEST_PORT_V2, port); ++ } else { ++ val &= ~MTK_FOE_IB2_DEST_PORT; ++ val |= FIELD_PREP(MTK_FOE_IB2_DEST_PORT, port); ++ } + *ib2 = val; + + return 0; + } + +-int mtk_foe_entry_set_ipv4_tuple(struct mtk_foe_entry *entry, bool egress, ++int mtk_foe_entry_set_ipv4_tuple(struct mtk_eth *eth, ++ struct mtk_foe_entry *entry, bool egress, + __be32 src_addr, __be16 src_port, + __be32 dest_addr, __be16 dest_port) + { +- int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); ++ int type = mtk_get_ib1_pkt_type(eth, entry->ib1); + struct mtk_ipv4_tuple *t; + + switch (type) { +@@ -262,11 +279,12 @@ int mtk_foe_entry_set_ipv4_tuple(struct + return 0; + } + +-int mtk_foe_entry_set_ipv6_tuple(struct mtk_foe_entry *entry, ++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 type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); ++ int type = mtk_get_ib1_pkt_type(eth, entry->ib1); + u32 *src, *dest; + int i; + +@@ -297,39 +315,41 @@ int mtk_foe_entry_set_ipv6_tuple(struct + return 0; + } + +-int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port) ++int mtk_foe_entry_set_dsa(struct mtk_eth *eth, struct mtk_foe_entry *entry, ++ int port) + { +- struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry); ++ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry); + + l2->etype = BIT(port); + +- if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_LAYER)) +- entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1); ++ if (!(entry->ib1 & mtk_get_ib1_vlan_layer_mask(eth))) ++ entry->ib1 |= mtk_prep_ib1_vlan_layer(eth, 1); + else + l2->etype |= BIT(8); + +- entry->ib1 &= ~MTK_FOE_IB1_BIND_VLAN_TAG; ++ entry->ib1 &= ~mtk_get_ib1_vlan_tag_mask(eth); + + return 0; + } + +-int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid) ++int mtk_foe_entry_set_vlan(struct mtk_eth *eth, struct mtk_foe_entry *entry, ++ int vid) + { +- struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry); ++ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry); + +- switch (FIELD_GET(MTK_FOE_IB1_BIND_VLAN_LAYER, entry->ib1)) { ++ switch (mtk_prep_ib1_vlan_layer(eth, entry->ib1)) { + case 0: +- entry->ib1 |= MTK_FOE_IB1_BIND_VLAN_TAG | +- FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1); ++ entry->ib1 |= mtk_get_ib1_vlan_tag_mask(eth) | ++ mtk_prep_ib1_vlan_layer(eth, 1); + l2->vlan1 = vid; + return 0; + case 1: +- if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_TAG)) { ++ if (!(entry->ib1 & mtk_get_ib1_vlan_tag_mask(eth))) { + l2->vlan1 = vid; + l2->etype |= BIT(8); + } else { + l2->vlan2 = vid; +- entry->ib1 += FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1); ++ entry->ib1 += mtk_prep_ib1_vlan_layer(eth, 1); + } + return 0; + default: +@@ -337,34 +357,42 @@ int mtk_foe_entry_set_vlan(struct mtk_fo + } + } + +-int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid) ++int mtk_foe_entry_set_pppoe(struct mtk_eth *eth, struct mtk_foe_entry *entry, ++ int sid) + { +- struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry); ++ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry); + +- if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_LAYER) || +- (entry->ib1 & MTK_FOE_IB1_BIND_VLAN_TAG)) ++ if (!(entry->ib1 & mtk_get_ib1_vlan_layer_mask(eth)) || ++ (entry->ib1 & mtk_get_ib1_vlan_tag_mask(eth))) + l2->etype = ETH_P_PPP_SES; + +- entry->ib1 |= MTK_FOE_IB1_BIND_PPPOE; ++ entry->ib1 |= mtk_get_ib1_ppoe_mask(eth); + l2->pppoe_id = sid; + + return 0; + } + +-int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq, +- int bss, int wcid) ++int mtk_foe_entry_set_wdma(struct mtk_eth *eth, struct mtk_foe_entry *entry, ++ int wdma_idx, int txq, int bss, int wcid) + { +- struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry); +- u32 *ib2 = mtk_foe_entry_ib2(entry); ++ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry); ++ u32 *ib2 = mtk_foe_entry_ib2(eth, entry); + +- *ib2 &= ~MTK_FOE_IB2_PORT_MG; +- *ib2 |= MTK_FOE_IB2_WDMA_WINFO; +- if (wdma_idx) +- *ib2 |= MTK_FOE_IB2_WDMA_DEVIDX; +- +- l2->vlan2 = FIELD_PREP(MTK_FOE_VLAN2_WINFO_BSS, bss) | +- FIELD_PREP(MTK_FOE_VLAN2_WINFO_WCID, wcid) | +- FIELD_PREP(MTK_FOE_VLAN2_WINFO_RING, txq); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ *ib2 &= ~MTK_FOE_IB2_PORT_MG_V2; ++ *ib2 |= FIELD_PREP(MTK_FOE_IB2_RX_IDX, txq) | ++ MTK_FOE_IB2_WDMA_WINFO_V2; ++ l2->winfo = FIELD_PREP(MTK_FOE_WINFO_WCID, wcid) | ++ FIELD_PREP(MTK_FOE_WINFO_BSS, bss); ++ } else { ++ *ib2 &= ~MTK_FOE_IB2_PORT_MG; ++ *ib2 |= MTK_FOE_IB2_WDMA_WINFO; ++ if (wdma_idx) ++ *ib2 |= MTK_FOE_IB2_WDMA_DEVIDX; ++ l2->vlan2 = FIELD_PREP(MTK_FOE_VLAN2_WINFO_BSS, bss) | ++ FIELD_PREP(MTK_FOE_VLAN2_WINFO_WCID, wcid) | ++ FIELD_PREP(MTK_FOE_VLAN2_WINFO_RING, txq); ++ } + + return 0; + } +@@ -376,14 +404,15 @@ static inline bool mtk_foe_entry_usable( + } + + static bool +-mtk_flow_entry_match(struct mtk_flow_entry *entry, struct mtk_foe_entry *data) ++mtk_flow_entry_match(struct mtk_eth *eth, struct mtk_flow_entry *entry, ++ struct mtk_foe_entry *data) + { + int type, len; + + if ((data->ib1 ^ entry->data.ib1) & MTK_FOE_IB1_UDP) + return false; + +- type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->data.ib1); ++ type = mtk_get_ib1_pkt_type(eth, entry->data.ib1); + if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE) + len = offsetof(struct mtk_foe_entry, ipv6._rsv); + else +@@ -427,14 +456,12 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp + + static int __mtk_foe_entry_idle_time(struct mtk_ppe *ppe, u32 ib1) + { +- u16 timestamp; +- u16 now; +- +- now = mtk_eth_timestamp(ppe->eth) & MTK_FOE_IB1_BIND_TIMESTAMP; +- timestamp = ib1 & MTK_FOE_IB1_BIND_TIMESTAMP; ++ u32 ib1_ts_mask = mtk_get_ib1_ts_mask(ppe->eth); ++ u16 now = mtk_eth_timestamp(ppe->eth); ++ u16 timestamp = ib1 & ib1_ts_mask; + + if (timestamp > now) +- return MTK_FOE_IB1_BIND_TIMESTAMP + 1 - timestamp + now; ++ return ib1_ts_mask + 1 - timestamp + now; + else + return now - timestamp; + } +@@ -442,6 +469,7 @@ static int __mtk_foe_entry_idle_time(str + static void + mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { ++ u32 ib1_ts_mask = mtk_get_ib1_ts_mask(ppe->eth); + struct mtk_flow_entry *cur; + struct mtk_foe_entry *hwe; + struct hlist_node *tmp; +@@ -466,8 +494,8 @@ mtk_flow_entry_update_l2(struct mtk_ppe + continue; + + idle = cur_idle; +- entry->data.ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP; +- entry->data.ib1 |= hwe->ib1 & MTK_FOE_IB1_BIND_TIMESTAMP; ++ entry->data.ib1 &= ~ib1_ts_mask; ++ entry->data.ib1 |= hwe->ib1 & ib1_ts_mask; + } + } + +@@ -489,7 +517,7 @@ mtk_flow_entry_update(struct mtk_ppe *pp + + hwe = mtk_foe_get_entry(ppe, entry->hash); + memcpy(&foe, hwe, ppe->eth->soc->foe_entry_size); +- if (!mtk_flow_entry_match(entry, &foe)) { ++ if (!mtk_flow_entry_match(ppe->eth, entry, &foe)) { + entry->hash = 0xffff; + goto out; + } +@@ -504,16 +532,22 @@ static void + __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, + u16 hash) + { ++ struct mtk_eth *eth = ppe->eth; ++ u16 timestamp = mtk_eth_timestamp(eth); + struct mtk_foe_entry *hwe; +- u16 timestamp; + +- timestamp = mtk_eth_timestamp(ppe->eth); +- timestamp &= MTK_FOE_IB1_BIND_TIMESTAMP; +- entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP; +- entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP, timestamp); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP_V2; ++ entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP_V2, ++ timestamp); ++ } else { ++ entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP; ++ entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP, ++ timestamp); ++ } + + hwe = mtk_foe_get_entry(ppe, hash); +- memcpy(&hwe->data, &entry->data, ppe->eth->soc->foe_entry_size); ++ memcpy(&hwe->data, &entry->data, eth->soc->foe_entry_size); + wmb(); + hwe->ib1 = entry->ib1; + +@@ -540,8 +574,8 @@ mtk_foe_entry_commit_l2(struct mtk_ppe * + + int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { +- int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->data.ib1); + const struct mtk_soc_data *soc = ppe->eth->soc; ++ int type = mtk_get_ib1_pkt_type(ppe->eth, entry->data.ib1); + u32 hash; + + if (type == MTK_PPE_PKT_TYPE_BRIDGE) +@@ -564,7 +598,7 @@ mtk_foe_entry_commit_subflow(struct mtk_ + struct mtk_flow_entry *flow_info; + struct mtk_foe_entry foe = {}, *hwe; + struct mtk_foe_mac_info *l2; +- u32 ib1_mask = MTK_FOE_IB1_PACKET_TYPE | MTK_FOE_IB1_UDP; ++ u32 ib1_mask = mtk_get_ib1_pkt_type_mask(ppe->eth) | MTK_FOE_IB1_UDP; + int type; + + flow_info = kzalloc(offsetof(struct mtk_flow_entry, l2_data.end), +@@ -584,16 +618,16 @@ mtk_foe_entry_commit_subflow(struct mtk_ + foe.ib1 &= ib1_mask; + foe.ib1 |= entry->data.ib1 & ~ib1_mask; + +- l2 = mtk_foe_entry_l2(&foe); ++ l2 = mtk_foe_entry_l2(ppe->eth, &foe); + memcpy(l2, &entry->data.bridge.l2, sizeof(*l2)); + +- type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, foe.ib1); ++ type = mtk_get_ib1_pkt_type(ppe->eth, foe.ib1); + if (type == MTK_PPE_PKT_TYPE_IPV4_HNAPT) + memcpy(&foe.ipv4.new, &foe.ipv4.orig, sizeof(foe.ipv4.new)); + else if (type >= MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T && l2->etype == ETH_P_IP) + l2->etype = ETH_P_IPV6; + +- *mtk_foe_entry_ib2(&foe) = entry->data.bridge.ib2; ++ *mtk_foe_entry_ib2(ppe->eth, &foe) = entry->data.bridge.ib2; + + __mtk_foe_entry_commit(ppe, &foe, hash); + } +@@ -626,7 +660,7 @@ void __mtk_ppe_check_skb(struct mtk_ppe + continue; + } + +- if (found || !mtk_flow_entry_match(entry, hwe)) { ++ if (found || !mtk_flow_entry_match(ppe->eth, entry, hwe)) { + if (entry->hash != 0xffff) + entry->hash = 0xffff; + continue; +@@ -771,6 +805,8 @@ void mtk_ppe_start(struct mtk_ppe *ppe) + MTK_PPE_SCAN_MODE_KEEPALIVE_AGE) | + FIELD_PREP(MTK_PPE_TB_CFG_ENTRY_NUM, + MTK_PPE_ENTRIES_SHIFT); ++ if (MTK_HAS_CAPS(ppe->eth->soc->caps, MTK_NETSYS_V2)) ++ val |= MTK_PPE_TB_CFG_INFO_SEL; + ppe_w32(ppe, MTK_PPE_TB_CFG, val); + + ppe_w32(ppe, MTK_PPE_IP_PROTO_CHK, +@@ -778,15 +814,21 @@ void mtk_ppe_start(struct mtk_ppe *ppe) + + mtk_ppe_cache_enable(ppe, true); + +- val = MTK_PPE_FLOW_CFG_IP4_TCP_FRAG | +- MTK_PPE_FLOW_CFG_IP4_UDP_FRAG | +- MTK_PPE_FLOW_CFG_IP6_3T_ROUTE | ++ val = MTK_PPE_FLOW_CFG_IP6_3T_ROUTE | + MTK_PPE_FLOW_CFG_IP6_5T_ROUTE | + MTK_PPE_FLOW_CFG_IP6_6RD | + MTK_PPE_FLOW_CFG_IP4_NAT | + MTK_PPE_FLOW_CFG_IP4_NAPT | + MTK_PPE_FLOW_CFG_IP4_DSLITE | + MTK_PPE_FLOW_CFG_IP4_NAT_FRAG; ++ if (MTK_HAS_CAPS(ppe->eth->soc->caps, MTK_NETSYS_V2)) ++ val |= MTK_PPE_MD_TOAP_BYP_CRSN0 | ++ MTK_PPE_MD_TOAP_BYP_CRSN1 | ++ MTK_PPE_MD_TOAP_BYP_CRSN2 | ++ MTK_PPE_FLOW_CFG_IP4_HASH_GRE_KEY; ++ else ++ val |= MTK_PPE_FLOW_CFG_IP4_TCP_FRAG | ++ MTK_PPE_FLOW_CFG_IP4_UDP_FRAG; + ppe_w32(ppe, MTK_PPE_FLOW_CFG, val); + + val = FIELD_PREP(MTK_PPE_UNBIND_AGE_MIN_PACKETS, 1000) | +@@ -820,6 +862,11 @@ void mtk_ppe_start(struct mtk_ppe *ppe) + ppe_w32(ppe, MTK_PPE_GLO_CFG, val); + + ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT, 0); ++ ++ if (MTK_HAS_CAPS(ppe->eth->soc->caps, MTK_NETSYS_V2)) { ++ ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT1, 0xcb777); ++ ppe_w32(ppe, MTK_PPE_SBW_CTRL, 0x7f); ++ } + } + + int mtk_ppe_stop(struct mtk_ppe *ppe) +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -32,6 +32,15 @@ + #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, +@@ -53,14 +62,25 @@ enum { + + #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_PORT_MG_V2 BIT(7) ++#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) ++ + enum { + MTK_FOE_STATE_INVALID, + MTK_FOE_STATE_UNBIND, +@@ -81,6 +101,9 @@ struct mtk_foe_mac_info { + + u16 pppoe_id; + u16 src_mac_lo; ++ ++ u16 minfo; ++ u16 winfo; + }; + + /* software-only entry type */ +@@ -198,7 +221,7 @@ struct mtk_foe_entry { + struct mtk_foe_ipv4_dslite dslite; + struct mtk_foe_ipv6 ipv6; + struct mtk_foe_ipv6_6rd ipv6_6rd; +- u32 data[19]; ++ u32 data[23]; + }; + }; + +@@ -306,20 +329,27 @@ mtk_ppe_check_skb(struct mtk_ppe *ppe, s + __mtk_ppe_check_skb(ppe, skb, hash); + } + +-int mtk_foe_entry_prepare(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_foe_entry *entry, u8 port); +-int mtk_foe_entry_set_ipv4_tuple(struct mtk_foe_entry *entry, bool orig, ++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_foe_entry *entry, ++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_foe_entry *entry, int port); +-int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid); +-int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid); +-int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq, +- int bss, int wcid); ++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); + 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); +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -52,18 +52,19 @@ static const struct rhashtable_params mt + }; + + static int +-mtk_flow_set_ipv4_addr(struct mtk_foe_entry *foe, struct mtk_flow_data *data, +- bool egress) ++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(foe, 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_foe_entry *foe, struct mtk_flow_data *data) ++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(foe, ++ 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); + } +@@ -190,16 +191,29 @@ mtk_flow_set_output_device(struct mtk_et + int pse_port, dsa_port; + + if (mtk_flow_get_wdma_info(dev, dest_mac, &info) == 0) { +- mtk_foe_entry_set_wdma(foe, info.wdma_idx, info.queue, info.bss, +- info.wcid); +- pse_port = 3; ++ mtk_foe_entry_set_wdma(eth, foe, info.wdma_idx, info.queue, ++ info.bss, info.wcid); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ switch (info.wdma_idx) { ++ case 0: ++ pse_port = 8; ++ break; ++ case 1: ++ pse_port = 9; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } else { ++ pse_port = 3; ++ } + *wed_index = info.wdma_idx; + goto out; + } + + dsa_port = mtk_flow_get_dsa_port(&dev); + if (dsa_port >= 0) +- mtk_foe_entry_set_dsa(foe, dsa_port); ++ mtk_foe_entry_set_dsa(eth, foe, dsa_port); + + if (dev == eth->netdev[0]) + pse_port = 1; +@@ -209,7 +223,7 @@ mtk_flow_set_output_device(struct mtk_et + return -EOPNOTSUPP; + + out: +- mtk_foe_entry_set_pse_port(foe, pse_port); ++ mtk_foe_entry_set_pse_port(eth, foe, pse_port); + + return 0; + } +@@ -333,9 +347,8 @@ mtk_flow_offload_replace(struct mtk_eth + !is_valid_ether_addr(data.eth.h_dest)) + return -EINVAL; + +- err = mtk_foe_entry_prepare(&foe, offload_type, l4proto, 0, +- data.eth.h_source, +- data.eth.h_dest); ++ err = mtk_foe_entry_prepare(eth, &foe, offload_type, l4proto, 0, ++ data.eth.h_source, data.eth.h_dest); + if (err) + return err; + +@@ -360,7 +373,7 @@ mtk_flow_offload_replace(struct mtk_eth + data.v4.src_addr = addrs.key->src; + data.v4.dst_addr = addrs.key->dst; + +- mtk_flow_set_ipv4_addr(&foe, &data, false); ++ mtk_flow_set_ipv4_addr(eth, &foe, &data, false); + } + + if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) { +@@ -371,7 +384,7 @@ mtk_flow_offload_replace(struct mtk_eth + data.v6.src_addr = addrs.key->src; + data.v6.dst_addr = addrs.key->dst; + +- mtk_flow_set_ipv6_addr(&foe, &data); ++ mtk_flow_set_ipv6_addr(eth, &foe, &data); + } + + flow_action_for_each(i, act, &rule->action) { +@@ -401,7 +414,7 @@ mtk_flow_offload_replace(struct mtk_eth + } + + if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { +- err = mtk_flow_set_ipv4_addr(&foe, &data, true); ++ err = mtk_flow_set_ipv4_addr(eth, &foe, &data, true); + if (err) + return err; + } +@@ -413,10 +426,10 @@ mtk_flow_offload_replace(struct mtk_eth + if (data.vlan.proto != htons(ETH_P_8021Q)) + return -EOPNOTSUPP; + +- mtk_foe_entry_set_vlan(&foe, data.vlan.id); ++ mtk_foe_entry_set_vlan(eth, &foe, data.vlan.id); + } + if (data.pppoe.num == 1) +- mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid); ++ 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); +--- a/drivers/net/ethernet/mediatek/mtk_ppe_regs.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h +@@ -21,6 +21,9 @@ + #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) +@@ -54,6 +57,7 @@ + #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) + + enum { + MTK_PPE_SCAN_MODE_DISABLED, +@@ -112,6 +116,8 @@ enum { + #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 +@@ -141,4 +147,6 @@ enum { + #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 diff --git a/target/linux/generic/pending-5.15/799-net-ethernet-mtk_eth_soc-enable-flow-offloading-supp.patch b/target/linux/generic/pending-5.15/799-net-ethernet-mtk_eth_soc-enable-flow-offloading-supp.patch new file mode 100644 index 0000000000..5b94c3ad3a --- /dev/null +++ b/target/linux/generic/pending-5.15/799-net-ethernet-mtk_eth_soc-enable-flow-offloading-supp.patch @@ -0,0 +1,26 @@ +From b94b02a270471337bef73c44fa3493a521e31a61 Mon Sep 17 00:00:00 2001 +Message-Id: +In-Reply-To: +References: +From: Lorenzo Bianconi +Date: Mon, 5 Sep 2022 13:56:13 +0200 +Subject: [PATCH net-next 5/5] net: ethernet: mtk_eth_soc: enable flow + offloading support for mt7986 + +Enable hw packet engine and wireless packet dispatcher for mt7986 + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4258,6 +4258,7 @@ static const struct mtk_soc_data mt7986_ + .hw_features = MTK_HW_FEATURES, + .required_clks = MT7986_CLKS_BITMAP, + .required_pctl = false, ++ .offload_version = 2, + .hash_offset = 4, + .foe_entry_size = sizeof(struct mtk_foe_entry), + .txrx = { diff --git a/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7986a.dtsi index 17adda1554..601c859617 100644 --- a/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +++ b/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7986a.dtsi @@ -397,6 +397,28 @@ #reset-cells = <1>; }; + wed_pcie: wed-pcie@10003000 { + compatible = "mediatek,mt7986-wed-pcie", + "syscon"; + reg = <0 0x10003000 0 0x10>; + }; + + wed0: wed@15010000 { + compatible = "mediatek,mt7986-wed", + "syscon"; + reg = <0 0x15010000 0 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; + }; + + wed1: wed@15011000 { + compatible = "mediatek,mt7986-wed", + "syscon"; + reg = <0 0x15011000 0 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; + }; + eth: ethernet@15100000 { compatible = "mediatek,mt7986-eth"; reg = <0 0x15100000 0 0x80000>; @@ -431,6 +453,8 @@ <&apmixedsys CLK_APMIXED_SGMPLL>; mediatek,ethsys = <ðsys>; mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>; + mediatek,wed-pcie = <&wed_pcie>; + mediatek,wed = <&wed0>, <&wed1>; #reset-cells = <1>; #address-cells = <1>; #size-cells = <0>; diff --git a/target/linux/mediatek/patches-5.15/510-net-mediatek-add-flow-offload-for-mt7623.patch b/target/linux/mediatek/patches-5.15/510-net-mediatek-add-flow-offload-for-mt7623.patch index 9b0d411bba..1f1f6e0e39 100644 --- a/target/linux/mediatek/patches-5.15/510-net-mediatek-add-flow-offload-for-mt7623.patch +++ b/target/linux/mediatek/patches-5.15/510-net-mediatek-add-flow-offload-for-mt7623.patch @@ -14,7 +14,7 @@ Signed-off-by: Frank Wunderlich --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3639,6 +3639,7 @@ static const struct mtk_soc_data mt2701_ +@@ -4166,6 +4166,7 @@ static const struct mtk_soc_data mt2701_ .hw_features = MTK_HW_FEATURES, .required_clks = MT7623_CLKS_BITMAP, .required_pctl = true, diff --git a/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch b/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch index 7544787701..9667930aa1 100644 --- a/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch +++ b/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch @@ -20,7 +20,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -196,13 +196,35 @@ static int _mtk_mdio_write(struct mtk_et +@@ -219,13 +219,35 @@ static int _mtk_mdio_write(struct mtk_et if (ret < 0) return ret; @@ -63,7 +63,7 @@ Signed-off-by: David S. Miller ret = mtk_mdio_busy_wait(eth); if (ret < 0) -@@ -219,12 +241,33 @@ static int _mtk_mdio_read(struct mtk_eth +@@ -242,12 +264,33 @@ static int _mtk_mdio_read(struct mtk_eth if (ret < 0) return ret; @@ -103,7 +103,7 @@ Signed-off-by: David S. Miller ret = mtk_mdio_busy_wait(eth); if (ret < 0) -@@ -621,6 +664,7 @@ static int mtk_mdio_init(struct mtk_eth +@@ -644,6 +687,7 @@ static int mtk_mdio_init(struct mtk_eth eth->mii_bus->name = "mdio"; eth->mii_bus->read = mtk_mdio_read; eth->mii_bus->write = mtk_mdio_write; @@ -113,7 +113,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -327,9 +327,12 @@ +@@ -330,9 +330,12 @@ #define PHY_IAC_ADDR_MASK GENMASK(24, 20) #define PHY_IAC_ADDR(x) FIELD_PREP(PHY_IAC_ADDR_MASK, (x)) #define PHY_IAC_CMD_MASK GENMASK(19, 18) diff --git a/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch b/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch index 43526f3c4a..d8ce3051b7 100644 --- a/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch +++ b/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch @@ -14,7 +14,7 @@ Signed-off-by: René van Dorst --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3230,6 +3230,7 @@ static const struct net_device_ops mtk_n +@@ -3736,6 +3736,7 @@ static const struct net_device_ops mtk_n static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) { @@ -22,7 +22,7 @@ Signed-off-by: René van Dorst const __be32 *_id = of_get_property(np, "reg", NULL); phy_interface_t phy_mode; struct phylink *phylink; -@@ -3349,6 +3350,9 @@ static int mtk_add_mac(struct mtk_eth *e +@@ -3855,6 +3856,9 @@ static int mtk_add_mac(struct mtk_eth *e else eth->netdev[id]->max_mtu = MTK_MAX_RX_LENGTH_2K - MTK_RX_ETH_HLEN;