diff options
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/usb.c')
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/usb.c | 119 |
1 files changed, 80 insertions, 39 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 79e59f2379a2..5f0faf07c346 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/module.h> #include "mt76.h" #include "usb_trace.h" #include "dma.h" @@ -109,6 +110,7 @@ u32 mt76u_rr(struct mt76_dev *dev, u32 addr) return ret; } +EXPORT_SYMBOL_GPL(mt76u_rr); /* should be called with usb_ctrl_mtx locked */ static void __mt76u_wr(struct mt76_dev *dev, u32 addr, u32 val) @@ -140,6 +142,7 @@ void mt76u_wr(struct mt76_dev *dev, u32 addr, u32 val) __mt76u_wr(dev, addr, val); mutex_unlock(&dev->usb.usb_ctrl_mtx); } +EXPORT_SYMBOL_GPL(mt76u_wr); static u32 mt76u_rmw(struct mt76_dev *dev, u32 addr, u32 mask, u32 val) @@ -187,6 +190,60 @@ void mt76u_single_wr(struct mt76_dev *dev, const u8 req, EXPORT_SYMBOL_GPL(mt76u_single_wr); static int +mt76u_req_wr_rp(struct mt76_dev *dev, u32 base, + const struct mt76_reg_pair *data, int len) +{ + struct mt76_usb *usb = &dev->usb; + + mutex_lock(&usb->usb_ctrl_mtx); + while (len > 0) { + __mt76u_wr(dev, base + data->reg, data->value); + len--; + data++; + } + mutex_unlock(&usb->usb_ctrl_mtx); + + return 0; +} + +static int +mt76u_wr_rp(struct mt76_dev *dev, u32 base, + const struct mt76_reg_pair *data, int n) +{ + if (test_bit(MT76_STATE_MCU_RUNNING, &dev->state)) + return dev->mcu_ops->mcu_wr_rp(dev, base, data, n); + else + return mt76u_req_wr_rp(dev, base, data, n); +} + +static int +mt76u_req_rd_rp(struct mt76_dev *dev, u32 base, struct mt76_reg_pair *data, + int len) +{ + struct mt76_usb *usb = &dev->usb; + + mutex_lock(&usb->usb_ctrl_mtx); + while (len > 0) { + data->value = __mt76u_rr(dev, base + data->reg); + len--; + data++; + } + mutex_unlock(&usb->usb_ctrl_mtx); + + return 0; +} + +static int +mt76u_rd_rp(struct mt76_dev *dev, u32 base, + struct mt76_reg_pair *data, int n) +{ + if (test_bit(MT76_STATE_MCU_RUNNING, &dev->state)) + return dev->mcu_ops->mcu_rd_rp(dev, base, data, n); + else + return mt76u_req_rd_rp(dev, base, data, n); +} + +static int mt76u_set_endpoints(struct usb_interface *intf, struct mt76_usb *usb) { @@ -219,15 +276,17 @@ 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; + spin_lock_bh(&q->rx_page_lock); for (i = 0; i < nsgs; i++) { struct page *page; void *data; int offset; - data = netdev_alloc_frag(len); + data = page_frag_alloc(&q->rx_page, len, GFP_ATOMIC); if (!data) break; @@ -235,6 +294,7 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf, offset = data - page_address(page); sg_set_page(&urb->sg[i], page, sglen, offset); } + spin_unlock_bh(&q->rx_page_lock); if (i < nsgs) { int j; @@ -326,9 +386,9 @@ static int mt76u_get_rx_entry_len(u8 *data, u32 data_len) min_len = MT_DMA_HDR_LEN + MT_RX_RXWI_LEN + MT_FCE_INFO_LEN; - if (data_len < min_len || WARN_ON(!dma_len) || - WARN_ON(dma_len + MT_DMA_HDR_LEN > data_len) || - WARN_ON(dma_len & 0x3)) + if (data_len < min_len || !dma_len || + dma_len + MT_DMA_HDR_LEN > data_len || + (dma_len & 0x3)) return -EINVAL; return dma_len; } @@ -463,6 +523,7 @@ static int mt76u_alloc_rx(struct mt76_dev *dev) struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; int i, err, nsgs; + spin_lock_init(&q->rx_page_lock); spin_lock_init(&q->lock); q->entry = devm_kcalloc(dev->dev, MT_NUM_RX_ENTRIES, sizeof(*q->entry), @@ -494,10 +555,21 @@ 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); + + spin_lock_bh(&q->rx_page_lock); + if (!q->rx_page.va) + goto out; + + 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)); +out: + spin_unlock_bh(&q->rx_page_lock); } static void mt76u_stop_rx(struct mt76_dev *dev) @@ -509,40 +581,6 @@ static void mt76u_stop_rx(struct mt76_dev *dev) usb_kill_urb(q->entry[i].ubuf.urb); } -int mt76u_skb_dma_info(struct sk_buff *skb, int port, u32 flags) -{ - struct sk_buff *iter, *last = skb; - u32 info, pad; - - /* Buffer layout: - * | 4B | xfer len | pad | 4B | - * | TXINFO | pkt/cmd | zero pad to 4B | zero | - * - * length field of TXINFO should be set to 'xfer len'. - */ - info = FIELD_PREP(MT_TXD_INFO_LEN, round_up(skb->len, 4)) | - FIELD_PREP(MT_TXD_INFO_DPORT, port) | flags; - put_unaligned_le32(info, skb_push(skb, sizeof(info))); - - pad = round_up(skb->len, 4) + 4 - skb->len; - skb_walk_frags(skb, iter) { - last = iter; - if (!iter->next) { - skb->data_len += pad; - skb->len += pad; - break; - } - } - - if (unlikely(pad)) { - if (__skb_pad(last, pad, true)) - return -ENOMEM; - __skb_put(last, pad); - } - return 0; -} -EXPORT_SYMBOL_GPL(mt76u_skb_dma_info); - static void mt76u_tx_tasklet(unsigned long data) { struct mt76_dev *dev = (struct mt76_dev *)data; @@ -715,7 +753,7 @@ static int mt76u_alloc_tx(struct mt76_dev *dev) q = &dev->q_tx[i]; spin_lock_init(&q->lock); INIT_LIST_HEAD(&q->swq); - q->hw_idx = q2hwq(i); + q->hw_idx = mt76_ac_to_hwq(i); q->entry = devm_kcalloc(dev->dev, MT_NUM_TX_ENTRIES, sizeof(*q->entry), @@ -822,6 +860,9 @@ int mt76u_init(struct mt76_dev *dev, .wr = mt76u_wr, .rmw = mt76u_rmw, .copy = mt76u_copy, + .wr_rp = mt76u_wr_rp, + .rd_rp = mt76u_rd_rp, + .type = MT76_BUS_USB, }; struct mt76_usb *usb = &dev->usb; |