Message ID | 1530771142-4118-4-git-send-email-sgruszka@redhat.com (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | Kalle Valo |
Headers | show |
On Jul 05, Stanislaw Gruszka wrote: > Add mac files of mt76x0 driver. > > Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com> > --- > drivers/net/wireless/mediatek/mt76/mt76x0/mac.c | 661 ++++++++++++++++++++++++ > drivers/net/wireless/mediatek/mt76/mt76x0/mac.h | 154 ++++++ > 2 files changed, 815 insertions(+) > create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x0/mac.c > create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x0/mac.h > > diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c > new file mode 100644 > index 000000000000..88e9f4665561 > --- /dev/null > +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c > @@ -0,0 +1,661 @@ > +/* > + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> > + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> > + * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 > + * as published by the Free Software Foundation > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + */ > + > +#include "mt76x0.h" > +#include "trace.h" > +#include <linux/etherdevice.h> > + > +static void > +mt76_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate, > + enum nl80211_band band) > +{ > + u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate); > + > + txrate->idx = 0; > + txrate->flags = 0; > + txrate->count = 1; > + > + switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) { > + case MT_PHY_TYPE_OFDM: > + if (band == NL80211_BAND_2GHZ) > + idx += 4; > + > + txrate->idx = idx; > + return; > + case MT_PHY_TYPE_CCK: > + if (idx >= 8) > + idx -= 8; > + > + txrate->idx = idx; > + return; > + case MT_PHY_TYPE_HT_GF: > + txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD; > + /* fall through */ > + case MT_PHY_TYPE_HT: > + txrate->flags |= IEEE80211_TX_RC_MCS; > + txrate->idx = idx; > + break; > + case MT_PHY_TYPE_VHT: > + txrate->flags |= IEEE80211_TX_RC_VHT_MCS; > + txrate->idx = idx; > + break; > + default: > + WARN_ON(1); > + return; > + } > + > + switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) { > + case MT_PHY_BW_20: > + break; > + case MT_PHY_BW_40: > + txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; > + break; > + case MT_PHY_BW_80: > + txrate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; > + break; > + default: > + WARN_ON(1); > + return; > + } > + > + if (rate & MT_RXWI_RATE_SGI) > + txrate->flags |= IEEE80211_TX_RC_SHORT_GI; > +} > + > +static void > +mt76_mac_fill_tx_status(struct mt76x0_dev *dev, struct ieee80211_tx_info *info, > + struct mt76_tx_status *st, int n_frames) > +{ > + struct ieee80211_tx_rate *rate = info->status.rates; > + int cur_idx, last_rate; > + int i; > + > + if (!n_frames) > + return; > + > + last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1); > + mt76_mac_process_tx_rate(&rate[last_rate], st->rate, > + dev->mt76.chandef.chan->band); > + if (last_rate < IEEE80211_TX_MAX_RATES - 1) > + rate[last_rate + 1].idx = -1; > + > + cur_idx = rate[last_rate].idx + st->retry; > + for (i = 0; i <= last_rate; i++) { > + rate[i].flags = rate[last_rate].flags; > + rate[i].idx = max_t(int, 0, cur_idx - i); > + rate[i].count = 1; > + } > + > + if (last_rate > 0) > + rate[last_rate - 1].count = st->retry + 1 - last_rate; there is an issue already fixed in mt76x2 here 2d1e9be00162 ('mt76x2: fix mrr idx/count estimation in mt76x2_mac_fill_tx_status()') > + > + info->status.ampdu_len = n_frames; > + info->status.ampdu_ack_len = st->success ? n_frames : 0; > + > + if (st->pktid & MT_TXWI_PKTID_PROBE) > + info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; > + > + if (st->aggr) > + info->flags |= IEEE80211_TX_CTL_AMPDU | > + IEEE80211_TX_STAT_AMPDU; > + > + if (!st->ack_req) > + info->flags |= IEEE80211_TX_CTL_NO_ACK; > + else if (st->success) > + info->flags |= IEEE80211_TX_STAT_ACK; > +} > + > +u16 mt76_mac_tx_rate_val(struct mt76x0_dev *dev, > + const struct ieee80211_tx_rate *rate, u8 *nss_val) > +{ > + u16 rateval; > + u8 phy, rate_idx; > + u8 nss = 1; > + u8 bw = 0; > + > + if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { > + rate_idx = rate->idx; > + nss = 1 + (rate->idx >> 4); > + phy = MT_PHY_TYPE_VHT; > + if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) > + bw = 2; > + else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) > + bw = 1; > + } else if (rate->flags & IEEE80211_TX_RC_MCS) { > + rate_idx = rate->idx; > + nss = 1 + (rate->idx >> 3); > + phy = MT_PHY_TYPE_HT; > + if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) > + phy = MT_PHY_TYPE_HT_GF; > + if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) > + bw = 1; > + } else { > + const struct ieee80211_rate *r; > + int band = dev->mt76.chandef.chan->band; > + u16 val; > + > + r = &dev->mt76.hw->wiphy->bands[band]->bitrates[rate->idx]; > + if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) > + val = r->hw_value_short; > + else > + val = r->hw_value; > + > + phy = val >> 8; > + rate_idx = val & 0xff; > + bw = 0; > + } > + > + rateval = FIELD_PREP(MT_RXWI_RATE_INDEX, rate_idx); > + rateval |= FIELD_PREP(MT_RXWI_RATE_PHY, phy); > + rateval |= FIELD_PREP(MT_RXWI_RATE_BW, bw); > + if (rate->flags & IEEE80211_TX_RC_SHORT_GI) > + rateval |= MT_RXWI_RATE_SGI; > + > + *nss_val = nss; > + return cpu_to_le16(rateval); > +} > + > +void mt76_mac_wcid_set_rate(struct mt76x0_dev *dev, struct mt76_wcid *wcid, > + const struct ieee80211_tx_rate *rate) > +{ > + unsigned long flags; > + > + spin_lock_irqsave(&dev->mt76.lock, flags); > + wcid->tx_rate = mt76_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss); > + wcid->tx_rate_set = true; > + spin_unlock_irqrestore(&dev->mt76.lock, flags); > +} > + > +struct mt76_tx_status mt76x0_mac_fetch_tx_status(struct mt76x0_dev *dev) > +{ > + struct mt76_tx_status stat = {}; > + u32 stat2, stat1; > + > + stat2 = mt76_rr(dev, MT_TX_STAT_FIFO_EXT); > + stat1 = mt76_rr(dev, MT_TX_STAT_FIFO); > + > + stat.valid = !!(stat1 & MT_TX_STAT_FIFO_VALID); > + stat.success = !!(stat1 & MT_TX_STAT_FIFO_SUCCESS); > + stat.aggr = !!(stat1 & MT_TX_STAT_FIFO_AGGR); > + stat.ack_req = !!(stat1 & MT_TX_STAT_FIFO_ACKREQ); > + stat.wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, stat1); > + stat.rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, stat1); > + > + stat.retry = FIELD_GET(MT_TX_STAT_FIFO_EXT_RETRY, stat2); > + stat.pktid = FIELD_GET(MT_TX_STAT_FIFO_EXT_PKTID, stat2); > + > + return stat; > +} > + > +void mt76_send_tx_status(struct mt76x0_dev *dev, struct mt76_tx_status *stat, u8 *update) > +{ > + struct ieee80211_tx_info info = {}; > + struct ieee80211_sta *sta = NULL; > + struct mt76_wcid *wcid = NULL; > + struct mt76_sta *msta = NULL; > + > + rcu_read_lock(); > + if (stat->wcid < ARRAY_SIZE(dev->wcid)) > + wcid = rcu_dereference(dev->wcid[stat->wcid]); > + > + if (wcid) { > + void *priv; > + priv = msta = container_of(wcid, struct mt76_sta, wcid); > + sta = container_of(priv, struct ieee80211_sta, drv_priv); > + } > + > + if (msta && stat->aggr) { > + u32 stat_val, stat_cache; > + > + stat_val = stat->rate; > + stat_val |= ((u32) stat->retry) << 16; > + stat_cache = msta->status.rate; > + stat_cache |= ((u32) msta->status.retry) << 16; > + > + if (*update == 0 && stat_val == stat_cache && > + stat->wcid == msta->status.wcid && msta->n_frames < 32) { > + msta->n_frames++; > + goto out; > + } > + > + mt76_mac_fill_tx_status(dev, &info, &msta->status, > + msta->n_frames); > + msta->status = *stat; > + msta->n_frames = 1; > + *update = 0; > + } else { > + mt76_mac_fill_tx_status(dev, &info, stat, 1); > + *update = 1; > + } > + > + spin_lock_bh(&dev->mac_lock); > + ieee80211_tx_status_noskb(dev->mt76.hw, sta, &info); > + spin_unlock_bh(&dev->mac_lock); > +out: > + rcu_read_unlock(); > +} > + > +void mt76x0_mac_set_protection(struct mt76x0_dev *dev, bool legacy_prot, > + int ht_mode) > +{ > + int mode = ht_mode & IEEE80211_HT_OP_MODE_PROTECTION; > + bool non_gf = !!(ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); > + u32 prot[6]; > + bool ht_rts[4] = {}; > + int i; > + > + prot[0] = MT_PROT_NAV_SHORT | > + MT_PROT_TXOP_ALLOW_ALL | > + MT_PROT_RTS_THR_EN; > + prot[1] = prot[0]; > + if (legacy_prot) > + prot[1] |= MT_PROT_CTRL_CTS2SELF; > + > + prot[2] = prot[4] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_BW20; > + prot[3] = prot[5] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_ALL; > + > + if (legacy_prot) { > + prot[2] |= MT_PROT_RATE_CCK_11; > + prot[3] |= MT_PROT_RATE_CCK_11; > + prot[4] |= MT_PROT_RATE_CCK_11; > + prot[5] |= MT_PROT_RATE_CCK_11; > + } else { > + prot[2] |= MT_PROT_RATE_OFDM_24; > + prot[3] |= MT_PROT_RATE_DUP_OFDM_24; > + prot[4] |= MT_PROT_RATE_OFDM_24; > + prot[5] |= MT_PROT_RATE_DUP_OFDM_24; > + } > + > + switch (mode) { > + case IEEE80211_HT_OP_MODE_PROTECTION_NONE: > + break; > + > + case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: > + ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true; > + break; > + > + case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: > + ht_rts[1] = ht_rts[3] = true; > + break; > + > + case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: > + ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true; > + break; > + } > + > + if (non_gf) > + ht_rts[2] = ht_rts[3] = true; > + > + for (i = 0; i < 4; i++) > + if (ht_rts[i]) > + prot[i + 2] |= MT_PROT_CTRL_RTS_CTS; > + > + for (i = 0; i < 6; i++) > + mt76_wr(dev, MT_CCK_PROT_CFG + i * 4, prot[i]); > +} > + > +void mt76x0_mac_set_short_preamble(struct mt76x0_dev *dev, bool short_preamb) > +{ > + if (short_preamb) > + mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT); > + else > + mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT); > +} > + > +void mt76x0_mac_config_tsf(struct mt76x0_dev *dev, bool enable, int interval) > +{ > + u32 val = mt76_rr(dev, MT_BEACON_TIME_CFG); > + > + val &= ~(MT_BEACON_TIME_CFG_TIMER_EN | > + MT_BEACON_TIME_CFG_SYNC_MODE | > + MT_BEACON_TIME_CFG_TBTT_EN); > + > + if (!enable) { > + mt76_wr(dev, MT_BEACON_TIME_CFG, val); > + return; > + } > + > + val &= ~MT_BEACON_TIME_CFG_INTVAL; > + val |= FIELD_PREP(MT_BEACON_TIME_CFG_INTVAL, interval << 4) | > + MT_BEACON_TIME_CFG_TIMER_EN | > + MT_BEACON_TIME_CFG_SYNC_MODE | > + MT_BEACON_TIME_CFG_TBTT_EN; > +} > + > +static void mt76x0_check_mac_err(struct mt76x0_dev *dev) > +{ > + u32 val = mt76_rr(dev, 0x10f4); > + > + if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5)))) > + return; > + > + dev_err(dev->mt76.dev, "Error: MAC specific condition occurred\n"); > + > + mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR); > + udelay(10); > + mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR); > +} > +void mt76x0_mac_work(struct work_struct *work) > +{ > + struct mt76x0_dev *dev = container_of(work, struct mt76x0_dev, > + mac_work.work); > + struct { > + u32 addr_base; > + u32 span; > + u64 *stat_base; > + } spans[] = { > + { MT_RX_STA_CNT0, 3, dev->stats.rx_stat }, > + { MT_TX_STA_CNT0, 3, dev->stats.tx_stat }, > + { MT_TX_AGG_STAT, 1, dev->stats.aggr_stat }, > + { MT_MPDU_DENSITY_CNT, 1, dev->stats.zero_len_del }, > + { MT_TX_AGG_CNT_BASE0, 8, &dev->stats.aggr_n[0] }, > + { MT_TX_AGG_CNT_BASE1, 8, &dev->stats.aggr_n[16] }, > + }; > + u32 sum, n; > + int i, j, k; > + > + /* Note: using MCU_RANDOM_READ is actually slower then reading all the > + * registers by hand. MCU takes ca. 20ms to complete read of 24 > + * registers while reading them one by one will takes roughly > + * 24*200us =~ 5ms. > + */ > + > + k = 0; > + n = 0; > + sum = 0; > + for (i = 0; i < ARRAY_SIZE(spans); i++) > + for (j = 0; j < spans[i].span; j++) { > + u32 val = mt76_rr(dev, spans[i].addr_base + j * 4); > + > + spans[i].stat_base[j * 2] += val & 0xffff; > + spans[i].stat_base[j * 2 + 1] += val >> 16; > + > + /* Calculate average AMPDU length */ > + if (spans[i].addr_base != MT_TX_AGG_CNT_BASE0 && > + spans[i].addr_base != MT_TX_AGG_CNT_BASE1) > + continue; > + > + n += (val >> 16) + (val & 0xffff); > + sum += (val & 0xffff) * (1 + k * 2) + > + (val >> 16) * (2 + k * 2); > + k++; > + } > + > + atomic_set(&dev->avg_ampdu_len, n ? DIV_ROUND_CLOSEST(sum, n) : 1); > + > + mt76x0_check_mac_err(dev); > + > + ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work, 10 * HZ); > +} > + > +void > +mt76x0_mac_wcid_setup(struct mt76x0_dev *dev, u8 idx, u8 vif_idx, u8 *mac) > +{ > + u8 zmac[ETH_ALEN] = {}; > + u32 attr; > + > + attr = FIELD_PREP(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) | > + FIELD_PREP(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8)); > + > + mt76_wr(dev, MT_WCID_ATTR(idx), attr); > + > + if (mac) > + memcpy(zmac, mac, sizeof(zmac)); > + > + mt76x0_addr_wr(dev, MT_WCID_ADDR(idx), zmac); > +} > + > +void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev) > +{ > + struct ieee80211_sta *sta; > + struct mt76_wcid *wcid; > + void *msta; > + u8 min_factor = 3; > + int i; > + > + return; > + > + rcu_read_lock(); > + for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) { > + wcid = rcu_dereference(dev->wcid[i]); > + if (!wcid) > + continue; > + > + msta = container_of(wcid, struct mt76_sta, wcid); > + sta = container_of(msta, struct ieee80211_sta, drv_priv); > + > + min_factor = min(min_factor, sta->ht_cap.ampdu_factor); > + } > + rcu_read_unlock(); > + > + mt76_wr(dev, MT_MAX_LEN_CFG, 0xa0fff | > + FIELD_PREP(MT_MAX_LEN_CFG_AMPDU, min_factor)); > +} > + > +static void > +mt76_mac_process_rate(struct ieee80211_rx_status *status, u16 rate) > +{ > + u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate); > + > + switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) { > + case MT_PHY_TYPE_OFDM: > + if (idx >= 8) > + idx = 0; > + > + if (status->band == NL80211_BAND_2GHZ) > + idx += 4; > + > + status->rate_idx = idx; > + return; > + case MT_PHY_TYPE_CCK: > + if (idx >= 8) { > + idx -= 8; > + status->enc_flags |= RX_ENC_FLAG_SHORTPRE; > + } > + > + if (idx >= 4) > + idx = 0; > + > + status->rate_idx = idx; > + return; > + case MT_PHY_TYPE_HT_GF: > + status->enc_flags |= RX_ENC_FLAG_HT_GF; > + /* fall through */ > + case MT_PHY_TYPE_HT: > + status->encoding = RX_ENC_HT; > + status->rate_idx = idx; > + break; > + case MT_PHY_TYPE_VHT: > + status->encoding = RX_ENC_VHT; > + status->rate_idx = FIELD_GET(MT_RATE_INDEX_VHT_IDX, idx); > + status->nss = FIELD_GET(MT_RATE_INDEX_VHT_NSS, idx) + 1; > + break; > + default: > + WARN_ON(1); > + return; > + } > + > + if (rate & MT_RXWI_RATE_LDPC) > + status->enc_flags |= RX_ENC_FLAG_LDPC; > + > + if (rate & MT_RXWI_RATE_SGI) > + status->enc_flags |= RX_ENC_FLAG_SHORT_GI; > + > + if (rate & MT_RXWI_RATE_STBC) > + status->enc_flags |= 1 << RX_ENC_FLAG_STBC_SHIFT; > + > + switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) { > + case MT_PHY_BW_20: > + break; > + case MT_PHY_BW_40: > + status->bw = RATE_INFO_BW_40; > + break; > + case MT_PHY_BW_80: > + status->bw = RATE_INFO_BW_80; > + break; > + default: > + WARN_ON(1); > + break; > + } > +} > + > +static void > +mt76x0_rx_monitor_beacon(struct mt76x0_dev *dev, struct mt76x0_rxwi *rxwi, > + u16 rate, int rssi) > +{ > + dev->bcn_phy_mode = FIELD_GET(MT_RXWI_RATE_PHY, rate); > + dev->avg_rssi = ((dev->avg_rssi * 15) / 16 + (rssi << 8)) / 256; > +} > + > +static int > +mt76x0_rx_is_our_beacon(struct mt76x0_dev *dev, u8 *data) > +{ > + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)data; > + > + return ieee80211_is_beacon(hdr->frame_control) && > + ether_addr_equal(hdr->addr2, dev->ap_bssid); > +} > + > +u32 mt76_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, > + u8 *data, void *rxi) > +{ > + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); > + struct mt76x0_rxwi *rxwi = rxi; > + u32 len, ctl = le32_to_cpu(rxwi->ctl); > + u16 rate = le16_to_cpu(rxwi->rate); > + int rssi; > + > + len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl); > + if (WARN_ON(len < 10)) > + return 0; > + > + if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) { > + status->flag |= RX_FLAG_DECRYPTED; > + status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; > + } > + > + status->chains = BIT(0); > + rssi = mt76x0_phy_get_rssi(dev, rxwi); > + status->chain_signal[0] = status->signal = rssi; > + status->freq = dev->mt76.chandef.chan->center_freq; > + status->band = dev->mt76.chandef.chan->band; > + > + mt76_mac_process_rate(status, rate); > + > + spin_lock_bh(&dev->con_mon_lock); > + if (mt76x0_rx_is_our_beacon(dev, data)) { > + mt76x0_rx_monitor_beacon(dev, rxwi, rate, rssi); > + } else if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_U2M)) { > + if (dev->avg_rssi == 0) > + dev->avg_rssi = rssi; > + else > + dev->avg_rssi = (dev->avg_rssi * 15) / 16 + rssi / 16; > + > + } > + spin_unlock_bh(&dev->con_mon_lock); > + > + return len; > +} > + > +static enum mt76_cipher_type > +mt76_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) > +{ > + memset(key_data, 0, 32); > + if (!key) > + return MT_CIPHER_NONE; > + > + if (key->keylen > 32) > + return MT_CIPHER_NONE; > + > + memcpy(key_data, key->key, key->keylen); > + > + switch (key->cipher) { > + case WLAN_CIPHER_SUITE_WEP40: > + return MT_CIPHER_WEP40; > + case WLAN_CIPHER_SUITE_WEP104: > + return MT_CIPHER_WEP104; > + case WLAN_CIPHER_SUITE_TKIP: > + return MT_CIPHER_TKIP; > + case WLAN_CIPHER_SUITE_CCMP: > + return MT_CIPHER_AES_CCMP; > + default: > + return MT_CIPHER_NONE; > + } > +} > + > +int mt76_mac_wcid_set_key(struct mt76x0_dev *dev, u8 idx, > + struct ieee80211_key_conf *key) > +{ > + enum mt76_cipher_type cipher; > + u8 key_data[32]; > + u8 iv_data[8]; > + u32 val; > + > + cipher = mt76_mac_get_key_info(key, key_data); > + if (cipher == MT_CIPHER_NONE && key) > + return -EINVAL; > + > + trace_set_key(&dev->mt76, idx); > + > + mt76_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data)); > + > + memset(iv_data, 0, sizeof(iv_data)); > + if (key) { > + iv_data[3] = key->keyidx << 6; > + if (cipher >= MT_CIPHER_TKIP) { > + /* Note: start with 1 to comply with spec, > + * (see comment on common/cmm_wpa.c:4291). > + */ > + iv_data[0] |= 1; > + iv_data[3] |= 0x20; > + } > + } > + mt76_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data)); > + > + val = mt76_rr(dev, MT_WCID_ATTR(idx)); > + val &= ~MT_WCID_ATTR_PKEY_MODE & ~MT_WCID_ATTR_PKEY_MODE_EXT; > + val |= FIELD_PREP(MT_WCID_ATTR_PKEY_MODE, cipher & 7) | > + FIELD_PREP(MT_WCID_ATTR_PKEY_MODE_EXT, cipher >> 3); > + val &= ~MT_WCID_ATTR_PAIRWISE; > + val |= MT_WCID_ATTR_PAIRWISE * > + !!(key && key->flags & IEEE80211_KEY_FLAG_PAIRWISE); > + mt76_wr(dev, MT_WCID_ATTR(idx), val); > + > + return 0; > +} > + > +int mt76_mac_shared_key_setup(struct mt76x0_dev *dev, u8 vif_idx, u8 key_idx, > + struct ieee80211_key_conf *key) > +{ > + enum mt76_cipher_type cipher; > + u8 key_data[32]; > + u32 val; > + > + cipher = mt76_mac_get_key_info(key, key_data); > + if (cipher == MT_CIPHER_NONE && key) > + return -EINVAL; > + > + trace_set_shared_key(&dev->mt76, vif_idx, key_idx); > + > + mt76_wr_copy(dev, MT_SKEY(vif_idx, key_idx), > + key_data, sizeof(key_data)); > + > + val = mt76_rr(dev, MT_SKEY_MODE(vif_idx)); > + val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx)); > + val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx); > + mt76_wr(dev, MT_SKEY_MODE(vif_idx), val); > + > + return 0; > +} > diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h > new file mode 100644 > index 000000000000..947eba253553 > --- /dev/null > +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h > @@ -0,0 +1,154 @@ > +/* > + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> > + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 > + * as published by the Free Software Foundation > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + */ > + > +#ifndef __MT76_MAC_H > +#define __MT76_MAC_H > + > +/* Note: values in original "RSSI" and "SNR" fields are not actually what they > + * are called for MT76X0U, names used by this driver are educated guesses > + * (see vendor mac/ral_omac.c). > + */ > +struct mt76x0_rxwi { > + __le32 rxinfo; > + > + __le32 ctl; > + > + __le16 tid_sn; > + __le16 rate; > + > + s8 rssi[4]; > + > + __le32 bbp_rxinfo[4]; > +} __packed __aligned(4); > + > +#define MT_RXINFO_BA BIT(0) > +#define MT_RXINFO_DATA BIT(1) > +#define MT_RXINFO_NULL BIT(2) > +#define MT_RXINFO_FRAG BIT(3) > +#define MT_RXINFO_U2M BIT(4) > +#define MT_RXINFO_MULTICAST BIT(5) > +#define MT_RXINFO_BROADCAST BIT(6) > +#define MT_RXINFO_MYBSS BIT(7) > +#define MT_RXINFO_CRCERR BIT(8) > +#define MT_RXINFO_ICVERR BIT(9) > +#define MT_RXINFO_MICERR BIT(10) > +#define MT_RXINFO_AMSDU BIT(11) > +#define MT_RXINFO_HTC BIT(12) > +#define MT_RXINFO_RSSI BIT(13) > +#define MT_RXINFO_L2PAD BIT(14) > +#define MT_RXINFO_AMPDU BIT(15) > +#define MT_RXINFO_DECRYPT BIT(16) > +#define MT_RXINFO_BSSIDX3 BIT(17) > +#define MT_RXINFO_WAPI_KEY BIT(18) > +#define MT_RXINFO_PN_LEN GENMASK(21, 19) > +#define MT_RXINFO_SW_PKT_80211 BIT(22) > +#define MT_RXINFO_TCP_SUM_BYPASS BIT(28) > +#define MT_RXINFO_IP_SUM_BYPASS BIT(29) > +#define MT_RXINFO_TCP_SUM_ERR BIT(30) > +#define MT_RXINFO_IP_SUM_ERR BIT(31) > + > +#define MT_RXWI_CTL_WCID GENMASK(7, 0) > +#define MT_RXWI_CTL_KEY_IDX GENMASK(9, 8) > +#define MT_RXWI_CTL_BSS_IDX GENMASK(12, 10) > +#define MT_RXWI_CTL_UDF GENMASK(15, 13) > +#define MT_RXWI_CTL_MPDU_LEN GENMASK(27, 16) > +#define MT_RXWI_CTL_TID GENMASK(31, 28) > + > +#define MT_RXWI_FRAG GENMASK(3, 0) > +#define MT_RXWI_SN GENMASK(15, 4) > + > +#define MT_RXWI_RATE_INDEX GENMASK(5, 0) > +#define MT_RXWI_RATE_LDPC BIT(6) > +#define MT_RXWI_RATE_BW GENMASK(8, 7) > +#define MT_RXWI_RATE_SGI BIT(9) > +#define MT_RXWI_RATE_STBC BIT(10) > +#define MT_RXWI_RATE_LDPC_ETXBF BIT(11) > +#define MT_RXWI_RATE_SND BIT(12) > +#define MT_RXWI_RATE_PHY GENMASK(15, 13) > + > +#define MT_RATE_INDEX_VHT_IDX GENMASK(3, 0) > +#define MT_RATE_INDEX_VHT_NSS GENMASK(5, 4) > + > +#define MT_RXWI_GAIN_RSSI_VAL GENMASK(5, 0) > +#define MT_RXWI_GAIN_RSSI_LNA_ID GENMASK(7, 6) > +#define MT_RXWI_ANT_AUX_LNA BIT(7) > + > +#define MT_RXWI_EANT_ENC_ANT_ID GENMASK(7, 0) > + > +enum mt76_phy_bandwidth { > + MT_PHY_BW_20, > + MT_PHY_BW_40, > + MT_PHY_BW_80, > +}; > + > +struct mt76_txwi { > + __le16 flags; > + __le16 rate_ctl; > + u8 ack_ctl; > + u8 wcid; > + __le16 len_ctl; > + __le32 iv; > + __le32 eiv; > + u8 aid; > + u8 txstream; > + u8 ctl2; > + u8 pktid; > +} __packed __aligned(4); > + > +#define MT_TXWI_FLAGS_FRAG BIT(0) > +#define MT_TXWI_FLAGS_MMPS BIT(1) > +#define MT_TXWI_FLAGS_CFACK BIT(2) > +#define MT_TXWI_FLAGS_TS BIT(3) > +#define MT_TXWI_FLAGS_AMPDU BIT(4) > +#define MT_TXWI_FLAGS_MPDU_DENSITY GENMASK(7, 5) > +#define MT_TXWI_FLAGS_TXOP GENMASK(9, 8) > +#define MT_TXWI_FLAGS_CWMIN GENMASK(12, 10) > +#define MT_TXWI_FLAGS_NO_RATE_FALLBACK BIT(13) > +#define MT_TXWI_FLAGS_TX_RPT BIT(14) > +#define MT_TXWI_FLAGS_TX_RATE_LUT BIT(15) > + > +#define MT_TXWI_RATE_MCS GENMASK(6, 0) > +#define MT_TXWI_RATE_BW BIT(7) > +#define MT_TXWI_RATE_SGI BIT(8) > +#define MT_TXWI_RATE_STBC GENMASK(10, 9) > +#define MT_TXWI_RATE_PHY_MODE GENMASK(15, 14) > + > +#define MT_TXWI_ACK_CTL_REQ BIT(0) > +#define MT_TXWI_ACK_CTL_NSEQ BIT(1) > +#define MT_TXWI_ACK_CTL_BA_WINDOW GENMASK(7, 2) > + > +#define MT_TXWI_LEN_BYTE_CNT GENMASK(11, 0) > + > +#define MT_TXWI_CTL_TX_POWER_ADJ GENMASK(3, 0) > +#define MT_TXWI_CTL_CHAN_CHECK_PKT BIT(4) > +#define MT_TXWI_CTL_PIFS_REV BIT(6) > + > +#define MT_TXWI_PKTID_PROBE BIT(7) > + > +u32 mt76_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, > + u8 *data, void *rxi); > +int mt76_mac_wcid_set_key(struct mt76x0_dev *dev, u8 idx, > + struct ieee80211_key_conf *key); > +void mt76_mac_wcid_set_rate(struct mt76x0_dev *dev, struct mt76_wcid *wcid, > + const struct ieee80211_tx_rate *rate); > + > +int mt76_mac_shared_key_setup(struct mt76x0_dev *dev, u8 vif_idx, u8 key_idx, > + struct ieee80211_key_conf *key); > +u16 mt76_mac_tx_rate_val(struct mt76x0_dev *dev, > + const struct ieee80211_tx_rate *rate, u8 *nss_val); > +struct mt76_tx_status > +mt76x0_mac_fetch_tx_status(struct mt76x0_dev *dev); > +void mt76_send_tx_status(struct mt76x0_dev *dev, struct mt76_tx_status *stat, u8 *update); > + > +#endif > -- > 1.9.3 >
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c new file mode 100644 index 000000000000..88e9f4665561 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.c @@ -0,0 +1,661 @@ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "mt76x0.h" +#include "trace.h" +#include <linux/etherdevice.h> + +static void +mt76_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate, + enum nl80211_band band) +{ + u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate); + + txrate->idx = 0; + txrate->flags = 0; + txrate->count = 1; + + switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) { + case MT_PHY_TYPE_OFDM: + if (band == NL80211_BAND_2GHZ) + idx += 4; + + txrate->idx = idx; + return; + case MT_PHY_TYPE_CCK: + if (idx >= 8) + idx -= 8; + + txrate->idx = idx; + return; + case MT_PHY_TYPE_HT_GF: + txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD; + /* fall through */ + case MT_PHY_TYPE_HT: + txrate->flags |= IEEE80211_TX_RC_MCS; + txrate->idx = idx; + break; + case MT_PHY_TYPE_VHT: + txrate->flags |= IEEE80211_TX_RC_VHT_MCS; + txrate->idx = idx; + break; + default: + WARN_ON(1); + return; + } + + switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) { + case MT_PHY_BW_20: + break; + case MT_PHY_BW_40: + txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + break; + case MT_PHY_BW_80: + txrate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; + break; + default: + WARN_ON(1); + return; + } + + if (rate & MT_RXWI_RATE_SGI) + txrate->flags |= IEEE80211_TX_RC_SHORT_GI; +} + +static void +mt76_mac_fill_tx_status(struct mt76x0_dev *dev, struct ieee80211_tx_info *info, + struct mt76_tx_status *st, int n_frames) +{ + struct ieee80211_tx_rate *rate = info->status.rates; + int cur_idx, last_rate; + int i; + + if (!n_frames) + return; + + last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1); + mt76_mac_process_tx_rate(&rate[last_rate], st->rate, + dev->mt76.chandef.chan->band); + if (last_rate < IEEE80211_TX_MAX_RATES - 1) + rate[last_rate + 1].idx = -1; + + cur_idx = rate[last_rate].idx + st->retry; + for (i = 0; i <= last_rate; i++) { + rate[i].flags = rate[last_rate].flags; + rate[i].idx = max_t(int, 0, cur_idx - i); + rate[i].count = 1; + } + + if (last_rate > 0) + rate[last_rate - 1].count = st->retry + 1 - last_rate; + + info->status.ampdu_len = n_frames; + info->status.ampdu_ack_len = st->success ? n_frames : 0; + + if (st->pktid & MT_TXWI_PKTID_PROBE) + info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; + + if (st->aggr) + info->flags |= IEEE80211_TX_CTL_AMPDU | + IEEE80211_TX_STAT_AMPDU; + + if (!st->ack_req) + info->flags |= IEEE80211_TX_CTL_NO_ACK; + else if (st->success) + info->flags |= IEEE80211_TX_STAT_ACK; +} + +u16 mt76_mac_tx_rate_val(struct mt76x0_dev *dev, + const struct ieee80211_tx_rate *rate, u8 *nss_val) +{ + u16 rateval; + u8 phy, rate_idx; + u8 nss = 1; + u8 bw = 0; + + if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { + rate_idx = rate->idx; + nss = 1 + (rate->idx >> 4); + phy = MT_PHY_TYPE_VHT; + if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) + bw = 2; + else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + bw = 1; + } else if (rate->flags & IEEE80211_TX_RC_MCS) { + rate_idx = rate->idx; + nss = 1 + (rate->idx >> 3); + phy = MT_PHY_TYPE_HT; + if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) + phy = MT_PHY_TYPE_HT_GF; + if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + bw = 1; + } else { + const struct ieee80211_rate *r; + int band = dev->mt76.chandef.chan->band; + u16 val; + + r = &dev->mt76.hw->wiphy->bands[band]->bitrates[rate->idx]; + if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + val = r->hw_value_short; + else + val = r->hw_value; + + phy = val >> 8; + rate_idx = val & 0xff; + bw = 0; + } + + rateval = FIELD_PREP(MT_RXWI_RATE_INDEX, rate_idx); + rateval |= FIELD_PREP(MT_RXWI_RATE_PHY, phy); + rateval |= FIELD_PREP(MT_RXWI_RATE_BW, bw); + if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + rateval |= MT_RXWI_RATE_SGI; + + *nss_val = nss; + return cpu_to_le16(rateval); +} + +void mt76_mac_wcid_set_rate(struct mt76x0_dev *dev, struct mt76_wcid *wcid, + const struct ieee80211_tx_rate *rate) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->mt76.lock, flags); + wcid->tx_rate = mt76_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss); + wcid->tx_rate_set = true; + spin_unlock_irqrestore(&dev->mt76.lock, flags); +} + +struct mt76_tx_status mt76x0_mac_fetch_tx_status(struct mt76x0_dev *dev) +{ + struct mt76_tx_status stat = {}; + u32 stat2, stat1; + + stat2 = mt76_rr(dev, MT_TX_STAT_FIFO_EXT); + stat1 = mt76_rr(dev, MT_TX_STAT_FIFO); + + stat.valid = !!(stat1 & MT_TX_STAT_FIFO_VALID); + stat.success = !!(stat1 & MT_TX_STAT_FIFO_SUCCESS); + stat.aggr = !!(stat1 & MT_TX_STAT_FIFO_AGGR); + stat.ack_req = !!(stat1 & MT_TX_STAT_FIFO_ACKREQ); + stat.wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, stat1); + stat.rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, stat1); + + stat.retry = FIELD_GET(MT_TX_STAT_FIFO_EXT_RETRY, stat2); + stat.pktid = FIELD_GET(MT_TX_STAT_FIFO_EXT_PKTID, stat2); + + return stat; +} + +void mt76_send_tx_status(struct mt76x0_dev *dev, struct mt76_tx_status *stat, u8 *update) +{ + struct ieee80211_tx_info info = {}; + struct ieee80211_sta *sta = NULL; + struct mt76_wcid *wcid = NULL; + struct mt76_sta *msta = NULL; + + rcu_read_lock(); + if (stat->wcid < ARRAY_SIZE(dev->wcid)) + wcid = rcu_dereference(dev->wcid[stat->wcid]); + + if (wcid) { + void *priv; + priv = msta = container_of(wcid, struct mt76_sta, wcid); + sta = container_of(priv, struct ieee80211_sta, drv_priv); + } + + if (msta && stat->aggr) { + u32 stat_val, stat_cache; + + stat_val = stat->rate; + stat_val |= ((u32) stat->retry) << 16; + stat_cache = msta->status.rate; + stat_cache |= ((u32) msta->status.retry) << 16; + + if (*update == 0 && stat_val == stat_cache && + stat->wcid == msta->status.wcid && msta->n_frames < 32) { + msta->n_frames++; + goto out; + } + + mt76_mac_fill_tx_status(dev, &info, &msta->status, + msta->n_frames); + msta->status = *stat; + msta->n_frames = 1; + *update = 0; + } else { + mt76_mac_fill_tx_status(dev, &info, stat, 1); + *update = 1; + } + + spin_lock_bh(&dev->mac_lock); + ieee80211_tx_status_noskb(dev->mt76.hw, sta, &info); + spin_unlock_bh(&dev->mac_lock); +out: + rcu_read_unlock(); +} + +void mt76x0_mac_set_protection(struct mt76x0_dev *dev, bool legacy_prot, + int ht_mode) +{ + int mode = ht_mode & IEEE80211_HT_OP_MODE_PROTECTION; + bool non_gf = !!(ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); + u32 prot[6]; + bool ht_rts[4] = {}; + int i; + + prot[0] = MT_PROT_NAV_SHORT | + MT_PROT_TXOP_ALLOW_ALL | + MT_PROT_RTS_THR_EN; + prot[1] = prot[0]; + if (legacy_prot) + prot[1] |= MT_PROT_CTRL_CTS2SELF; + + prot[2] = prot[4] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_BW20; + prot[3] = prot[5] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_ALL; + + if (legacy_prot) { + prot[2] |= MT_PROT_RATE_CCK_11; + prot[3] |= MT_PROT_RATE_CCK_11; + prot[4] |= MT_PROT_RATE_CCK_11; + prot[5] |= MT_PROT_RATE_CCK_11; + } else { + prot[2] |= MT_PROT_RATE_OFDM_24; + prot[3] |= MT_PROT_RATE_DUP_OFDM_24; + prot[4] |= MT_PROT_RATE_OFDM_24; + prot[5] |= MT_PROT_RATE_DUP_OFDM_24; + } + + switch (mode) { + case IEEE80211_HT_OP_MODE_PROTECTION_NONE: + break; + + case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: + ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true; + break; + + case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: + ht_rts[1] = ht_rts[3] = true; + break; + + case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: + ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true; + break; + } + + if (non_gf) + ht_rts[2] = ht_rts[3] = true; + + for (i = 0; i < 4; i++) + if (ht_rts[i]) + prot[i + 2] |= MT_PROT_CTRL_RTS_CTS; + + for (i = 0; i < 6; i++) + mt76_wr(dev, MT_CCK_PROT_CFG + i * 4, prot[i]); +} + +void mt76x0_mac_set_short_preamble(struct mt76x0_dev *dev, bool short_preamb) +{ + if (short_preamb) + mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT); + else + mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT); +} + +void mt76x0_mac_config_tsf(struct mt76x0_dev *dev, bool enable, int interval) +{ + u32 val = mt76_rr(dev, MT_BEACON_TIME_CFG); + + val &= ~(MT_BEACON_TIME_CFG_TIMER_EN | + MT_BEACON_TIME_CFG_SYNC_MODE | + MT_BEACON_TIME_CFG_TBTT_EN); + + if (!enable) { + mt76_wr(dev, MT_BEACON_TIME_CFG, val); + return; + } + + val &= ~MT_BEACON_TIME_CFG_INTVAL; + val |= FIELD_PREP(MT_BEACON_TIME_CFG_INTVAL, interval << 4) | + MT_BEACON_TIME_CFG_TIMER_EN | + MT_BEACON_TIME_CFG_SYNC_MODE | + MT_BEACON_TIME_CFG_TBTT_EN; +} + +static void mt76x0_check_mac_err(struct mt76x0_dev *dev) +{ + u32 val = mt76_rr(dev, 0x10f4); + + if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5)))) + return; + + dev_err(dev->mt76.dev, "Error: MAC specific condition occurred\n"); + + mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR); + udelay(10); + mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR); +} +void mt76x0_mac_work(struct work_struct *work) +{ + struct mt76x0_dev *dev = container_of(work, struct mt76x0_dev, + mac_work.work); + struct { + u32 addr_base; + u32 span; + u64 *stat_base; + } spans[] = { + { MT_RX_STA_CNT0, 3, dev->stats.rx_stat }, + { MT_TX_STA_CNT0, 3, dev->stats.tx_stat }, + { MT_TX_AGG_STAT, 1, dev->stats.aggr_stat }, + { MT_MPDU_DENSITY_CNT, 1, dev->stats.zero_len_del }, + { MT_TX_AGG_CNT_BASE0, 8, &dev->stats.aggr_n[0] }, + { MT_TX_AGG_CNT_BASE1, 8, &dev->stats.aggr_n[16] }, + }; + u32 sum, n; + int i, j, k; + + /* Note: using MCU_RANDOM_READ is actually slower then reading all the + * registers by hand. MCU takes ca. 20ms to complete read of 24 + * registers while reading them one by one will takes roughly + * 24*200us =~ 5ms. + */ + + k = 0; + n = 0; + sum = 0; + for (i = 0; i < ARRAY_SIZE(spans); i++) + for (j = 0; j < spans[i].span; j++) { + u32 val = mt76_rr(dev, spans[i].addr_base + j * 4); + + spans[i].stat_base[j * 2] += val & 0xffff; + spans[i].stat_base[j * 2 + 1] += val >> 16; + + /* Calculate average AMPDU length */ + if (spans[i].addr_base != MT_TX_AGG_CNT_BASE0 && + spans[i].addr_base != MT_TX_AGG_CNT_BASE1) + continue; + + n += (val >> 16) + (val & 0xffff); + sum += (val & 0xffff) * (1 + k * 2) + + (val >> 16) * (2 + k * 2); + k++; + } + + atomic_set(&dev->avg_ampdu_len, n ? DIV_ROUND_CLOSEST(sum, n) : 1); + + mt76x0_check_mac_err(dev); + + ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work, 10 * HZ); +} + +void +mt76x0_mac_wcid_setup(struct mt76x0_dev *dev, u8 idx, u8 vif_idx, u8 *mac) +{ + u8 zmac[ETH_ALEN] = {}; + u32 attr; + + attr = FIELD_PREP(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) | + FIELD_PREP(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8)); + + mt76_wr(dev, MT_WCID_ATTR(idx), attr); + + if (mac) + memcpy(zmac, mac, sizeof(zmac)); + + mt76x0_addr_wr(dev, MT_WCID_ADDR(idx), zmac); +} + +void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev) +{ + struct ieee80211_sta *sta; + struct mt76_wcid *wcid; + void *msta; + u8 min_factor = 3; + int i; + + return; + + rcu_read_lock(); + for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) { + wcid = rcu_dereference(dev->wcid[i]); + if (!wcid) + continue; + + msta = container_of(wcid, struct mt76_sta, wcid); + sta = container_of(msta, struct ieee80211_sta, drv_priv); + + min_factor = min(min_factor, sta->ht_cap.ampdu_factor); + } + rcu_read_unlock(); + + mt76_wr(dev, MT_MAX_LEN_CFG, 0xa0fff | + FIELD_PREP(MT_MAX_LEN_CFG_AMPDU, min_factor)); +} + +static void +mt76_mac_process_rate(struct ieee80211_rx_status *status, u16 rate) +{ + u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate); + + switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) { + case MT_PHY_TYPE_OFDM: + if (idx >= 8) + idx = 0; + + if (status->band == NL80211_BAND_2GHZ) + idx += 4; + + status->rate_idx = idx; + return; + case MT_PHY_TYPE_CCK: + if (idx >= 8) { + idx -= 8; + status->enc_flags |= RX_ENC_FLAG_SHORTPRE; + } + + if (idx >= 4) + idx = 0; + + status->rate_idx = idx; + return; + case MT_PHY_TYPE_HT_GF: + status->enc_flags |= RX_ENC_FLAG_HT_GF; + /* fall through */ + case MT_PHY_TYPE_HT: + status->encoding = RX_ENC_HT; + status->rate_idx = idx; + break; + case MT_PHY_TYPE_VHT: + status->encoding = RX_ENC_VHT; + status->rate_idx = FIELD_GET(MT_RATE_INDEX_VHT_IDX, idx); + status->nss = FIELD_GET(MT_RATE_INDEX_VHT_NSS, idx) + 1; + break; + default: + WARN_ON(1); + return; + } + + if (rate & MT_RXWI_RATE_LDPC) + status->enc_flags |= RX_ENC_FLAG_LDPC; + + if (rate & MT_RXWI_RATE_SGI) + status->enc_flags |= RX_ENC_FLAG_SHORT_GI; + + if (rate & MT_RXWI_RATE_STBC) + status->enc_flags |= 1 << RX_ENC_FLAG_STBC_SHIFT; + + switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) { + case MT_PHY_BW_20: + break; + case MT_PHY_BW_40: + status->bw = RATE_INFO_BW_40; + break; + case MT_PHY_BW_80: + status->bw = RATE_INFO_BW_80; + break; + default: + WARN_ON(1); + break; + } +} + +static void +mt76x0_rx_monitor_beacon(struct mt76x0_dev *dev, struct mt76x0_rxwi *rxwi, + u16 rate, int rssi) +{ + dev->bcn_phy_mode = FIELD_GET(MT_RXWI_RATE_PHY, rate); + dev->avg_rssi = ((dev->avg_rssi * 15) / 16 + (rssi << 8)) / 256; +} + +static int +mt76x0_rx_is_our_beacon(struct mt76x0_dev *dev, u8 *data) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)data; + + return ieee80211_is_beacon(hdr->frame_control) && + ether_addr_equal(hdr->addr2, dev->ap_bssid); +} + +u32 mt76_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, + u8 *data, void *rxi) +{ + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + struct mt76x0_rxwi *rxwi = rxi; + u32 len, ctl = le32_to_cpu(rxwi->ctl); + u16 rate = le16_to_cpu(rxwi->rate); + int rssi; + + len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl); + if (WARN_ON(len < 10)) + return 0; + + if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) { + status->flag |= RX_FLAG_DECRYPTED; + status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; + } + + status->chains = BIT(0); + rssi = mt76x0_phy_get_rssi(dev, rxwi); + status->chain_signal[0] = status->signal = rssi; + status->freq = dev->mt76.chandef.chan->center_freq; + status->band = dev->mt76.chandef.chan->band; + + mt76_mac_process_rate(status, rate); + + spin_lock_bh(&dev->con_mon_lock); + if (mt76x0_rx_is_our_beacon(dev, data)) { + mt76x0_rx_monitor_beacon(dev, rxwi, rate, rssi); + } else if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_U2M)) { + if (dev->avg_rssi == 0) + dev->avg_rssi = rssi; + else + dev->avg_rssi = (dev->avg_rssi * 15) / 16 + rssi / 16; + + } + spin_unlock_bh(&dev->con_mon_lock); + + return len; +} + +static enum mt76_cipher_type +mt76_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) +{ + memset(key_data, 0, 32); + if (!key) + return MT_CIPHER_NONE; + + if (key->keylen > 32) + return MT_CIPHER_NONE; + + memcpy(key_data, key->key, key->keylen); + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + return MT_CIPHER_WEP40; + case WLAN_CIPHER_SUITE_WEP104: + return MT_CIPHER_WEP104; + case WLAN_CIPHER_SUITE_TKIP: + return MT_CIPHER_TKIP; + case WLAN_CIPHER_SUITE_CCMP: + return MT_CIPHER_AES_CCMP; + default: + return MT_CIPHER_NONE; + } +} + +int mt76_mac_wcid_set_key(struct mt76x0_dev *dev, u8 idx, + struct ieee80211_key_conf *key) +{ + enum mt76_cipher_type cipher; + u8 key_data[32]; + u8 iv_data[8]; + u32 val; + + cipher = mt76_mac_get_key_info(key, key_data); + if (cipher == MT_CIPHER_NONE && key) + return -EINVAL; + + trace_set_key(&dev->mt76, idx); + + mt76_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data)); + + memset(iv_data, 0, sizeof(iv_data)); + if (key) { + iv_data[3] = key->keyidx << 6; + if (cipher >= MT_CIPHER_TKIP) { + /* Note: start with 1 to comply with spec, + * (see comment on common/cmm_wpa.c:4291). + */ + iv_data[0] |= 1; + iv_data[3] |= 0x20; + } + } + mt76_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data)); + + val = mt76_rr(dev, MT_WCID_ATTR(idx)); + val &= ~MT_WCID_ATTR_PKEY_MODE & ~MT_WCID_ATTR_PKEY_MODE_EXT; + val |= FIELD_PREP(MT_WCID_ATTR_PKEY_MODE, cipher & 7) | + FIELD_PREP(MT_WCID_ATTR_PKEY_MODE_EXT, cipher >> 3); + val &= ~MT_WCID_ATTR_PAIRWISE; + val |= MT_WCID_ATTR_PAIRWISE * + !!(key && key->flags & IEEE80211_KEY_FLAG_PAIRWISE); + mt76_wr(dev, MT_WCID_ATTR(idx), val); + + return 0; +} + +int mt76_mac_shared_key_setup(struct mt76x0_dev *dev, u8 vif_idx, u8 key_idx, + struct ieee80211_key_conf *key) +{ + enum mt76_cipher_type cipher; + u8 key_data[32]; + u32 val; + + cipher = mt76_mac_get_key_info(key, key_data); + if (cipher == MT_CIPHER_NONE && key) + return -EINVAL; + + trace_set_shared_key(&dev->mt76, vif_idx, key_idx); + + mt76_wr_copy(dev, MT_SKEY(vif_idx, key_idx), + key_data, sizeof(key_data)); + + val = mt76_rr(dev, MT_SKEY_MODE(vif_idx)); + val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx)); + val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx); + mt76_wr(dev, MT_SKEY_MODE(vif_idx), val); + + return 0; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h new file mode 100644 index 000000000000..947eba253553 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mac.h @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT76_MAC_H +#define __MT76_MAC_H + +/* Note: values in original "RSSI" and "SNR" fields are not actually what they + * are called for MT76X0U, names used by this driver are educated guesses + * (see vendor mac/ral_omac.c). + */ +struct mt76x0_rxwi { + __le32 rxinfo; + + __le32 ctl; + + __le16 tid_sn; + __le16 rate; + + s8 rssi[4]; + + __le32 bbp_rxinfo[4]; +} __packed __aligned(4); + +#define MT_RXINFO_BA BIT(0) +#define MT_RXINFO_DATA BIT(1) +#define MT_RXINFO_NULL BIT(2) +#define MT_RXINFO_FRAG BIT(3) +#define MT_RXINFO_U2M BIT(4) +#define MT_RXINFO_MULTICAST BIT(5) +#define MT_RXINFO_BROADCAST BIT(6) +#define MT_RXINFO_MYBSS BIT(7) +#define MT_RXINFO_CRCERR BIT(8) +#define MT_RXINFO_ICVERR BIT(9) +#define MT_RXINFO_MICERR BIT(10) +#define MT_RXINFO_AMSDU BIT(11) +#define MT_RXINFO_HTC BIT(12) +#define MT_RXINFO_RSSI BIT(13) +#define MT_RXINFO_L2PAD BIT(14) +#define MT_RXINFO_AMPDU BIT(15) +#define MT_RXINFO_DECRYPT BIT(16) +#define MT_RXINFO_BSSIDX3 BIT(17) +#define MT_RXINFO_WAPI_KEY BIT(18) +#define MT_RXINFO_PN_LEN GENMASK(21, 19) +#define MT_RXINFO_SW_PKT_80211 BIT(22) +#define MT_RXINFO_TCP_SUM_BYPASS BIT(28) +#define MT_RXINFO_IP_SUM_BYPASS BIT(29) +#define MT_RXINFO_TCP_SUM_ERR BIT(30) +#define MT_RXINFO_IP_SUM_ERR BIT(31) + +#define MT_RXWI_CTL_WCID GENMASK(7, 0) +#define MT_RXWI_CTL_KEY_IDX GENMASK(9, 8) +#define MT_RXWI_CTL_BSS_IDX GENMASK(12, 10) +#define MT_RXWI_CTL_UDF GENMASK(15, 13) +#define MT_RXWI_CTL_MPDU_LEN GENMASK(27, 16) +#define MT_RXWI_CTL_TID GENMASK(31, 28) + +#define MT_RXWI_FRAG GENMASK(3, 0) +#define MT_RXWI_SN GENMASK(15, 4) + +#define MT_RXWI_RATE_INDEX GENMASK(5, 0) +#define MT_RXWI_RATE_LDPC BIT(6) +#define MT_RXWI_RATE_BW GENMASK(8, 7) +#define MT_RXWI_RATE_SGI BIT(9) +#define MT_RXWI_RATE_STBC BIT(10) +#define MT_RXWI_RATE_LDPC_ETXBF BIT(11) +#define MT_RXWI_RATE_SND BIT(12) +#define MT_RXWI_RATE_PHY GENMASK(15, 13) + +#define MT_RATE_INDEX_VHT_IDX GENMASK(3, 0) +#define MT_RATE_INDEX_VHT_NSS GENMASK(5, 4) + +#define MT_RXWI_GAIN_RSSI_VAL GENMASK(5, 0) +#define MT_RXWI_GAIN_RSSI_LNA_ID GENMASK(7, 6) +#define MT_RXWI_ANT_AUX_LNA BIT(7) + +#define MT_RXWI_EANT_ENC_ANT_ID GENMASK(7, 0) + +enum mt76_phy_bandwidth { + MT_PHY_BW_20, + MT_PHY_BW_40, + MT_PHY_BW_80, +}; + +struct mt76_txwi { + __le16 flags; + __le16 rate_ctl; + u8 ack_ctl; + u8 wcid; + __le16 len_ctl; + __le32 iv; + __le32 eiv; + u8 aid; + u8 txstream; + u8 ctl2; + u8 pktid; +} __packed __aligned(4); + +#define MT_TXWI_FLAGS_FRAG BIT(0) +#define MT_TXWI_FLAGS_MMPS BIT(1) +#define MT_TXWI_FLAGS_CFACK BIT(2) +#define MT_TXWI_FLAGS_TS BIT(3) +#define MT_TXWI_FLAGS_AMPDU BIT(4) +#define MT_TXWI_FLAGS_MPDU_DENSITY GENMASK(7, 5) +#define MT_TXWI_FLAGS_TXOP GENMASK(9, 8) +#define MT_TXWI_FLAGS_CWMIN GENMASK(12, 10) +#define MT_TXWI_FLAGS_NO_RATE_FALLBACK BIT(13) +#define MT_TXWI_FLAGS_TX_RPT BIT(14) +#define MT_TXWI_FLAGS_TX_RATE_LUT BIT(15) + +#define MT_TXWI_RATE_MCS GENMASK(6, 0) +#define MT_TXWI_RATE_BW BIT(7) +#define MT_TXWI_RATE_SGI BIT(8) +#define MT_TXWI_RATE_STBC GENMASK(10, 9) +#define MT_TXWI_RATE_PHY_MODE GENMASK(15, 14) + +#define MT_TXWI_ACK_CTL_REQ BIT(0) +#define MT_TXWI_ACK_CTL_NSEQ BIT(1) +#define MT_TXWI_ACK_CTL_BA_WINDOW GENMASK(7, 2) + +#define MT_TXWI_LEN_BYTE_CNT GENMASK(11, 0) + +#define MT_TXWI_CTL_TX_POWER_ADJ GENMASK(3, 0) +#define MT_TXWI_CTL_CHAN_CHECK_PKT BIT(4) +#define MT_TXWI_CTL_PIFS_REV BIT(6) + +#define MT_TXWI_PKTID_PROBE BIT(7) + +u32 mt76_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb, + u8 *data, void *rxi); +int mt76_mac_wcid_set_key(struct mt76x0_dev *dev, u8 idx, + struct ieee80211_key_conf *key); +void mt76_mac_wcid_set_rate(struct mt76x0_dev *dev, struct mt76_wcid *wcid, + const struct ieee80211_tx_rate *rate); + +int mt76_mac_shared_key_setup(struct mt76x0_dev *dev, u8 vif_idx, u8 key_idx, + struct ieee80211_key_conf *key); +u16 mt76_mac_tx_rate_val(struct mt76x0_dev *dev, + const struct ieee80211_tx_rate *rate, u8 *nss_val); +struct mt76_tx_status +mt76x0_mac_fetch_tx_status(struct mt76x0_dev *dev); +void mt76_send_tx_status(struct mt76x0_dev *dev, struct mt76_tx_status *stat, u8 *update); + +#endif
Add mac files of mt76x0 driver. Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com> --- drivers/net/wireless/mediatek/mt76/mt76x0/mac.c | 661 ++++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76x0/mac.h | 154 ++++++ 2 files changed, 815 insertions(+) create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x0/mac.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x0/mac.h