mt76: switch to page_pool allocator
Subsystems (2)
Lorenzo Bianconi
maintainerPATCH v2 3/4 wifi: mt76: dma: keep rx pages DMA mapped
In reply to Lorenzo BianconiFor mmio devices rely on page_pool capability to keep rx buffers DMA mapped and just sync rx buffers before accessing them.
--- drivers/net/wireless/mediatek/mt76/dma.c | 34 +++++++++++-------- drivers/net/wireless/mediatek/mt76/mac80211.c | 8 +++++ .../net/wireless/mediatek/mt76/mt7915/mmio.c | 5 +-- 3 files changed, 31 insertions(+), 16 deletions(-)
drivers/net/wireless/mediatek/mt76/dma.c +20 -14
@@ -407,9 +407,14 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,if (!t)return NULL ; -dma_unmap_single (dev->dma_dev, t->dma_addr, -SKB_WITH_OVERHEAD (q->buf_size), -DMA_FROM_DEVICE ); +if (mt76_is_page_from_pp (t->ptr)) +dma_sync_single_for_cpu (dev->dma_dev, t->dma_addr, +SKB_WITH_OVERHEAD (q->buf_size), +page_pool_get_dma_dir (q->page_pool)); +else +dma_unmap_single (dev->dma_dev, t->dma_addr, +SKB_WITH_OVERHEAD (q->buf_size), +DMA_FROM_DEVICE ); buf = t->ptr; t->dma_addr =0 ;
@@ -426,9 +431,14 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx, }else { buf = e->buf; e->buf =NULL ; -dma_unmap_single (dev->dma_dev, e->dma_addr[0 ], -SKB_WITH_OVERHEAD (q->buf_size), -DMA_FROM_DEVICE ); +if (mt76_is_page_from_pp (buf)) +dma_sync_single_for_cpu (dev->dma_dev, e->dma_addr[0 ], +SKB_WITH_OVERHEAD (q->buf_size), +page_pool_get_dma_dir (q->page_pool)); +else +dma_unmap_single (dev->dma_dev, e->dma_addr[0 ], +SKB_WITH_OVERHEAD (q->buf_size), +DMA_FROM_DEVICE ); }return buf;
@@ -592,6 +602,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q,spin_lock_bh (&q->lock);while (q->queued < q->ndesc -1 ) { +enum dma_data_direction dir;struct mt76_queue_buf qbuf;dma_addr_t addr;int offset;
@@ -601,19 +612,14 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q,if (!buf)break ; - addr =dma_map_single (dev->dma_dev, buf + offset, len, -DMA_FROM_DEVICE ); -if (unlikely (dma_mapping_error (dev->dma_dev, addr))) { -mt76_put_page_pool_buf (buf, allow_direct); -break ; - } + addr =page_pool_get_dma_addr (virt_to_head_page (buf)) + offset; + dir =page_pool_get_dma_dir (q->page_pool); +dma_sync_single_for_device (dev->dma_dev, addr, len, dir); qbuf.addr = addr + q->buf_offset; qbuf.len = len - q->buf_offset; qbuf.skip_unmap = false;if (mt76_dma_add_rx_buf (dev, q, &qbuf, buf) <0 ) { -dma_unmap_single (dev->dma_dev, addr, len, -DMA_FROM_DEVICE );mt76_put_page_pool_buf (buf, allow_direct);break ; }
drivers/net/wireless/mediatek/mt76/mac80211.c +8 -0
@@ -567,6 +567,14 @@ int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q) .dev = dev->dma_dev, }; +if (mt76_is_mmio (dev)) { +/* rely on page_pool for DMA mapping */ + pp_params.flags |=PP_FLAG_DMA_MAP |PP_FLAG_DMA_SYNC_DEV ; + pp_params.dma_dir =DMA_FROM_DEVICE ; + pp_params.max_len =PAGE_SIZE ; + pp_params.offset =0 ; + } + q->page_pool =page_pool_create (&pp_params);if (IS_ERR (q->page_pool)) {int err =PTR_ERR (q->page_pool);
drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +3 -2
@@ -604,8 +604,9 @@ static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed)if (!t || !t->ptr)continue ; -dma_unmap_single (dev->mt76.dma_dev, t->dma_addr, - wed->wlan.rx_size,DMA_FROM_DEVICE ); +if (!mt76_is_page_from_pp (t->ptr)) +dma_unmap_single (dev->mt76.dma_dev, t->dma_addr, + wed->wlan.rx_size,DMA_FROM_DEVICE );mt76_put_page_pool_buf (t->ptr, false); t->ptr =NULL ;
Signature · 1 line
2.39.0
Lorenzo Bianconi
maintainerPATCH v2 2/4 wifi: mt76: switch to page_pool allocator
In reply to Lorenzo BianconiIn order to reduce possible memory allocation failures due to memory fragmentation caused by page_frag_cache allocator, switch to page_pool allocator for dma and usb mt76 drivers.
Remove per rx-queue page_frag_cache
--- drivers/net/wireless/mediatek/mt76/Kconfig | 1 + drivers/net/wireless/mediatek/mt76/dma.c | 55 ++++++++++--------- drivers/net/wireless/mediatek/mt76/mac80211.c | 36 ++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 23 +++++++- .../net/wireless/mediatek/mt76/mt7915/mmio.c | 16 ++---- drivers/net/wireless/mediatek/mt76/usb.c | 42 +++++++------- 6 files changed, 112 insertions(+), 61 deletions(-)
drivers/net/wireless/mediatek/mt76/Kconfig +1 -0
@@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config MT76_CORE tristate + select PAGE_POOL config MT76_LEDS bool
drivers/net/wireless/mediatek/mt76/dma.c +29 -26
155 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mac80211.c +36 -0
@@ -4,6 +4,7 @@*/ #include <linux/sched.h> #include <linux/of.h> +#include <net/page_pool.h> #include "mt76.h" #define CHAN2G (_idx, _freq) { \
@@ -556,6 +557,41 @@ void mt76_unregister_phy(struct mt76_phy *phy) }EXPORT_SYMBOL_GPL (mt76_unregister_phy); +int mt76_create_page_pool (struct mt76_dev *dev,struct mt76_queue *q) +{ +struct page_pool_params pp_params = { + .order =0 , + .pool_size =256 , + .flags =PP_FLAG_PAGE_FRAG , + .nid =NUMA_NO_NODE , + .dev = dev->dma_dev, + }; + + q->page_pool =page_pool_create (&pp_params); +if (IS_ERR (q->page_pool)) { +int err =PTR_ERR (q->page_pool); + + q->page_pool =NULL ; +return err; + } + +return 0 ; +} +EXPORT_SYMBOL_GPL (mt76_create_page_pool); + +void mt76_put_page_pool_buf (void *buf,bool allow_direct) +{ +struct page *page =virt_to_head_page (buf); + +if (!mt76_is_page_from_pp (buf)) { +skb_free_frag (buf); +return ; + } + +page_pool_put_full_page (page->pp, page, allow_direct); +} +EXPORT_SYMBOL_GPL (mt76_put_page_pool_buf); +struct mt76_dev * mt76_alloc_device(struct device *pdev, unsigned int size, const struct ieee80211_ops *ops,
drivers/net/wireless/mediatek/mt76/mt76.h +22 -1
@@ -202,7 +202,7 @@ struct mt76_queue {dma_addr_t desc_dma;struct sk_buff *rx_head; -struct page_frag_cache rx_page; +struct page_pool *page_pool; };struct mt76_mcu_ops {
@@ -1402,6 +1402,13 @@ mt76_mcu_skb_send_msg(struct mt76_dev *dev, struct sk_buff *skb, int cmd,return mt76_mcu_skb_send_and_get_msg (dev, skb, cmd, wait_resp,NULL ); } +static inline bool mt76_is_page_from_pp (void *buf) +{ +struct page *page =virt_to_head_page (buf); + +return (page->pp_magic & ~0x3UL ) ==PP_SIGNATURE ; +} +void mt76_set_irq_mask (struct mt76_dev *dev,u32 addr,u32 clear,u32 set); s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
@@ -1422,6 +1429,20 @@ void __mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked);struct mt76_txwi_cache *mt76_rx_token_release (struct mt76_dev *dev,int token);int mt76_rx_token_consume (struct mt76_dev *dev,void *ptr,struct mt76_txwi_cache *r,dma_addr_t phys); +int mt76_create_page_pool (struct mt76_dev *dev,struct mt76_queue *q); +void mt76_put_page_pool_buf (void *buf,bool allow_direct); + +static inline void * +mt76_get_page_pool_buf (struct mt76_queue *q,u32 *offset,u32 size) +{ +struct page *page; + + page =page_pool_dev_alloc_frag (q->page_pool, offset, size); +if (!page) +return NULL ; + +return page_address (page) + *offset; +}static inline void mt76_set_tx_blocked (struct mt76_dev *dev,bool blocked) {
drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +4 -12
@@ -594,13 +594,9 @@ static void mt7915_mmio_wed_offload_disable(struct mtk_wed_device *wed)static void mt7915_mmio_wed_release_rx_buf (struct mtk_wed_device *wed) {struct mt7915_dev *dev; -u32 length;int i; dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - length =SKB_DATA_ALIGN (NET_SKB_PAD + wed->wlan.rx_size + -sizeof (struct skb_shared_info )); -for (i =0 ; i < dev->mt76.rx_token_size; i++) {struct mt76_txwi_cache *t;
@@ -610,7 +606,7 @@ static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed)dma_unmap_single (dev->mt76.dma_dev, t->dma_addr, wed->wlan.rx_size,DMA_FROM_DEVICE ); -__free_pages (virt_to_page (t->ptr),get_order (length)); +mt76_put_page_pool_buf (t->ptr, false); t->ptr =NULL ;mt76_put_rxwi (&dev->mt76, t);
@@ -623,13 +619,9 @@ static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) {struct mtk_rxbm_desc *desc = wed->rx_buf_ring.desc;struct mt7915_dev *dev; -u32 length;int i; dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - length =SKB_DATA_ALIGN (NET_SKB_PAD + wed->wlan.rx_size + -sizeof (struct skb_shared_info )); -for (i =0 ; i < size; i++) {struct mt76_txwi_cache *t =mt76_get_rxwi (&dev->mt76);dma_addr_t phy_addr;
@@ -640,7 +632,7 @@ static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size)if (!t) goto unmap; - page =__dev_alloc_pages (GFP_KERNEL ,get_order (length)); + page =__dev_alloc_page (GFP_KERNEL );if (!page) {mt76_put_rxwi (&dev->mt76, t); goto unmap;
@@ -651,7 +643,7 @@ static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) wed->wlan.rx_size, DMA_TO_DEVICE);if (unlikely (dma_mapping_error (dev->mt76.dev, phy_addr))) { -__free_pages (page,get_order (length)); +__free_page (page);mt76_put_rxwi (&dev->mt76, t); goto unmap; }
@@ -661,7 +653,7 @@ static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size)if (token <0 ) {dma_unmap_single (dev->mt76.dma_dev, phy_addr, wed->wlan.rx_size,DMA_TO_DEVICE ); -__free_pages (page,get_order (length)); +__free_page (page);mt76_put_rxwi (&dev->mt76, t); goto unmap; }
drivers/net/wireless/mediatek/mt76/usb.c +20 -22
120 lines not on this page · raw message
Signature · 1 line
2.39.0
Lorenzo Bianconi
maintainerv2 cover mt76: switch to page_pool allocator
In order to reduce possible memory allocation failures due to memory fragmentation caused by page_frag_cache allocator, switch to page_pool allocator for dma and usb mt76 drivers.
Remove per rx-queue page_frag_cache
Changes since v1:
- rebase on top of mt76 tree
Lorenzo Bianconi (4):
wifi: mt76: mt7915: fix memory leak in mt7915_mmio_wed_init_rx_buf
wifi: mt76: switch to page_pool allocator
wifi: mt76: dma: keep rx pages DMA mapped
wifi: mt76: enable page_pool stats
drivers/net/wireless/mediatek/mt76/Kconfig | 2 + drivers/net/wireless/mediatek/mt76/dma.c | 83 ++++++++++--------- drivers/net/wireless/mediatek/mt76/mac80211.c | 57 +++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 24 +++++- .../net/wireless/mediatek/mt76/mt7915/main.c | 26 +++--- .../net/wireless/mediatek/mt76/mt7915/mmio.c | 30 +++---- .../net/wireless/mediatek/mt76/mt7921/main.c | 31 ++++++- drivers/net/wireless/mediatek/mt76/usb.c | 42 +++++----- 8 files changed, 206 insertions(+), 89 deletions(-)
Signature · 1 line
2.39.0
Lorenzo Bianconi
maintainerPATCH v2 4/4 wifi: mt76: enable page_pool stats
Enable page_pool ethtool statistics for mt7915 and mt7921 chipsets.
--- drivers/net/wireless/mediatek/mt76/Kconfig | 1 + drivers/net/wireless/mediatek/mt76/mac80211.c | 13 ++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 1 + .../net/wireless/mediatek/mt76/mt7915/main.c | 26 ++++++++++------ .../net/wireless/mediatek/mt76/mt7921/main.c | 31 ++++++++++++++++--- 5 files changed, 58 insertions(+), 14 deletions(-)
drivers/net/wireless/mediatek/mt76/Kconfig +1 -0
@@ -2,6 +2,7 @@ config MT76_CORE tristate select PAGE_POOL + select PAGE_POOL_STATS config MT76_LEDS bool
drivers/net/wireless/mediatek/mt76/mac80211.c +13 -0
@@ -1729,6 +1729,19 @@ void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi, }EXPORT_SYMBOL_GPL (mt76_ethtool_worker); +void mt76_ethtool_page_pool_stats (struct mt76_dev *dev,u64 *data,int *index) +{ +struct page_pool_stats stats = {}; +int i; + +mt76_for_each_q_rx (dev, i) +page_pool_get_stats (dev->q_rx[i].page_pool, &stats); + +page_pool_ethtool_stats_get (data, &stats); + *index +=page_pool_ethtool_stats_get_count (); +} +EXPORT_SYMBOL_GPL (mt76_ethtool_page_pool_stats); +enum mt76_dfs_state mt76_phy_dfs_state (struct mt76_phy *phy) {struct ieee80211_hw *hw = phy->hw;
drivers/net/wireless/mediatek/mt76/mt76.h +1 -0
@@ -1311,6 +1311,7 @@ mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int *actual_len,return usb_bulk_msg (udev, pipe, data, len, actual_len, timeout); } +void mt76_ethtool_page_pool_stats (struct mt76_dev *dev,u64 *data,int *index);void mt76_ethtool_worker (struct mt76_ethtool_worker_info *wi,struct mt76_sta_stats *stats);int mt76_skb_adjust_pad (struct sk_buff *skb,int pad);
drivers/net/wireless/mediatek/mt76/mt7915/main.c +16 -10
@@ -1280,19 +1280,22 @@ void mt7915_get_et_strings(struct ieee80211_hw *hw,struct ieee80211_vif *vif, u32 sset, u8 *data) { - if (sset == ETH_SS_STATS) - memcpy(data, *mt7915_gstrings_stats, - sizeof(mt7915_gstrings_stats)); + if (sset != ETH_SS_STATS) + return; + + memcpy(data, *mt7915_gstrings_stats, sizeof(mt7915_gstrings_stats)); + data +=sizeof (mt7915_gstrings_stats); +page_pool_ethtool_stats_get_strings (data); }static int mt7915_get_et_sset_count (struct ieee80211_hw *hw,struct ieee80211_vif *vif,int sset) { -if (sset ==ETH_SS_STATS ) -return MT7915_SSTATS_LEN ; +if (sset !=ETH_SS_STATS ) +return 0 ; -return 0 ; +return MT7915_SSTATS_LEN +page_pool_ethtool_stats_get_count (); }static void mt7915_ethtool_worker (void *wi_data,struct ieee80211_sta *sta)
@@ -1320,7 +1323,7 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw, };struct mib_stats *mib = &phy->mib;/* See mt7915_ampdu_stat_read_phy, etc */ -int i, ei =0 ; +int i, ei =0 , stats_size;mutex_lock (&dev->mt76.mutex);
@@ -1401,9 +1404,12 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw,return ; ei += wi.worker_stat_count; -if (ei !=MT7915_SSTATS_LEN ) -dev_err (dev->mt76.dev,"ei: %d MT7915_SSTATS_LEN: %d" , - ei, (int )MT7915_SSTATS_LEN ); + +mt76_ethtool_page_pool_stats (&dev->mt76, &data[ei], &ei); + + stats_size =MT7915_SSTATS_LEN +page_pool_ethtool_stats_get_count (); +if (ei != stats_size) +dev_err (dev->mt76.dev,"ei: %d size: %d" , ei, stats_size); } static void
drivers/net/wireless/mediatek/mt76/mt7921/main.c +27 -4
@@ -1135,17 +1135,34 @@ static void mt7921_get_et_strings(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 sset, u8 *data) { + struct mt7921_dev *dev = mt7921_hw_dev(hw); +if (sset !=ETH_SS_STATS )return ;memcpy (data, *mt7921_gstrings_stats,sizeof (mt7921_gstrings_stats)); + +if (mt76_is_sdio (&dev->mt76)) +return ; + + data +=sizeof (mt7921_gstrings_stats); +page_pool_ethtool_stats_get_strings (data); }static int mt7921_get_et_sset_count (struct ieee80211_hw *hw,struct ieee80211_vif *vif,int sset) { -return sset ==ETH_SS_STATS ?ARRAY_SIZE (mt7921_gstrings_stats) :0 ; +struct mt7921_dev *dev =mt7921_hw_dev (hw); + +if (sset !=ETH_SS_STATS ) +return 0 ; + +if (mt76_is_sdio (&dev->mt76)) +return ARRAY_SIZE (mt7921_gstrings_stats); + +return ARRAY_SIZE (mt7921_gstrings_stats) + +page_pool_ethtool_stats_get_count (); } static void
@@ -1165,6 +1182,7 @@ void mt7921_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ethtool_stats *stats, u64 *data) { struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; +int stats_size =ARRAY_SIZE (mt7921_gstrings_stats);struct mt7921_phy *phy =mt7921_hw_phy (hw);struct mt7921_dev *dev = phy->dev;struct mib_stats *mib = &phy->mib;
@@ -1220,9 +1238,14 @@ void mt7921_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif,return ; ei += wi.worker_stat_count; -if (ei !=ARRAY_SIZE (mt7921_gstrings_stats)) -dev_err (dev->mt76.dev,"ei: %d SSTATS_LEN: %zu" , - ei,ARRAY_SIZE (mt7921_gstrings_stats)); + +if (!mt76_is_sdio (&dev->mt76)) { +mt76_ethtool_page_pool_stats (&dev->mt76, &data[ei], &ei); + stats_size +=page_pool_ethtool_stats_get_count (); + } + +if (ei != stats_size) +dev_err (dev->mt76.dev,"ei: %d SSTATS_LEN: %d" , ei, stats_size); } static u64
Signature · 1 line
2.39.0
Lorenzo Bianconi
maintainerPATCH v2 1/4 wifi: mt76: mt7915: fix memory leak in mt7915_mmio_wed_init_rx_buf
In reply to Lorenzo BianconiFree mt76_txwi_cache pointer in mt7915_mmio_wed_init_rx_buf routine in case of failure.
--- drivers/net/wireless/mediatek/mt76/mt7915/mmio.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +8 -1
@@ -637,9 +637,14 @@ static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size)int token;void *ptr; +if (!t) + goto unmap; + page =__dev_alloc_pages (GFP_KERNEL ,get_order (length)); -if (!page) +if (!page) { +mt76_put_rxwi (&dev->mt76, t); goto unmap; + } ptr =page_address (page); phy_addr = dma_map_single(dev->mt76.dma_dev, ptr,
@@ -647,6 +652,7 @@ static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) DMA_TO_DEVICE);if (unlikely (dma_mapping_error (dev->mt76.dev, phy_addr))) {__free_pages (page,get_order (length)); +mt76_put_rxwi (&dev->mt76, t); goto unmap; }
@@ -656,6 +662,7 @@ static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size)dma_unmap_single (dev->mt76.dma_dev, phy_addr, wed->wlan.rx_size,DMA_TO_DEVICE );__free_pages (page,get_order (length)); +mt76_put_rxwi (&dev->mt76, t); goto unmap; }
Signature · 1 line
2.39.0