Linux Audio

Check our new training course

Yocto / OpenEmbedded training

Mar 24-27, 2025, special US time zones
Register
Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: ISC
  2
  3#include "mt7603.h"
  4#include "mac.h"
  5#include "../dma.h"
  6
  7static int
  8mt7603_init_tx_queue(struct mt7603_dev *dev, struct mt76_sw_queue *q,
  9		     int idx, int n_desc)
 10{
 11	struct mt76_queue *hwq;
 12	int err;
 13
 14	hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL);
 15	if (!hwq)
 16		return -ENOMEM;
 17
 18	err = mt76_queue_alloc(dev, hwq, idx, n_desc, 0, MT_TX_RING_BASE);
 19	if (err < 0)
 20		return err;
 21
 22	INIT_LIST_HEAD(&q->swq);
 23	q->q = hwq;
 24
 25	mt7603_irq_enable(dev, MT_INT_TX_DONE(idx));
 26
 27	return 0;
 28}
 29
 30static void
 31mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb)
 32{
 33	__le32 *txd = (__le32 *)skb->data;
 34	struct ieee80211_hdr *hdr;
 35	struct ieee80211_sta *sta;
 36	struct mt7603_sta *msta;
 37	struct mt76_wcid *wcid;
 38	void *priv;
 39	int idx;
 40	u32 val;
 41	u8 tid;
 42
 43	if (skb->len < MT_TXD_SIZE + sizeof(struct ieee80211_hdr))
 44		goto free;
 45
 46	val = le32_to_cpu(txd[1]);
 47	idx = FIELD_GET(MT_TXD1_WLAN_IDX, val);
 48	skb->priority = FIELD_GET(MT_TXD1_TID, val);
 49
 50	if (idx >= MT7603_WTBL_STA - 1)
 51		goto free;
 52
 53	wcid = rcu_dereference(dev->mt76.wcid[idx]);
 54	if (!wcid)
 55		goto free;
 56
 57	priv = msta = container_of(wcid, struct mt7603_sta, wcid);
 58	val = le32_to_cpu(txd[0]);
 59	skb_set_queue_mapping(skb, FIELD_GET(MT_TXD0_Q_IDX, val));
 60
 61	val &= ~(MT_TXD0_P_IDX | MT_TXD0_Q_IDX);
 62	val |= FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_HW_QUEUE_MGMT);
 63	txd[0] = cpu_to_le32(val);
 64
 65	sta = container_of(priv, struct ieee80211_sta, drv_priv);
 66	hdr = (struct ieee80211_hdr *)&skb->data[MT_TXD_SIZE];
 67	tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
 68	ieee80211_sta_set_buffered(sta, tid, true);
 69
 70	spin_lock_bh(&dev->ps_lock);
 71	__skb_queue_tail(&msta->psq, skb);
 72	if (skb_queue_len(&msta->psq) >= 64) {
 73		skb = __skb_dequeue(&msta->psq);
 74		dev_kfree_skb(skb);
 75	}
 76	spin_unlock_bh(&dev->ps_lock);
 77	return;
 78
 79free:
 80	dev_kfree_skb(skb);
 81}
 82
 83void mt7603_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
 84			 struct sk_buff *skb)
 85{
 86	struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
 87	__le32 *rxd = (__le32 *)skb->data;
 88	__le32 *end = (__le32 *)&skb->data[skb->len];
 89	enum rx_pkt_type type;
 90
 91	type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0]));
 92
 93	if (q == MT_RXQ_MCU) {
 94		if (type == PKT_TYPE_RX_EVENT)
 95			mt76_mcu_rx_event(&dev->mt76, skb);
 96		else
 97			mt7603_rx_loopback_skb(dev, skb);
 98		return;
 99	}
