1 /*
2  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
3  * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include "mt76x2.h"
19 #include "../mt76x02_util.h"
20 
21 void mt76x2_mac_stop(struct mt76x02_dev *dev, bool force)
22 {
23 	bool stopped = false;
24 	u32 rts_cfg;
25 	int i;
26 
27 	mt76_wr(dev, MT_MAC_SYS_CTRL, 0);
28 
29 	rts_cfg = mt76_rr(dev, MT_TX_RTS_CFG);
30 	mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg & ~MT_TX_RTS_CFG_RETRY_LIMIT);
31 
32 	/* Wait for MAC to become idle */
33 	for (i = 0; i < 300; i++) {
34 		if ((mt76_rr(dev, MT_MAC_STATUS) &
35 		     (MT_MAC_STATUS_RX | MT_MAC_STATUS_TX)) ||
36 		    mt76_rr(dev, MT_BBP(IBI, 12))) {
37 			udelay(1);
38 			continue;
39 		}
40 
41 		stopped = true;
42 		break;
43 	}
44 
45 	if (force && !stopped) {
46 		mt76_set(dev, MT_BBP(CORE, 4), BIT(1));
47 		mt76_clear(dev, MT_BBP(CORE, 4), BIT(1));
48 
49 		mt76_set(dev, MT_BBP(CORE, 4), BIT(0));
50 		mt76_clear(dev, MT_BBP(CORE, 4), BIT(0));
51 	}
52 
53 	mt76_wr(dev, MT_TX_RTS_CFG, rts_cfg);
54 }
55 EXPORT_SYMBOL_GPL(mt76x2_mac_stop);
56 
57 int mt76x2_mac_get_rssi(struct mt76x02_dev *dev, s8 rssi, int chain)
58 {
59 	struct mt76x02_rx_freq_cal *cal = &dev->cal.rx;
60 
61 	rssi += cal->rssi_offset[chain];
62 	rssi -= cal->lna_gain;
63 
64 	return rssi;
65 }
66 
67 int mt76x2_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb,
68 			  void *rxi)
69 {
70 	struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
71 	struct mt76x02_rxwi *rxwi = rxi;
72 	struct mt76x02_sta *sta;
73 	u32 rxinfo = le32_to_cpu(rxwi->rxinfo);
74 	u32 ctl = le32_to_cpu(rxwi->ctl);
75 	u16 rate = le16_to_cpu(rxwi->rate);
76 	u16 tid_sn = le16_to_cpu(rxwi->tid_sn);
77 	bool unicast = rxwi->rxinfo & cpu_to_le32(MT_RXINFO_UNICAST);
78 	int pad_len = 0;
79 	u8 pn_len;
80 	u8 wcid;
81 	int len;
82 
83 	if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state))
84 		return -EINVAL;
85 
86 	if (rxinfo & MT_RXINFO_L2PAD)
87 		pad_len += 2;
88 
89 	if (rxinfo & MT_RXINFO_DECRYPT) {
90 		status->flag |= RX_FLAG_DECRYPTED;
91 		status->flag |= RX_FLAG_MMIC_STRIPPED;
92 		status->flag |= RX_FLAG_MIC_STRIPPED;
93 		status->flag |= RX_FLAG_IV_STRIPPED;
94 	}
95 
96 	wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl);
97 	sta = mt76x02_rx_get_sta(&dev->mt76, wcid);
98 	status->wcid = mt76x02_rx_get_sta_wcid(sta, unicast);
99 
100 	len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl);
101 	pn_len = FIELD_GET(MT_RXINFO_PN_LEN, rxinfo);
102 	if (pn_len) {
103 		int offset = ieee80211_get_hdrlen_from_skb(skb) + pad_len;
104 		u8 *data = skb->data + offset;
105 
106 		status->iv[0] = data[7];
107 		status->iv[1] = data[6];
108 		status->iv[2] = data[5];
109 		status->iv[3] = data[4];
110 		status->iv[4] = data[1];
111 		status->iv[5] = data[0];
112 
113 		/*
114 		 * Driver CCMP validation can't deal with fragments.
115 		 * Let mac80211 take care of it.
116 		 */
117 		if (rxinfo & MT_RXINFO_FRAG) {
118 			status->flag &= ~RX_FLAG_IV_STRIPPED;
119 		} else {
120 			pad_len += pn_len << 2;
121 			len -= pn_len << 2;
122 		}
123 	}
124 
125 	mt76x02_remove_hdr_pad(skb, pad_len);
126 
127 	if ((rxinfo & MT_RXINFO_BA) && !(rxinfo & MT_RXINFO_NULL))
128 		status->aggr = true;
129 
130 	if (WARN_ON_ONCE(len > skb->len))
131 		return -EINVAL;
132 
133 	pskb_trim(skb, len);
134 	status->chains = BIT(0) | BIT(1);
135 	status->chain_signal[0] = mt76x2_mac_get_rssi(dev, rxwi->rssi[0], 0);
136 	status->chain_signal[1] = mt76x2_mac_get_rssi(dev, rxwi->rssi[1], 1);
137 	status->signal = max(status->chain_signal[0], status->chain_signal[1]);
138 	status->freq = dev->mt76.chandef.chan->center_freq;
139 	status->band = dev->mt76.chandef.chan->band;
140 
141 	status->tid = FIELD_GET(MT_RXWI_TID, tid_sn);
142 	status->seqno = FIELD_GET(MT_RXWI_SN, tid_sn);
143 
144 	if (sta) {
145 		ewma_signal_add(&sta->rssi, status->signal);
146 		sta->inactive_count = 0;
147 	}
148 
149 	return mt76x02_mac_process_rate(status, rate);
150 }
151 EXPORT_SYMBOL_GPL(mt76x2_mac_process_rx);
152