mt76x2_main.c 8.6 KB
Newer Older
F
Felix Fietkau 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "mt76x2.h"
18
#include "mt76x02_util.h"
F
Felix Fietkau 已提交
19 20 21 22 23 24 25

static int
mt76x2_start(struct ieee80211_hw *hw)
{
	struct mt76x2_dev *dev = hw->priv;
	int ret;

26
	mutex_lock(&dev->mt76.mutex);
F
Felix Fietkau 已提交
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41

	ret = mt76x2_mac_start(dev);
	if (ret)
		goto out;

	ret = mt76x2_phy_start(dev);
	if (ret)
		goto out;

	ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work,
				     MT_CALIBRATE_INTERVAL);

	set_bit(MT76_STATE_RUNNING, &dev->mt76.state);

out:
42
	mutex_unlock(&dev->mt76.mutex);
F
Felix Fietkau 已提交
43 44 45 46 47 48 49 50
	return ret;
}

static void
mt76x2_stop(struct ieee80211_hw *hw)
{
	struct mt76x2_dev *dev = hw->priv;

51
	mutex_lock(&dev->mt76.mutex);
F
Felix Fietkau 已提交
52 53
	clear_bit(MT76_STATE_RUNNING, &dev->mt76.state);
	mt76x2_stop_hardware(dev);
54
	mutex_unlock(&dev->mt76.mutex);
F
Felix Fietkau 已提交
55 56 57 58 59 60
}

static int
mt76x2_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
	struct mt76x2_dev *dev = hw->priv;
61
	struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv;
F
Felix Fietkau 已提交
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
	unsigned int idx = 0;

	if (vif->addr[0] & BIT(1))
		idx = 1 + (((dev->mt76.macaddr[0] ^ vif->addr[0]) >> 2) & 7);

	/*
	 * Client mode typically only has one configurable BSSID register,
	 * which is used for bssidx=0. This is linked to the MAC address.
	 * Since mac80211 allows changing interface types, and we cannot
	 * force the use of the primary MAC address for a station mode
	 * interface, we need some other way of configuring a per-interface
	 * remote BSSID.
	 * The hardware provides an AP-Client feature, where bssidx 0-7 are
	 * used for AP mode and bssidx 8-15 for client mode.
	 * We shift the station interface bss index by 8 to force the
	 * hardware to recognize the BSSID.
	 * The resulting bssidx mismatch for unicast frames is ignored by hw.
	 */
	if (vif->type == NL80211_IFTYPE_STATION)
		idx += 8;

	mvif->idx = idx;
84
	mvif->group_wcid.idx = MT_VIF_WCID(idx);
F
Felix Fietkau 已提交
85 86 87
	mvif->group_wcid.hw_key_idx = -1;
	mt76x2_txq_init(dev, vif->txq);

88
	return 0;
F
Felix Fietkau 已提交
89 90 91 92 93 94 95
}

static int
mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef)
{
	int ret;

96 97 98 99
	cancel_delayed_work_sync(&dev->cal_work);

	set_bit(MT76_RESET, &dev->mt76.state);

F
Felix Fietkau 已提交
100 101 102
	mt76_set_channel(&dev->mt76);

	tasklet_disable(&dev->pre_tbtt_tasklet);
103
	tasklet_disable(&dev->dfs_pd.dfs_tasklet);
F
Felix Fietkau 已提交
104 105 106 107 108 109 110 111 112 113 114

	mt76x2_mac_stop(dev, true);
	ret = mt76x2_phy_set_channel(dev, chandef);

	/* channel cycle counters read-and-clear */
	mt76_rr(dev, MT_CH_IDLE);
	mt76_rr(dev, MT_CH_BUSY);

	mt76x2_dfs_init_params(dev);

	mt76x2_mac_resume(dev);
115
	tasklet_enable(&dev->dfs_pd.dfs_tasklet);
F
Felix Fietkau 已提交
116 117
	tasklet_enable(&dev->pre_tbtt_tasklet);

118 119 120 121
	clear_bit(MT76_RESET, &dev->mt76.state);

	mt76_txq_schedule_all(&dev->mt76);

F
Felix Fietkau 已提交
122 123 124 125 126 127 128 129 130
	return ret;
}