100
101	switch (type) {
102	case PKT_TYPE_TXS:
103		for (rxd++; rxd + 5 <= end; rxd += 5)
104			mt7603_mac_add_txs(dev, rxd);
105		dev_kfree_skb(skb);
106		break;
107	case PKT_TYPE_RX_EVENT:
108		mt76_mcu_rx_event(&dev->mt76, skb);
109		return;
110	case PKT_TYPE_NORMAL:
111		if (mt7603_mac_fill_rx(dev, skb) == 0) {
112			mt76_rx(&dev->mt76, q, skb);
113			return;
114		}
115		/* fall through */
116	default:
117		dev_kfree_skb(skb);
118		break;
119	}
120}
121
122static int
123mt7603_init_rx_queue(struct mt7603_dev *dev, struct mt76_queue *q,
124		     int idx, int n_desc, int bufsize)
125{
126	int err;
127
128	err = mt76_queue_alloc(dev, q, idx, n_desc, bufsize,
129			       MT_RX_RING_BASE);
130	if (err < 0)
131		return err;
132
133	mt7603_irq_enable(dev, MT_INT_RX_DONE(idx));
134
135	return 0;
136}
137
138static int mt7603_poll_tx(struct napi_struct *napi, int budget)
139{
140	struct mt7603_dev *dev;
141	int i;
142
143	dev = container_of(napi, struct mt7603_dev, mt76.tx_napi);
144	dev->tx_dma_check = 0;
145
146	for (i = MT_TXQ_MCU; i >= 0; i--)
147		mt76_queue_tx_cleanup(dev, i, false);
148
149	if (napi_complete_done(napi, 0))
150		mt7603_irq_enable(dev, MT_INT_TX_DONE_ALL);
151
152	for (i = MT_TXQ_MCU; i >= 0; i--)
153		mt76_queue_tx_cleanup(dev, i, false);
154
155	tasklet_schedule(&dev->mt76.tx_tasklet);
156
157	return 0;
158}
159
160int mt7603_dma_init(struct mt7603_dev *dev)
161{
162	static const u8 wmm_queue_map[] = {
163		[IEEE80211_AC_BK] = 0,
164		[IEEE80211_AC_BE] = 1,
165		[IEEE80211_AC_VI] = 2,
166		[IEEE80211_AC_VO] = 3,
167	};
168	int ret;
169	int i;
170
171	mt76_dma_attach(&dev->mt76);
172
173	mt76_clear(dev, MT_WPDMA_GLO_CFG,
174		   MT_WPDMA_GLO_CFG_TX_DMA_EN |
175		   MT_WPDMA_GLO_CFG_RX_DMA_EN |
176		   MT_WPDMA_GLO_CFG_DMA_BURST_SIZE |
177		   MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
178
179	mt76_wr(dev, MT_WPDMA_RST_IDX, ~0);
180	mt7603_pse_client_reset(dev);
181
182	for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) {
183		ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[i],
184					   wmm_queue_map[i],
185					   MT_TX_RING_SIZE);
186		if (ret)
187			return ret;
188	}
189
190	ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_PSD],
191				   MT_TX_HW_QUEUE_MGMT, MT_TX_RING_SIZE);
192	if (ret)
193		return ret;
194
195	ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU],
196				   MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE);
197	if (ret)
198		return ret;
199
200	ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_BEACON],
201				   MT_TX_HW_QUEUE_BCN, MT_MCU_RING_SIZE);
202	if (ret)
203		return ret;
204
205	ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_CAB],
206				   MT_TX_HW_QUEUE_BMC, MT_MCU_RING_SIZE);
207	if (ret)
208		return ret;
209
210	ret = mt7603_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1,
211				   MT_MCU_RING_SIZE, MT_RX_BUF_SIZE);
212	if (ret)
213		return ret;
214
215	ret = mt7603_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], 0,
216				   MT7603_RX_RING_SIZE, MT_RX_BUF_SIZE);
217	if (ret)
218		return ret;
219
220	mt76_wr(dev, MT_DELAY_INT_CFG, 0);
221	ret = mt76_init_queues(dev);
222	if (ret)
223		return ret;
224
225	netif_tx_napi_add(&dev->mt76.napi_dev, &dev->mt76.tx_napi,
226			  mt7603_poll_tx, NAPI_POLL_WEIGHT);
227	napi_enable(&dev->mt76.tx_napi);
228
229	return 0;
230}
231
232void mt7603_dma_cleanup(struct mt7603_dev *dev)
233{
234	mt76_clear(dev, MT_WPDMA_GLO_CFG,
235		   MT_WPDMA_GLO_CFG_TX_DMA_EN |
236		   MT_WPDMA_GLO_CFG_RX_DMA_EN |
237		   MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
238
239	tasklet_kill(&dev->mt76.tx_tasklet);
240	mt76_dma_cleanup(&dev->mt76);
241}