Commit e99a2d6b authored by Kalle Valo's avatar Kalle Valo
Browse files

Merge tag 'mt76-for-kvalo-2022-05-12' of https://github.com/nbd168/wireless

mt76 patches for 5.19

- tx locking improvements
- wireless ethernet dispatch support for flow offload
- non-standard VHT MCS10-11 support
- fixes
- runtime PM improvements
- mt7921 AP mode support
- mt7921 ipv6 NS offload support
parents 569cf386 5fc201aa
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -162,15 +162,15 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames)
	if (!sta)
		return;

	if (!status->aggr && !(status->flag & RX_FLAG_8023)) {
	if (!status->aggr) {
		if (!(status->flag & RX_FLAG_8023))
			mt76_rx_aggr_check_ctl(skb, frames);
		return;
	}

	/* not part of a BA session */
	ackp = status->qos_ctl & IEEE80211_QOS_CTL_ACK_POLICY_MASK;
	if (ackp != IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK &&
	    ackp != IEEE80211_QOS_CTL_ACK_POLICY_NORMAL)
	if (ackp == IEEE80211_QOS_CTL_ACK_POLICY_NOACK)
		return;

	tid = rcu_dereference(wcid->aggr[tidno]);
+157 −58
Original line number Diff line number Diff line
@@ -7,6 +7,37 @@
#include "mt76.h"
#include "dma.h"

#if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)

#define Q_READ(_dev, _q, _field) ({					\
	u32 _offset = offsetof(struct mt76_queue_regs, _field);		\
	u32 _val;							\
	if ((_q)->flags & MT_QFLAG_WED)					\
		_val = mtk_wed_device_reg_read(&(_dev)->mmio.wed,	\
					       ((_q)->wed_regs +	\
					        _offset));		\
	else								\
		_val = readl(&(_q)->regs->_field);			\
	_val;								\
})

#define Q_WRITE(_dev, _q, _field, _val)	do {				\
	u32 _offset = offsetof(struct mt76_queue_regs, _field);		\
	if ((_q)->flags & MT_QFLAG_WED)					\
		mtk_wed_device_reg_write(&(_dev)->mmio.wed,		\
					 ((_q)->wed_regs + _offset),	\
					 _val);				\
	else								\
		writel(_val, &(_q)->regs->_field);			\
} while (0)

#else

#define Q_READ(_dev, _q, _field)	readl(&(_q)->regs->_field)
#define Q_WRITE(_dev, _q, _field, _val)	writel(_val, &(_q)->regs->_field)

#endif

static struct mt76_txwi_cache *
mt76_alloc_txwi(struct mt76_dev *dev)
{
@@ -16,11 +47,11 @@ mt76_alloc_txwi(struct mt76_dev *dev)
	int size;

	size = L1_CACHE_ALIGN(dev->drv->txwi_size + sizeof(*t));
	txwi = devm_kzalloc(dev->dev, size, GFP_ATOMIC);
	txwi = kzalloc(size, GFP_ATOMIC);
	if (!txwi)
		return NULL;

	addr = dma_map_single(dev->dev, txwi, dev->drv->txwi_size,
	addr = dma_map_single(dev->dma_dev, txwi, dev->drv->txwi_size,
			      DMA_TO_DEVICE);
	t = (struct mt76_txwi_cache *)(txwi + dev->drv->txwi_size);
	t->dma_addr = addr;
@@ -73,18 +104,20 @@ mt76_free_pending_txwi(struct mt76_dev *dev)
	struct mt76_txwi_cache *t;

	local_bh_disable();
	while ((t = __mt76_get_txwi(dev)) != NULL)
		dma_unmap_single(dev->dev, t->dma_addr, dev->drv->txwi_size,
	while ((t = __mt76_get_txwi(dev)) != NULL) {
		dma_unmap_single(dev->dma_dev, t->dma_addr, dev->drv->txwi_size,
				 DMA_TO_DEVICE);
		kfree(mt76_get_txwi_ptr(dev, t));
	}
	local_bh_enable();
}

static void
mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q)
{
	writel(q->desc_dma, &q->regs->desc_base);
	writel(q->ndesc, &q->regs->ring_size);
	q->head = readl(&q->regs->dma_idx);
	Q_WRITE(dev, q, desc_base, q->desc_dma);
	Q_WRITE(dev, q, ring_size, q->ndesc);
	q->head = Q_READ(dev, q, dma_idx);
	q->tail = q->head;
}

@@ -100,41 +133,11 @@ mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q)
	for (i = 0; i < q->ndesc; i++)
		q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE);

	writel(0, &q->regs->cpu_idx);
	writel(0, &q->regs->dma_idx);
	Q_WRITE(dev, q, cpu_idx, 0);
	Q_WRITE(dev, q, dma_idx, 0);
	mt76_dma_sync_idx(dev, q);
}