static int
mt76x2_config(struct ieee80211_hw *hw, u32 changed)
{
	struct mt76x2_dev *dev = hw->priv;
	int ret = 0;

131
	mutex_lock(&dev->mt76.mutex);
F
Felix Fietkau 已提交
132

133 134
	if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
		if (!(hw->conf.flags & IEEE80211_CONF_MONITOR))
135
			dev->mt76.rxfilter |= MT_RX_FILTR_CFG_PROMISC;
136
		else
137
			dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_PROMISC;
138

139
		mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
140 141
	}

F
Felix Fietkau 已提交
142 143 144
	if (changed & IEEE80211_CONF_CHANGE_POWER) {
		dev->txpower_conf = hw->conf.power_level * 2;

145 146 147
		/* convert to per-chain power for 2x2 devices */
		dev->txpower_conf -= 6;

F
Felix Fietkau 已提交
148 149 150 151 152 153 154 155 156 157 158 159
		if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) {
			mt76x2_phy_set_txpower(dev);
			mt76x2_tx_set_txpwr_auto(dev, dev->txpower_conf);
		}
	}

	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
		ieee80211_stop_queues(hw);
		ret = mt76x2_set_channel(dev, &hw->conf.chandef);
		ieee80211_wake_queues(hw);
	}

160
	mutex_unlock(&dev->mt76.mutex);
F
Felix Fietkau 已提交
161 162 163 164 165 166 167 168 169

	return ret;
}

static void
mt76x2_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
			struct ieee80211_bss_conf *info, u32 changed)
{
	struct mt76x2_dev *dev = hw->priv;
170
	struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv;
F
Felix Fietkau 已提交
171

172
	mutex_lock(&dev->mt76.mutex);
F
Felix Fietkau 已提交
173 174 175 176

	if (changed & BSS_CHANGED_BSSID)
		mt76x2_mac_set_bssid(dev, mvif->idx, info->bssid);

F
Felix Fietkau 已提交
177
	if (changed & BSS_CHANGED_BEACON_INT) {
F
Felix Fietkau 已提交
178 179 180
		mt76_rmw_field(dev, MT_BEACON_TIME_CFG,
			       MT_BEACON_TIME_CFG_INTVAL,
			       info->beacon_int << 4);
F
Felix Fietkau 已提交
181 182 183
		dev->beacon_int = info->beacon_int;
		dev->tbtt_count = 0;
	}
F
Felix Fietkau 已提交
184 185 186 187 188 189 190 191 192 193 194 195

	if (changed & BSS_CHANGED_BEACON_ENABLED) {
		tasklet_disable(&dev->pre_tbtt_tasklet);
		mt76x2_mac_set_beacon_enable(dev, mvif->idx,
					     info->enable_beacon);
		tasklet_enable(&dev->pre_tbtt_tasklet);
	}

	if (changed & BSS_CHANGED_ERP_SLOT) {
		int slottime = info->use_short_slot ? 9 : 20;

		dev->slottime = slottime;
196
		mt76x2_set_tx_ackto(dev);
F
Felix Fietkau 已提交
197 198
	}

199
	mutex_unlock(&dev->mt76.mutex);
F
Felix Fietkau 已提交
200 201
}

F
Felix Fietkau 已提交
202 203
void
mt76x2_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps)
F
Felix Fietkau 已提交
204 205
{
	struct mt76x2_sta *msta = (struct mt76x2_sta *) sta->drv_priv;
F
Felix Fietkau 已提交
206
	struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76);
F
Felix Fietkau 已提交
207 208
	int idx = msta->wcid.idx;

209
	mt76_stop_tx_queues(&dev->mt76, sta, true);
210
	mt76x02_mac_wcid_set_drop(&dev->mt76, idx, ps);
F
Felix Fietkau 已提交
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
}

static void
mt76x2_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
	       const u8 *mac)
{
	struct mt76x2_dev *dev = hw->priv;

	tasklet_disable(&dev->pre_tbtt_tasklet);
	set_bit(MT76_SCANNING, &dev->mt76.state);
}

static void
mt76x2_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
	struct mt76x2_dev *dev = hw->priv;

	clear_bit(MT76_SCANNING, &dev->mt76.state);
	tasklet_enable(&dev->pre_tbtt_tasklet);
}

