summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/mediatek/mt76/mt7915/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt7915/init.c')
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/init.c123
1 files changed, 94 insertions, 29 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
index ad4e5b95158b..2732899689fd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
@@ -4,6 +4,7 @@
#include <linux/etherdevice.h>
#include "mt7915.h"
#include "mac.h"
+#include "mcu.h"
#include "eeprom.h"
#define CCK_RATE(_idx, _rate) { \
@@ -93,6 +94,10 @@ mt7915_init_wiphy(struct ieee80211_hw *hw)
hw->queues = 4;
hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
+ hw->netdev_features = NETIF_F_RXCSUM;
+
+ hw->radiotap_timestamp.units_pos =
+ IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US;
phy->slottime = 9;
@@ -108,9 +113,28 @@ mt7915_init_wiphy(struct ieee80211_hw *hw)
ieee80211_hw_set(hw, HAS_RATE_CONTROL);
ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD);
+ ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD);
ieee80211_hw_set(hw, WANT_MONITOR_VIF);
hw->max_tx_fragments = 4;
+
+ if (phy->mt76->cap.has_2ghz)
+ phy->mt76->sband_2g.sband.ht_cap.cap |=
+ IEEE80211_HT_CAP_LDPC_CODING |
+ IEEE80211_HT_CAP_MAX_AMSDU;
+
+ if (phy->mt76->cap.has_5ghz) {
+ phy->mt76->sband_5g.sband.ht_cap.cap |=
+ IEEE80211_HT_CAP_LDPC_CODING |
+ IEEE80211_HT_CAP_MAX_AMSDU;
+ phy->mt76->sband_5g.sband.vht_cap.cap |=
+ IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 |
+ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
+ }
+
+ mt76_set_stream_caps(phy->mt76, true);
+ mt7915_set_stream_vht_txbf_caps(phy);
+ mt7915_set_stream_he_caps(phy);
}
static void
@@ -153,16 +177,14 @@ static void mt7915_mac_init(struct mt7915_dev *dev)
int i;
mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 1536);
- /* disable hardware de-agg */
- mt76_clear(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN);
+ /* enable hardware de-agg */
+ mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN);
for (i = 0; i < MT7915_WTBL_SIZE; i++)
mt7915_mac_wtbl_update(dev, i,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
for (i = 0; i < 2; i++)
mt7915_mac_init_band(dev, i);
-
- mt7915_mcu_set_rts_thresh(&dev->phy, 0x92b);
}
static int mt7915_txbf_init(struct mt7915_dev *dev)
@@ -238,22 +260,17 @@ static int mt7915_register_ext_phy(struct mt7915_dev *dev)
phy->mt76 = mphy;
mphy->chainmask = dev->chainmask & ~dev->mphy.chainmask;
mphy->antenna_mask = BIT(hweight8(mphy->chainmask)) - 1;
- mt7915_init_wiphy(mphy->hw);
INIT_LIST_HEAD(&phy->stats_list);
INIT_DELAYED_WORK(&mphy->mac_work, mt7915_mac_work);
mt7915_eeprom_parse_band_config(phy);
- mt7915_set_stream_vht_txbf_caps(phy);
- mt7915_set_stream_he_caps(phy);
+ mt7915_init_wiphy(mphy->hw);
memcpy(mphy->macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR2,
ETH_ALEN);
mt76_eeprom_override(mphy);
- /* The second interface does not get any packets unless it has a vif */
- ieee80211_hw_set(mphy->hw, WANT_MONITOR_VIF);
-
ret = mt7915_init_tx_queues(phy, MT7915_TXQ_BAND1,
MT7915_TX_RING_SIZE);
if (ret)
@@ -280,7 +297,45 @@ static void mt7915_init_work(struct work_struct *work)
mt7915_mac_init(dev);
mt7915_init_txpower(dev);
mt7915_txbf_init(dev);
- mt7915_register_ext_phy(dev);
+}
+
+static void mt7915_wfsys_reset(struct mt7915_dev *dev)
+{
+ u32 val = MT_TOP_PWR_KEY | MT_TOP_PWR_SW_PWR_ON | MT_TOP_PWR_PWR_ON;
+
+#define MT_MCU_DUMMY_RANDOM GENMASK(15, 0)
+#define MT_MCU_DUMMY_DEFAULT GENMASK(31, 16)
+
+ mt76_wr(dev, MT_MCU_WFDMA0_DUMMY_CR, MT_MCU_DUMMY_RANDOM);
+
+ /* change to software control */
+ val |= MT_TOP_PWR_SW_RST;
+ mt76_wr(dev, MT_TOP_PWR_CTRL, val);
+
+ /* reset wfsys */
+ val &= ~MT_TOP_PWR_SW_RST;
+ mt76_wr(dev, MT_TOP_PWR_CTRL, val);
+
+ /* release wfsys then mcu re-excutes romcode */
+ val |= MT_TOP_PWR_SW_RST;
+ mt76_wr(dev, MT_TOP_PWR_CTRL, val);
+
+ /* switch to hw control */
+ val &= ~MT_TOP_PWR_SW_RST;
+ val |= MT_TOP_PWR_HW_CTRL;
+ mt76_wr(dev, MT_TOP_PWR_CTRL, val);
+
+ /* check whether mcu resets to default */
+ if (!mt76_poll_msec(dev, MT_MCU_WFDMA0_DUMMY_CR, MT_MCU_DUMMY_DEFAULT,
+ MT_MCU_DUMMY_DEFAULT, 1000)) {
+ dev_err(dev->mt76.dev, "wifi subsystem reset failure\n");
+ return;
+ }
+
+ /* wfsys reset won't clear host registers */
+ mt76_clear(dev, MT_TOP_MISC, MT_TOP_MISC_FW_STATE);
+
+ msleep(100);
}
static int mt7915_init_hardware(struct mt7915_dev *dev)
@@ -293,7 +348,12 @@ static int mt7915_init_hardware(struct mt7915_dev *dev)
spin_lock_init(&dev->token_lock);
idr_init(&dev->token);
- dev->dbdc_support = !!(mt7915_l1_rr(dev, MT_HW_BOUND) & BIT(5));
+ dev->dbdc_support = !!(mt76_rr(dev, MT_HW_BOUND) & BIT(5));
+
+ /* If MCU was already running, it is likely in a bad state */
+ if (mt76_get_field(dev, MT_TOP_MISC, MT_TOP_MISC_FW_STATE) >
+ FW_STATE_FW_DOWNLOAD)
+ mt7915_wfsys_reset(dev);
ret = mt7915_dma_init(dev);
if (ret)
@@ -308,8 +368,14 @@ static int mt7915_init_hardware(struct mt7915_dev *dev)
mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);
ret = mt7915_mcu_init(dev);
- if (ret)
- return ret;
+ if (ret) {
+ /* Reset and try again */
+ mt7915_wfsys_reset(dev);
+
+ ret = mt7915_mcu_init(dev);
+ if (ret)
+ return ret;
+ }
ret = mt7915_eeprom_init(dev);
if (ret < 0)
@@ -330,8 +396,14 @@ static int mt7915_init_hardware(struct mt7915_dev *dev)
void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy)
{
- int nss = hweight8(phy->mt76->chainmask);
- u32 *cap = &phy->mt76->sband_5g.sband.vht_cap.cap;
+ int nss;
+ u32 *cap;
+
+ if (!phy->mt76->cap.has_5ghz)
+ return;
+
+ nss = hweight8(phy->mt76->chainmask);
+ cap = &phy->mt76->sband_5g.sband.vht_cap.cap;
*cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |
@@ -635,25 +707,14 @@ int mt7915_register_device(struct mt7915_dev *dev)
return ret;
mt7915_init_wiphy(hw);
- dev->mphy.sband_2g.sband.ht_cap.cap |=
- IEEE80211_HT_CAP_LDPC_CODING |
- IEEE80211_HT_CAP_MAX_AMSDU;
- dev->mphy.sband_5g.sband.ht_cap.cap |=
- IEEE80211_HT_CAP_LDPC_CODING |
- IEEE80211_HT_CAP_MAX_AMSDU;
- dev->mphy.sband_5g.sband.vht_cap.cap |=
- IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 |
- IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
+
if (!dev->dbdc_support)
dev->mphy.sband_5g.sband.vht_cap.cap |=
IEEE80211_VHT_CAP_SHORT_GI_160 |
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+
dev->mphy.hw->wiphy->available_antennas_rx = dev->mphy.chainmask;
dev->mphy.hw->wiphy->available_antennas_tx = dev->mphy.chainmask;
-
- mt76_set_stream_caps(&dev->mphy, true);
- mt7915_set_stream_vht_txbf_caps(&dev->phy);
- mt7915_set_stream_he_caps(&dev->phy);
dev->phy.dfs_state = -1;
#ifdef CONFIG_NL80211_TESTMODE
@@ -667,6 +728,10 @@ int mt7915_register_device(struct mt7915_dev *dev)
ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
+ ret = mt7915_register_ext_phy(dev);
+ if (ret)
+ return ret;
+
return mt7915_init_debugfs(dev);
}