diff --git a/dma.c b/dma.c index abbd2b9f..a4758f12 100644 --- a/dma.c +++ b/dma.c @@ -247,6 +247,78 @@ mt76_dma_init(struct mt76_dev *dev) return 0; } +static void +mt76_add_fragment(struct mt76_dev *dev, struct mt76_queue *q, void *data, + int len, bool more) +{ + struct page *page = virt_to_head_page(data); + int offset = data - page_address(page); + struct sk_buff *skb = q->rx_head; + + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, offset, len, + q->buf_size); + + if (more) + return; + + q->rx_head = NULL; + dev->drv->rx_skb(dev, q, skb); +} + +static int +mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) +{ + struct sk_buff *skb; + unsigned char *data; + int len; + int done = 0; + bool napi = q == &dev->q_rx[MT_RXQ_MAIN]; + bool more; + + while (done < budget) { + u32 info; + + data = mt76_dma_dequeue(dev, q, false, &len, &info, &more); + if (!data) + break; + + if (q->rx_head) { + mt76_add_fragment(dev, q, data, len, more); + continue; + } + + skb = build_skb(data, q->buf_size); + if (!skb) { + skb_free_frag(data); + continue; + } + + skb_reserve(skb, q->buf_offset); + if (skb->tail + len > skb->end) { + dev_kfree_skb(skb); + continue; + } + + if (q == &dev->q_rx[MT_RXQ_MCU]) { + u32 * rxfce = (u32 *) skb->cb; + *rxfce = info; + } + + __skb_put(skb, len); + done++; + + if (more) { + q->rx_head = skb; + continue; + } + + dev->drv->rx_skb(dev, q, skb); + } + + mt76_dma_rx_fill(dev, q, napi); + return done; +} + static const struct mt76_queue_ops mt76_dma_ops = { .init = mt76_dma_init, .alloc = mt76_dma_alloc_queue, @@ -255,6 +327,7 @@ static const struct mt76_queue_ops mt76_dma_ops = { .dequeue = mt76_dma_dequeue, .tx_cleanup = mt76_dma_tx_cleanup, .kick = mt76_dma_kick_queue, + .rx_process = mt76_dma_rx_process, }; int mt76_dma_attach(struct mt76_dev *dev) diff --git a/mt76.h b/mt76.h index bcadadb8..b79cd7a8 100644 --- a/mt76.h +++ b/mt76.h @@ -107,6 +107,8 @@ struct mt76_queue_ops { int (*rx_fill)(struct mt76_dev *dev, struct mt76_queue *q, bool napi); + int (*rx_process)(struct mt76_dev *dev, struct mt76_queue *q, int budget); + void (*kick)(struct mt76_dev *dev, struct mt76_queue *q); }; @@ -156,6 +158,9 @@ struct mt76_driver_ops { int (*tx_queue_skb)(struct mt76_dev *dev, struct mt76_queue *q, struct sk_buff *skb, struct mt76_txwi_cache *txwi, struct mt76_wcid *wcid, struct ieee80211_sta *sta); + + void (*rx_skb)(struct mt76_dev *mdev, struct mt76_queue *q, + struct sk_buff *skb); }; struct mt76_dev { @@ -233,6 +238,7 @@ static inline u16 mt76_rev(struct mt76_dev *dev) #define mt76_queue_dequeue(dev, ...) (dev)->mt76.queue_ops->dequeue(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_rx_fill(dev, ...) (dev)->mt76.queue_ops->rx_fill(&((dev)->mt76), __VA_ARGS__) +#define mt76_queue_rx_process(dev, ...) (dev)->mt76.queue_ops->rx_process(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_kick(dev, ...) (dev)->mt76.queue_ops->kick(&((dev)->mt76), __VA_ARGS__) int mt76_register_device(struct mt76_dev *dev, bool vht, diff --git a/mt76x2.h b/mt76x2.h index 8c55602d..8cd65a57 100644 --- a/mt76x2.h +++ b/mt76x2.h @@ -227,4 +227,7 @@ void mt76x2_pre_tbtt_tasklet(unsigned long data); void mt76x2_txq_init(struct mt76x2_dev *dev, struct ieee80211_txq *txq); +void mt76x2_queue_rx_skb(struct mt76_dev *mdev, struct mt76_queue *q, + struct sk_buff *skb); + #endif diff --git a/mt76x2_dma.c b/mt76x2_dma.c index b0150af5..ee969fde 100644 --- a/mt76x2_dma.c +++ b/mt76x2_dma.c @@ -122,13 +122,13 @@ mt76x2_init_tx_queue(struct mt76x2_dev *dev, struct mt76_queue *q, return 0; } -static void -mt76x2_process_rx_skb(struct mt76x2_dev *dev, struct mt76_queue *q, - struct sk_buff *skb) +void mt76x2_queue_rx_skb(struct mt76_dev *mdev, struct mt76_queue *q, + struct sk_buff *skb) { + struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); void *rxwi = skb->data; - if (q == &dev->mt76.q_rx[MT_RXQ_MCU]) { + if (q == &mdev->q_rx[MT_RXQ_MCU]) { skb_queue_tail(&dev->mcu.res_q, skb); wake_up(&dev->mcu.wait); return; @@ -143,77 +143,6 @@ mt76x2_process_rx_skb(struct mt76x2_dev *dev, struct mt76_queue *q, mt76x2_rx(dev, skb); } -static void -mt76x2_add_fragment(struct mt76x2_dev *dev, struct mt76_queue *q, void *data, - int len, bool more) -{ - struct page *page = virt_to_head_page(data); - int offset = data - page_address(page); - struct sk_buff *skb = q->rx_head; - - skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, offset, len, - q->buf_size); - - if (!more) { - q->rx_head = NULL; - mt76x2_process_rx_skb(dev, q, skb); - } -} - -static int -mt76x2_process_rx_queue(struct mt76x2_dev *dev, struct mt76_queue *q, int budget) -{ - struct sk_buff *skb; - unsigned char *data; - int len; - int done = 0; - bool napi = q == &dev->mt76.q_rx[MT_RXQ_MAIN]; - bool more; - - while (done < budget) { - u32 info; - - data = mt76_queue_dequeue(dev, q, false, &len, &info, &more); - if (!data) - break; - - if (q->rx_head) { - mt76x2_add_fragment(dev, q, data, len, more); - continue; - } - - skb = build_skb(data, q->buf_size); - if (!skb) { - skb_free_frag(data); - continue; - } - - skb_reserve(skb, q->buf_offset); - if (skb->tail + len > skb->end) { - dev_kfree_skb(skb); - continue; - } - - if (q == &dev->mt76.q_rx[MT_RXQ_MCU]) { - u32 * rxfce = (u32 *) skb->cb; - *rxfce = info; - } - - __skb_put(skb, len); - done++; - - if (more) { - q->rx_head = skb; - continue; - } - - mt76x2_process_rx_skb(dev, q, skb); - } - - mt76_queue_rx_fill(dev, q, napi); - return done; -} - static int mt76x2_init_rx_queue(struct mt76x2_dev *dev, struct mt76_queue *q, int idx, int n_desc, int bufsize) @@ -254,7 +183,7 @@ mt76x2_dma_rx_poll(struct napi_struct *napi, int budget) struct mt76x2_dev *dev = container_of(napi, struct mt76x2_dev, napi); int done; - done = mt76x2_process_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], budget); + done = mt76_queue_rx_process(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], budget); if (done < budget) { napi_complete(napi); @@ -270,7 +199,7 @@ mt76x2_rx_tasklet(unsigned long data) struct mt76x2_dev *dev = (struct mt76x2_dev *) data; struct mt76_queue *q = &dev->mt76.q_rx[MT_RXQ_MCU]; - mt76x2_process_rx_queue(dev, q, q->ndesc); + mt76_queue_rx_process(dev, q, q->ndesc); mt76x2_irq_enable(dev, MT_INT_RX_DONE(1)); } diff --git a/mt76x2_init.c b/mt76x2_init.c index 179d0af5..b160e4e9 100644 --- a/mt76x2_init.c +++ b/mt76x2_init.c @@ -590,7 +590,8 @@ struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev) { static const struct mt76_driver_ops drv_ops = { .fill_txwi = mt76x2_mac_write_txwi, - .tx_queue_skb = mt76x2_tx_queue_skb + .tx_queue_skb = mt76x2_tx_queue_skb, + .rx_skb = mt76x2_queue_rx_skb, }; struct ieee80211_hw *hw; struct mt76x2_dev *dev;