static void
mt76x2_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
	     u32 queues, bool drop)
{
}

static int
mt76x2_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm)
{
	struct mt76x2_dev *dev = hw->priv;

	*dbm = dev->txpower_cur / 2;
244 245 246 247

	/* convert from per-chain power to combined output on 2x2 devices */
	*dbm += 3;

F
Felix Fietkau 已提交
248 249 250 251 252 253 254 255
	return 0;
}

static void mt76x2_set_coverage_class(struct ieee80211_hw *hw,
				      s16 coverage_class)
{
	struct mt76x2_dev *dev = hw->priv;

256
	mutex_lock(&dev->mt76.mutex);
F
Felix Fietkau 已提交
257 258
	dev->coverage_class = coverage_class;
	mt76x2_set_tx_ackto(dev);
259
	mutex_unlock(&dev->mt76.mutex);
F
Felix Fietkau 已提交
260 261
}

F
Felix Fietkau 已提交
262 263 264 265 266 267
static int
mt76x2_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
{
	return 0;
}

268 269 270 271 272 273 274 275
static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant,
			      u32 rx_ant)
{
	struct mt76x2_dev *dev = hw->priv;

	if (!tx_ant || tx_ant > 3 || tx_ant != rx_ant)
		return -EINVAL;

276
	mutex_lock(&dev->mt76.mutex);
277 278 279 280 281 282 283

	dev->chainmask = (tx_ant == 3) ? 0x202 : 0x101;
	dev->mt76.antenna_mask = tx_ant;

	mt76_set_stream_caps(&dev->mt76, true);
	mt76x2_phy_set_antenna(dev);

284
	mutex_unlock(&dev->mt76.mutex);
285 286 287 288 289 290 291 292 293

	return 0;
}

static int mt76x2_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant,
			      u32 *rx_ant)
{
	struct mt76x2_dev *dev = hw->priv;

294
	mutex_lock(&dev->mt76.mutex);
295 296
	*tx_ant = dev->mt76.antenna_mask;
	*rx_ant = dev->mt76.antenna_mask;
297
	mutex_unlock(&dev->mt76.mutex);
298 299 300 301

	return 0;
}

302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
static int
mt76x2_set_rts_threshold(struct ieee80211_hw *hw, u32 val)
{
	struct mt76x2_dev *dev = hw->priv;

	if (val != ~0 && val > 0xffff)
		return -EINVAL;

	mutex_lock(&dev->mutex);
	mt76x2_mac_set_tx_protection(dev, val);
	mutex_unlock(&dev->mutex);

	return 0;
}

F
Felix Fietkau 已提交
317 318 319 320 321 322 323
const struct ieee80211_ops mt76x2_ops = {
	.tx = mt76x2_tx,
	.start = mt76x2_start,
	.stop = mt76x2_stop,
	.add_interface = mt76x2_add_interface,
	.remove_interface = mt76x2_remove_interface,
	.config = mt76x2_config,
324
	.configure_filter = mt76x02_configure_filter,
F
Felix Fietkau 已提交
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
	.bss_info_changed = mt76x2_bss_info_changed,
	.sta_add = mt76x2_sta_add,
	.sta_remove = mt76x2_sta_remove,
	.set_key = mt76x2_set_key,
	.conf_tx = mt76x2_conf_tx,
	.sw_scan_start = mt76x2_sw_scan,
	.sw_scan_complete = mt76x2_sw_scan_complete,
	.flush = mt76x2_flush,
	.ampdu_action = mt76x2_ampdu_action,
	.get_txpower = mt76x2_get_txpower,
	.wake_tx_queue = mt76_wake_tx_queue,
	.sta_rate_tbl_update = mt76x2_sta_rate_tbl_update,
	.release_buffered_frames = mt76_release_buffered_frames,
	.set_coverage_class = mt76x2_set_coverage_class,
	.get_survey = mt76_get_survey,
F
Felix Fietkau 已提交
340
	.set_tim = mt76x2_set_tim,
341 342
	.set_antenna = mt76x2_set_antenna,
	.get_antenna = mt76x2_get_antenna,
343
	.set_rts_threshold = mt76x2_set_rts_threshold,
F
Felix Fietkau 已提交
344 345
};