static int
mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
		     int idx, int n_desc, int bufsize,
		     u32 ring_base)
{
	int size;

	spin_lock_init(&q->lock);
	spin_lock_init(&q->cleanup_lock);

	q->regs = dev->mmio.regs + ring_base + idx * MT_RING_SIZE;
	q->ndesc = n_desc;
	q->buf_size = bufsize;
	q->hw_idx = idx;

	size = q->ndesc * sizeof(struct mt76_desc);
	q->desc = dmam_alloc_coherent(dev->dev, size, &q->desc_dma, GFP_KERNEL);
	if (!q->desc)
		return -ENOMEM;

	size = q->ndesc * sizeof(*q->entry);
	q->entry = devm_kzalloc(dev->dev, size, GFP_KERNEL);
	if (!q->entry)
		return -ENOMEM;

	mt76_dma_queue_reset(dev, q);

	return 0;
}

static int
mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
		 struct mt76_queue_buf *buf, int nbufs, u32 info,
@@ -203,11 +206,11 @@ mt76_dma_tx_cleanup_idx(struct mt76_dev *dev, struct mt76_queue *q, int idx,
	struct mt76_queue_entry *e = &q->entry[idx];

	if (!e->skip_buf0)
		dma_unmap_single(dev->dev, e->dma_addr[0], e->dma_len[0],
		dma_unmap_single(dev->dma_dev, e->dma_addr[0], e->dma_len[0],
				 DMA_TO_DEVICE);

	if (!e->skip_buf1)
		dma_unmap_single(dev->dev, e->dma_addr[1], e->dma_len[1],
		dma_unmap_single(dev->dma_dev, e->dma_addr[1], e->dma_len[1],
				 DMA_TO_DEVICE);

	if (e->txwi == DMA_DUMMY_DATA)
@@ -224,7 +227,7 @@ static void
mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q)
{
	wmb();
	writel(q->head, &q->regs->cpu_idx);
	Q_WRITE(dev, q, cpu_idx, q->head);
}

static void
@@ -240,7 +243,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush)
	if (flush)
		last = -1;
	else
		last = readl(&q->regs->dma_idx);
		last = Q_READ(dev, q, dma_idx);

	while (q->queued > 0 && q->tail != last) {
		mt76_dma_tx_cleanup_idx(dev, q, q->tail, &entry);
@@ -252,8 +255,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush)
		}

		if (!flush && q->tail == last)
			last = readl(&q->regs->dma_idx);

			last = Q_READ(dev, q, dma_idx);
	}
	spin_unlock_bh(&q->cleanup_lock);

@@ -288,7 +290,7 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
	if (info)
		*info = le32_to_cpu(desc->info);

	dma_unmap_single(dev->dev, buf_addr, buf_len, DMA_FROM_DEVICE);
	dma_unmap_single(dev->dma_dev, buf_addr, buf_len, DMA_FROM_DEVICE);
	e->buf = NULL;

	return buf;
