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