1 /*
2  * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
3  * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
4  * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2
8  * as published by the Free Software Foundation
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  */
15 
16 #include <linux/etherdevice.h>
17 #include "mt76x0.h"
18 
19 static int
20 mt76x0_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef)
21 {
22 	int ret;
23 
24 	cancel_delayed_work_sync(&dev->cal_work);
25 	dev->beacon_ops->pre_tbtt_enable(dev, false);
26 	if (mt76_is_mmio(dev))
27 		tasklet_disable(&dev->dfs_pd.dfs_tasklet);
28 
29 	mt76_set_channel(&dev->mt76);
30 	ret = mt76x0_phy_set_channel(dev, chandef);
31 
32 	/* channel cycle counters read-and-clear */
33 	mt76_rr(dev, MT_CH_IDLE);
34 	mt76_rr(dev, MT_CH_BUSY);
35 
36 	mt76x02_edcca_init(dev, true);
37 
38 	if (mt76_is_mmio(dev)) {
39 		mt76x02_dfs_init_params(dev);
40 		tasklet_enable(&dev->dfs_pd.dfs_tasklet);
41 	}
42 	dev->beacon_ops->pre_tbtt_enable(dev, true);
43 
44 	mt76_txq_schedule_all(&dev->mt76);
45 
46 	return ret;
47 }
48 
49 int mt76x0_config(struct ieee80211_hw *hw, u32 changed)
50 {
51 	struct mt76x02_dev *dev = hw->priv;
52 	int ret = 0;
53 
54 	mutex_lock(&dev->mt76.mutex);
55 
56 	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
57 		ieee80211_stop_queues(hw);
58 		ret = mt76x0_set_channel(dev, &hw->conf.chandef);
59 		ieee80211_wake_queues(hw);
60 	}
61 
62 	if (changed & IEEE80211_CONF_CHANGE_POWER) {
63 		dev->mt76.txpower_conf = hw->conf.power_level * 2;
64 
65 		if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state))
66 			mt76x0_phy_set_txpower(dev);
67 	}
68 
69 	if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
70 		if (!(hw->conf.flags & IEEE80211_CONF_MONITOR))
71 			dev->mt76.rxfilter |= MT_RX_FILTR_CFG_PROMISC;
72 		else
73 			dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_PROMISC;
74 
75 		mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
76 	}
77 
78 	mutex_unlock(&dev->mt76.mutex);
79 
80 	return ret;
81 }
82 EXPORT_SYMBOL_GPL(mt76x0_config);
83