@@ -325,9 +327,9 @@ mt76_dma_tx_queue_skb_raw(struct mt76_dev *dev, struct mt76_queue *q,
	if (q->queued + 1 >= q->ndesc - 1)
		goto error;

	addr = dma_map_single(dev->dev, skb->data, skb->len,
	addr = dma_map_single(dev->dma_dev, skb->data, skb->len,
			      DMA_TO_DEVICE);
	if (unlikely(dma_mapping_error(dev->dev, addr)))
	if (unlikely(dma_mapping_error(dev->dma_dev, addr)))
		goto error;

	buf.addr = addr;
@@ -374,8 +376,8 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
		mt76_insert_hdr_pad(skb);

	len = skb_headlen(skb);
	addr = dma_map_single(dev->dev, skb->data, len, DMA_TO_DEVICE);
	if (unlikely(dma_mapping_error(dev->dev, addr)))
	addr = dma_map_single(dev->dma_dev, skb->data, len, DMA_TO_DEVICE);
	if (unlikely(dma_mapping_error(dev->dma_dev, addr)))
		goto free;

	tx_info.buf[n].addr = t->dma_addr;
@@ -387,9 +389,9 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
		if (n == ARRAY_SIZE(tx_info.buf))
			goto unmap;

		addr = dma_map_single(dev->dev, iter->data, iter->len,
		addr = dma_map_single(dev->dma_dev, iter->data, iter->len,
				      DMA_TO_DEVICE);
		if (unlikely(dma_mapping_error(dev->dev, addr)))
		if (unlikely(dma_mapping_error(dev->dma_dev, addr)))
			goto unmap;

		tx_info.buf[n].addr = addr;
@@ -402,10 +404,10 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
		goto unmap;
	}

	dma_sync_single_for_cpu(dev->dev, t->dma_addr, dev->drv->txwi_size,
	dma_sync_single_for_cpu(dev->dma_dev, t->dma_addr, dev->drv->txwi_size,
				DMA_TO_DEVICE);
	ret = dev->drv->tx_prepare_skb(dev, txwi, q->qid, wcid, sta, &tx_info);
	dma_sync_single_for_device(dev->dev, t->dma_addr, dev->drv->txwi_size,
	dma_sync_single_for_device(dev->dma_dev, t->dma_addr, dev->drv->txwi_size,
				   DMA_TO_DEVICE);
	if (ret < 0)
		goto unmap;
@@ -415,7 +417,7 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,

unmap:
	for (n--; n > 0; n--)
		dma_unmap_single(dev->dev, tx_info.buf[n].addr,
		dma_unmap_single(dev->dma_dev, tx_info.buf[n].addr,
				 tx_info.buf[n].len, DMA_TO_DEVICE);

free:
@@ -460,8 +462,8 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q)
		if (!buf)
			break;

		addr = dma_map_single(dev->dev, buf, len, DMA_FROM_DEVICE);
		if (unlikely(dma_mapping_error(dev->dev, addr))) {
		addr = dma_map_single(dev->dma_dev, buf, len, DMA_FROM_DEVICE);
		if (unlikely(dma_mapping_error(dev->dma_dev, addr))) {
			skb_free_frag(buf);
			break;
		}
@@ -481,6 +483,85 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q)
	return frames;
}

static int
mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q)
{
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
	struct mtk_wed_device *wed = &dev->mmio.wed;
	int ret, type, ring;
	u8 flags = q->flags;

	if (!mtk_wed_device_active(wed))
		q->flags &= ~MT_QFLAG_WED;

	if (!(q->flags & MT_QFLAG_WED))
		return 0;

	type = FIELD_GET(MT_QFLAG_WED_TYPE, q->flags);
	ring = FIELD_GET(MT_QFLAG_WED_RING, q->flags);

	switch (type) {
	case MT76_WED_Q_TX:
		ret = mtk_wed_device_tx_ring_setup(wed, ring, q->regs);
		if (!ret)
			q->wed_regs = wed->tx_ring[ring].reg_base;
		break;
	case MT76_WED_Q_TXFREE:
		/* WED txfree queue needs ring to be initialized before setup */
		q->flags = 0;
		mt76_dma_queue_reset(dev, q);
		mt76_dma_rx_fill(dev, q);
		q->flags = flags;

		ret = mtk_wed_device_txfree_ring_setup(wed, q->regs);
		if (!ret)
			q->wed_regs = wed->txfree_ring.reg_base;
		break;
	default:
		ret = -EINVAL;
	}

	return ret;
#else
	return 0;
#endif
}

static int
mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
		     int idx, int n_desc, int bufsize,
		     u32 ring_base)
{
	int ret, size;

	spin_lock_init(&q->lock);
	spin_lock_init(&q->cleanup_lock);

	q->regs = dev->mmio.regs + ring_base + idx * MT_RING_SIZE;
	q->ndesc = n_desc;
	q->buf_size = bufsize;
	q->hw_idx = idx;

	size = q->ndesc * sizeof(struct mt76_desc);
	q->desc = dmam_alloc_coherent(dev->dma_dev, size, &q->desc_dma, GFP_KERNEL);
	if (!q->desc)
		return -ENOMEM;

	size = q->ndesc * sizeof(*q->entry);
	q->entry = devm_kzalloc(dev->dev, size, GFP_KERNEL);
	if (!q->entry)
		return -ENOMEM;

	ret = mt76_dma_wed_setup(dev, q);
	if (ret)
		return ret;

	if (q->flags != MT_WED_Q_TXFREE)
		mt76_dma_queue_reset(dev, q);

	return 0;
}

static void
mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
{
@@ -562,14 +643,29 @@ mt76_add_fragment(struct mt76_dev *dev, struct mt76_queue *q, void *data,
static int
mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
{
	int len, data_len, done = 0;
	int len, data_len, done = 0, dma_idx;
	struct sk_buff *skb;
	unsigned char *data;
	bool check_ddone = false;
	bool more;

	if (IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) &&
	    q->flags == MT_WED_Q_TXFREE) {
		dma_idx = Q_READ(dev, q, dma_idx);
		check_ddone = true;
	}

	while (done < budget) {
		u32 info;

		if (check_ddone) {
			if (q->tail == dma_idx)
				dma_idx = Q_READ(dev, q, dma_idx);

			if (q->tail == dma_idx)
				break;
		}

		data = mt76_dma_dequeue(dev, q, false, &len, &info, &more);
		if (!data)
			break;
@@ -710,5 +806,8 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
	}

	mt76_free_pending_txwi(dev);

	if (mtk_wed_device_active(&dev->mmio.wed))
		mtk_wed_device_detach(&dev->mmio.wed);
}
EXPORT_SYMBOL_GPL(mt76_dma_cleanup);
+10 −4
Original line number Diff line number Diff line
@@ -248,6 +248,8 @@ static void mt76_init_stream_cap(struct mt76_phy *phy,
		vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
	else
		vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC;
	vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN;

	for (i = 0; i < 8; i++) {
		if (i < nstream)
@@ -323,8 +325,6 @@ mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband,
	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
			IEEE80211_VHT_CAP_RXSTBC_1 |
			IEEE80211_VHT_CAP_SHORT_GI_80 |
			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
			IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
			(3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);

	return 0;
@@ -545,6 +545,7 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
	dev->hw = hw;
	dev->dev = pdev;
	dev->drv = drv_ops;
	dev->dma_dev = pdev;

	phy = &dev->phy;
	phy->dev = dev;
@@ -579,6 +580,7 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
	INIT_LIST_HEAD(&dev->wcid_list);

	INIT_LIST_HEAD(&dev->txwi_cache);
	dev->token_size = dev->drv->token_size;

	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
		skb_queue_head_init(&dev->rx_skb[i]);
@@ -1303,7 +1305,7 @@ mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
			continue;

		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
		mtxq->wcid = wcid;
		mtxq->wcid = wcid->idx;
	}

	ewma_signal_init(&wcid->rssi);
@@ -1381,7 +1383,9 @@ void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;

	mutex_lock(&dev->mutex);
	spin_lock_bh(&dev->status_lock);
	rcu_assign_pointer(dev->wcid[wcid->idx], NULL);
	spin_unlock_bh(&dev->status_lock);
	mutex_unlock(&dev->mutex);
}
EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove);
@@ -1578,7 +1582,7 @@ EXPORT_SYMBOL_GPL(mt76_get_antenna);

struct mt76_queue *
mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
		int ring_base)
		int ring_base, u32 flags)
{
	struct mt76_queue *hwq;
	int err;
@@ -1587,6 +1591,8 @@ mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
	if (!hwq)
		return ERR_PTR(-ENOMEM);

	hwq->flags = flags;

	err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base);
	if (err < 0)
		return ERR_PTR(err);
