diff options
author | Felix Fietkau | 2018-07-13 16:26:15 +0200 |
---|---|---|
committer | Felix Fietkau | 2018-09-19 12:31:44 +0200 |
commit | c12128ce44b04a987c4eb0f733cc99c4dd50d45a (patch) | |
tree | 84bd4a01b7571716251cdf573ee7d8bb66dcd318 /drivers/net/wireless/mediatek/mt76/usb.c | |
parent | mt76x2: move mt76x2_phy_tssi_compensate in mt76x2-common module (diff) | |
download | kernel-qcow2-linux-c12128ce44b04a987c4eb0f733cc99c4dd50d45a.tar.gz kernel-qcow2-linux-c12128ce44b04a987c4eb0f733cc99c4dd50d45a.tar.xz kernel-qcow2-linux-c12128ce44b04a987c4eb0f733cc99c4dd50d45a.zip |
mt76: use a per rx queue page fragment cache
Using the NAPI or netdev frag cache along with other drivers can lead to
32 KiB pages being held for a long time, despite only being used for
very few page fragments.
This can happen if the driver grabs one or two fragments for rx ring
refill, while other drivers use (and free up) the remaining fragments.
The 32 KiB higher-order page can only be freed once all users have freed
their fragments.
Depending on the traffic patterns, this can waste a lot of memory and
look a lot like a memory leak.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/usb.c')
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/usb.c | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 16a9682d5452..be43e2941dc4 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -275,6 +275,7 @@ static int mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf, int nsgs, int len, int sglen) { + struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; struct urb *urb = buf->urb; int i; @@ -283,7 +284,7 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf, void *data; int offset; - data = netdev_alloc_frag(len); + data = page_frag_alloc(&q->rx_page, q->buf_size, GFP_ATOMIC); if (!data) break; @@ -550,10 +551,18 @@ static int mt76u_alloc_rx(struct mt76_dev *dev) static void mt76u_free_rx(struct mt76_dev *dev) { struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; + struct page *page; int i; for (i = 0; i < q->ndesc; i++) mt76u_buf_free(&q->entry[i].ubuf); + + if (!q->rx_page.va) + return; + + page = virt_to_page(q->rx_page.va); + __page_frag_cache_drain(page, q->rx_page.pagecnt_bias); + memset(&q->rx_page, 0, sizeof(q->rx_page)); } static void mt76u_stop_rx(struct mt76_dev *dev) |