10e3d6777SRyder Lee // SPDX-License-Identifier: ISC
21613c621SLorenzo Bianconi /*
31613c621SLorenzo Bianconi * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
41613c621SLorenzo Bianconi */
51613c621SLorenzo Bianconi
61613c621SLorenzo Bianconi #include "mt76x2.h"
7ad571c93SLorenzo Bianconi #include "../mt76x02_mac.h"
81613c621SLorenzo Bianconi
91613c621SLorenzo Bianconi static int
mt76x2_start(struct ieee80211_hw * hw)101613c621SLorenzo Bianconi mt76x2_start(struct ieee80211_hw *hw)
111613c621SLorenzo Bianconi {
12e40803f2SLorenzo Bianconi struct mt76x02_dev *dev = hw->priv;
131613c621SLorenzo Bianconi
14ad571c93SLorenzo Bianconi mt76x02_mac_start(dev);
15fd6c2dfaSFelix Fietkau mt76x2_phy_start(dev);
161613c621SLorenzo Bianconi
17a782f8bfSLorenzo Bianconi ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work,
182e405024SFelix Fietkau MT_MAC_WORK_INTERVAL);
19c1e0d2beSLorenzo Bianconi ieee80211_queue_delayed_work(mt76_hw(dev), &dev->wdt_work,
20c1e0d2beSLorenzo Bianconi MT_WATCHDOG_TIME);
211613c621SLorenzo Bianconi
22011849e0SFelix Fietkau set_bit(MT76_STATE_RUNNING, &dev->mphy.state);
23091a79fdSStanislaw Gruszka return 0;
241613c621SLorenzo Bianconi }
251613c621SLorenzo Bianconi
261613c621SLorenzo Bianconi static void
mt76x2_stop(struct ieee80211_hw * hw)271613c621SLorenzo Bianconi mt76x2_stop(struct ieee80211_hw *hw)
281613c621SLorenzo Bianconi {
29e40803f2SLorenzo Bianconi struct mt76x02_dev *dev = hw->priv;
301613c621SLorenzo Bianconi
31011849e0SFelix Fietkau clear_bit(MT76_STATE_RUNNING, &dev->mphy.state);
321613c621SLorenzo Bianconi mt76x2_stop_hardware(dev);
331613c621SLorenzo Bianconi }
341613c621SLorenzo Bianconi
35fd6c2dfaSFelix Fietkau static void
mt76x2_set_channel(struct mt76x02_dev * dev,struct cfg80211_chan_def * chandef)36e40803f2SLorenzo Bianconi mt76x2_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef)
371613c621SLorenzo Bianconi {
381613c621SLorenzo Bianconi cancel_delayed_work_sync(&dev->cal_work);
396e4caaeaSLorenzo Bianconi tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
406e4caaeaSLorenzo Bianconi tasklet_disable(&dev->dfs_pd.dfs_tasklet);
411613c621SLorenzo Bianconi
426e4caaeaSLorenzo Bianconi mutex_lock(&dev->mt76.mutex);
43011849e0SFelix Fietkau set_bit(MT76_RESET, &dev->mphy.state);
441613c621SLorenzo Bianconi
4596747a51SFelix Fietkau mt76_set_channel(&dev->mphy);
461613c621SLorenzo Bianconi
471613c621SLorenzo Bianconi mt76x2_mac_stop(dev, true);
48fd6c2dfaSFelix Fietkau mt76x2_phy_set_channel(dev, chandef);
491613c621SLorenzo Bianconi
50aec65e48SFelix Fietkau mt76x02_mac_cc_reset(dev);
51e6cb3291SLorenzo Bianconi mt76x02_dfs_init_params(dev);
521613c621SLorenzo Bianconi
531613c621SLorenzo Bianconi mt76x2_mac_resume(dev);
541613c621SLorenzo Bianconi
55011849e0SFelix Fietkau clear_bit(MT76_RESET, &dev->mphy.state);
566e4caaeaSLorenzo Bianconi mutex_unlock(&dev->mt76.mutex);
576e4caaeaSLorenzo Bianconi
586e4caaeaSLorenzo Bianconi tasklet_enable(&dev->dfs_pd.dfs_tasklet);
596e4caaeaSLorenzo Bianconi tasklet_enable(&dev->mt76.pre_tbtt_tasklet);
601613c621SLorenzo Bianconi
619fba6d07SFelix Fietkau mt76_txq_schedule_all(&dev->mphy);
621613c621SLorenzo Bianconi }
631613c621SLorenzo Bianconi
641613c621SLorenzo Bianconi static int
mt76x2_config(struct ieee80211_hw * hw,u32 changed)651613c621SLorenzo Bianconi mt76x2_config(struct ieee80211_hw *hw, u32 changed)
661613c621SLorenzo Bianconi {
67e40803f2SLorenzo Bianconi struct mt76x02_dev *dev = hw->priv;
681613c621SLorenzo Bianconi
691613c621SLorenzo Bianconi mutex_lock(&dev->mt76.mutex);
701613c621SLorenzo Bianconi
711613c621SLorenzo Bianconi if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
721613c621SLorenzo Bianconi if (!(hw->conf.flags & IEEE80211_CONF_MONITOR))
731613c621SLorenzo Bianconi dev->mt76.rxfilter |= MT_RX_FILTR_CFG_PROMISC;
741613c621SLorenzo Bianconi else
751613c621SLorenzo Bianconi dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_PROMISC;
761613c621SLorenzo Bianconi
771613c621SLorenzo Bianconi mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
781613c621SLorenzo Bianconi }
791613c621SLorenzo Bianconi
801613c621SLorenzo Bianconi if (changed & IEEE80211_CONF_CHANGE_POWER) {
81*633f77b5SLorenzo Bianconi struct mt76_phy *mphy = &dev->mphy;
821613c621SLorenzo Bianconi
83*633f77b5SLorenzo Bianconi dev->txpower_conf = hw->conf.power_level * 2;
84*633f77b5SLorenzo Bianconi dev->txpower_conf = mt76_get_sar_power(mphy,
85*633f77b5SLorenzo Bianconi mphy->chandef.chan,
86*633f77b5SLorenzo Bianconi dev->txpower_conf);
871613c621SLorenzo Bianconi /* convert to per-chain power for 2x2 devices */
889e5f6dd7SFelix Fietkau dev->txpower_conf -= 6;
891613c621SLorenzo Bianconi
90011849e0SFelix Fietkau if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) {
911613c621SLorenzo Bianconi mt76x2_phy_set_txpower(dev);
929e5f6dd7SFelix Fietkau mt76x02_tx_set_txpwr_auto(dev, dev->txpower_conf);
931613c621SLorenzo Bianconi }
941613c621SLorenzo Bianconi }
951613c621SLorenzo Bianconi
966e4caaeaSLorenzo Bianconi mutex_unlock(&dev->mt76.mutex);
976e4caaeaSLorenzo Bianconi
981613c621SLorenzo Bianconi if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
991613c621SLorenzo Bianconi ieee80211_stop_queues(hw);
100fd6c2dfaSFelix Fietkau mt76x2_set_channel(dev, &hw->conf.chandef);
1011613c621SLorenzo Bianconi ieee80211_wake_queues(hw);
1021613c621SLorenzo Bianconi }
1031613c621SLorenzo Bianconi
104fd6c2dfaSFelix Fietkau return 0;
1051613c621SLorenzo Bianconi }
1061613c621SLorenzo Bianconi
1071613c621SLorenzo Bianconi static void
mt76x2_flush(struct ieee80211_hw * hw,struct ieee80211_vif * vif,u32 queues,bool drop)1081613c621SLorenzo Bianconi mt76x2_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1091613c621SLorenzo Bianconi u32 queues, bool drop)
1101613c621SLorenzo Bianconi {
1111613c621SLorenzo Bianconi }
1121613c621SLorenzo Bianconi
mt76x2_set_antenna(struct ieee80211_hw * hw,u32 tx_ant,u32 rx_ant)1131613c621SLorenzo Bianconi static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant,
1141613c621SLorenzo Bianconi u32 rx_ant)
1151613c621SLorenzo Bianconi {
116e40803f2SLorenzo Bianconi struct mt76x02_dev *dev = hw->priv;
1171613c621SLorenzo Bianconi
1181613c621SLorenzo Bianconi if (!tx_ant || tx_ant > 3 || tx_ant != rx_ant)
1191613c621SLorenzo Bianconi return -EINVAL;
1201613c621SLorenzo Bianconi
1211613c621SLorenzo Bianconi mutex_lock(&dev->mt76.mutex);
1221613c621SLorenzo Bianconi
123b9027e08SLorenzo Bianconi dev->mphy.chainmask = (tx_ant == 3) ? 0x202 : 0x101;
124beaaeb6bSFelix Fietkau dev->mphy.antenna_mask = tx_ant;
1251613c621SLorenzo Bianconi
126bb3e3fecSRyder Lee mt76_set_stream_caps(&dev->mphy, true);
1271613c621SLorenzo Bianconi mt76x2_phy_set_antenna(dev);
1281613c621SLorenzo Bianconi
1291613c621SLorenzo Bianconi mutex_unlock(&dev->mt76.mutex);
1301613c621SLorenzo Bianconi
1311613c621SLorenzo Bianconi return 0;
1321613c621SLorenzo Bianconi }
1331613c621SLorenzo Bianconi
1341613c621SLorenzo Bianconi const struct ieee80211_ops mt76x2_ops = {
1352f0308d0SLorenzo Bianconi .tx = mt76x02_tx,
1361613c621SLorenzo Bianconi .start = mt76x2_start,
1371613c621SLorenzo Bianconi .stop = mt76x2_stop,
1381613c621SLorenzo Bianconi .add_interface = mt76x02_add_interface,
1391613c621SLorenzo Bianconi .remove_interface = mt76x02_remove_interface,
1401613c621SLorenzo Bianconi .config = mt76x2_config,
1411613c621SLorenzo Bianconi .configure_filter = mt76x02_configure_filter,
142cc726268SLorenzo Bianconi .bss_info_changed = mt76x02_bss_info_changed,
143e28487eaSFelix Fietkau .sta_state = mt76_sta_state,
14443ba1922SFelix Fietkau .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove,
1451613c621SLorenzo Bianconi .set_key = mt76x02_set_key,
1461613c621SLorenzo Bianconi .conf_tx = mt76x02_conf_tx,
1478b8ab5c2SLorenzo Bianconi .sw_scan_start = mt76_sw_scan,
148c2756a1cSLorenzo Bianconi .sw_scan_complete = mt76x02_sw_scan_complete,
1491613c621SLorenzo Bianconi .flush = mt76x2_flush,
1501613c621SLorenzo Bianconi .ampdu_action = mt76x02_ampdu_action,
1519313faacSFelix Fietkau .get_txpower = mt76_get_txpower,
1521613c621SLorenzo Bianconi .wake_tx_queue = mt76_wake_tx_queue,
1531613c621SLorenzo Bianconi .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update,
1541613c621SLorenzo Bianconi .release_buffered_frames = mt76_release_buffered_frames,
15536704051SLorenzo Bianconi .set_coverage_class = mt76x02_set_coverage_class,
1561613c621SLorenzo Bianconi .get_survey = mt76_get_survey,
15787d53103SStanislaw Gruszka .set_tim = mt76_set_tim,
1581613c621SLorenzo Bianconi .set_antenna = mt76x2_set_antenna,
159e49c76d4SLorenzo Bianconi .get_antenna = mt76_get_antenna,
160317ed42bSLorenzo Bianconi .set_rts_threshold = mt76x02_set_rts_threshold,
161fd6c2dfaSFelix Fietkau .reconfig_complete = mt76x02_reconfig_complete,
162*633f77b5SLorenzo Bianconi .set_sar_specs = mt76x2_set_sar_specs,
1631613c621SLorenzo Bianconi };
1641613c621SLorenzo Bianconi
165