+4 −4
Original line number Diff line number Diff line
@@ -6,14 +6,14 @@
#include "mt76.h"

struct sk_buff *
mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data,
		   int data_len)
__mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data,
		     int data_len, gfp_t gfp)
{
	const struct mt76_mcu_ops *ops = dev->mcu_ops;
	int length = ops->headroom + data_len + ops->tailroom;
	struct sk_buff *skb;

	skb = alloc_skb(length, GFP_KERNEL);
	skb = alloc_skb(length, gfp);
	if (!skb)
		return NULL;

@@ -25,7 +25,7 @@ mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data,

	return skb;
}
EXPORT_SYMBOL_GPL(mt76_mcu_msg_alloc);
EXPORT_SYMBOL_GPL(__mt76_mcu_msg_alloc);

struct sk_buff *mt76_mcu_get_response(struct mt76_dev *dev,
				      unsigned long expires)
+7 −2
Original line number Diff line number Diff line
@@ -73,8 +73,13 @@ void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr,
	spin_lock_irqsave(&dev->mmio.irq_lock, flags);
	dev->mmio.irqmask &= ~clear;
	dev->mmio.irqmask |= set;
	if (addr)
	if (addr) {
		if (mtk_wed_device_active(&dev->mmio.wed))
			mtk_wed_device_irq_set_mask(&dev->mmio.wed,
						    dev->mmio.irqmask);
		else
			mt76_mmio_wr(dev, addr, dev->mmio.irqmask);
	}
	spin_unlock_irqrestore(&dev->mmio.irq_lock, flags);
}
EXPORT_SYMBOL_GPL(mt76_set_irq_mask);
Loading