brintos

brintos / linux-shallow public Read only

0
0
Text · 10.8 KiB · 7570c6c Raw
432 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>4 * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>5 */6 7#include "mt7601u.h"8#include "mac.h"9#include <linux/etherdevice.h>10 11static int mt7601u_start(struct ieee80211_hw *hw)12{13	struct mt7601u_dev *dev = hw->priv;14	int ret;15 16	mutex_lock(&dev->mutex);17 18	ret = mt7601u_mac_start(dev);19	if (ret)20		goto out;21 22	ieee80211_queue_delayed_work(dev->hw, &dev->mac_work,23				     MT_CALIBRATE_INTERVAL);24	ieee80211_queue_delayed_work(dev->hw, &dev->cal_work,25				     MT_CALIBRATE_INTERVAL);26out:27	mutex_unlock(&dev->mutex);28	return ret;29}30 31static void mt7601u_stop(struct ieee80211_hw *hw, bool suspend)32{33	struct mt7601u_dev *dev = hw->priv;34 35	mutex_lock(&dev->mutex);36 37	cancel_delayed_work_sync(&dev->cal_work);38	cancel_delayed_work_sync(&dev->mac_work);39	mt7601u_mac_stop(dev);40 41	mutex_unlock(&dev->mutex);42}43 44static int mt7601u_add_interface(struct ieee80211_hw *hw,45				 struct ieee80211_vif *vif)46{47	struct mt7601u_dev *dev = hw->priv;48	struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;49	unsigned int idx = 0;50	unsigned int wcid = GROUP_WCID(idx);51 52	/* Note: for AP do the AP-STA things mt76 does:53	 *	- beacon offsets54	 *	- do mac address tricks55	 *	- shift vif idx56	 */57	mvif->idx = idx;58 59	if (!ether_addr_equal(dev->macaddr, vif->addr))60		mt7601u_set_macaddr(dev, vif->addr);61 62	if (dev->wcid_mask[wcid / BITS_PER_LONG] & BIT(wcid % BITS_PER_LONG))63		return -ENOSPC;64	dev->wcid_mask[wcid / BITS_PER_LONG] |= BIT(wcid % BITS_PER_LONG);65	mvif->group_wcid.idx = wcid;66	mvif->group_wcid.hw_key_idx = -1;67 68	return 0;69}70 71static void mt7601u_remove_interface(struct ieee80211_hw *hw,72				     struct ieee80211_vif *vif)73{74	struct mt7601u_dev *dev = hw->priv;75	struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;76	unsigned int wcid = mvif->group_wcid.idx;77 78	dev->wcid_mask[wcid / BITS_PER_LONG] &= ~BIT(wcid % BITS_PER_LONG);79}80 81static int mt7601u_config(struct ieee80211_hw *hw, u32 changed)82{83	struct mt7601u_dev *dev = hw->priv;84	int ret = 0;85 86	mutex_lock(&dev->mutex);87 88	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {89		ieee80211_stop_queues(hw);90		ret = mt7601u_phy_set_channel(dev, &hw->conf.chandef);91		ieee80211_wake_queues(hw);92	}93 94	mutex_unlock(&dev->mutex);95 96	return ret;97}98 99static void100mt76_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,101		      unsigned int *total_flags, u64 multicast)102{103	struct mt7601u_dev *dev = hw->priv;104	u32 flags = 0;105 106#define MT76_FILTER(_flag, _hw) do { \107		flags |= *total_flags & FIF_##_flag;			\108		dev->rxfilter &= ~(_hw);				\109		dev->rxfilter |= !(flags & FIF_##_flag) * (_hw);	\110	} while (0)111 112	mutex_lock(&dev->mutex);113 114	dev->rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS;115 116	MT76_FILTER(OTHER_BSS, MT_RX_FILTR_CFG_PROMISC);117	MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR);118	MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR);119	MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK |120			     MT_RX_FILTR_CFG_CTS |121			     MT_RX_FILTR_CFG_CFEND |122			     MT_RX_FILTR_CFG_CFACK |123			     MT_RX_FILTR_CFG_BA |124			     MT_RX_FILTR_CFG_CTRL_RSV);125	MT76_FILTER(PSPOLL, MT_RX_FILTR_CFG_PSPOLL);126 127	*total_flags = flags;128	mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter);129 130	mutex_unlock(&dev->mutex);131}132 133static void134mt7601u_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,135			 struct ieee80211_bss_conf *info, u64 changed)136{137	struct mt7601u_dev *dev = hw->priv;138 139	mutex_lock(&dev->mutex);140 141	if (changed & BSS_CHANGED_ASSOC)142		mt7601u_phy_con_cal_onoff(dev, info);143 144	if (changed & BSS_CHANGED_BSSID) {145		mt7601u_addr_wr(dev, MT_MAC_BSSID_DW0, info->bssid);146 147		/* Note: this is a hack because beacon_int is not changed148		 *	 on leave nor is any more appropriate event generated.149		 *	 rt2x00 doesn't seem to be bothered though.150		 */151		if (is_zero_ether_addr(info->bssid))152			mt7601u_mac_config_tsf(dev, false, 0);153	}154 155	if (changed & BSS_CHANGED_BASIC_RATES) {156		mt7601u_wr(dev, MT_LEGACY_BASIC_RATE, info->basic_rates);157		mt7601u_wr(dev, MT_HT_FBK_CFG0, 0x65432100);158		mt7601u_wr(dev, MT_HT_FBK_CFG1, 0xedcba980);159		mt7601u_wr(dev, MT_LG_FBK_CFG0, 0xedcba988);160		mt7601u_wr(dev, MT_LG_FBK_CFG1, 0x00002100);161	}162 163	if (changed & BSS_CHANGED_BEACON_INT)164		mt7601u_mac_config_tsf(dev, true, info->beacon_int);165 166	if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT)167		mt7601u_mac_set_protection(dev, info->use_cts_prot,168					   info->ht_operation_mode);169 170	if (changed & BSS_CHANGED_ERP_PREAMBLE)171		mt7601u_mac_set_short_preamble(dev, info->use_short_preamble);172 173	if (changed & BSS_CHANGED_ERP_SLOT) {174		int slottime = info->use_short_slot ? 9 : 20;175 176		mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG,177			       MT_BKOFF_SLOT_CFG_SLOTTIME, slottime);178	}179 180	if (changed & BSS_CHANGED_ASSOC)181		mt7601u_phy_recalibrate_after_assoc(dev);182 183	mutex_unlock(&dev->mutex);184}185 186static int187mt76_wcid_alloc(struct mt7601u_dev *dev)188{189	int i, idx = 0;190 191	for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) {192		idx = ffs(~dev->wcid_mask[i]);193		if (!idx)194			continue;195 196		idx--;197		dev->wcid_mask[i] |= BIT(idx);198		break;199	}200 201	idx = i * BITS_PER_LONG + idx;202	if (idx > 119)203		return -1;204 205	return idx;206}207 208static int209mt7601u_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,210		struct ieee80211_sta *sta)211{212	struct mt7601u_dev *dev = hw->priv;213	struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;214	struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;215	int ret = 0;216	int idx = 0;217 218	mutex_lock(&dev->mutex);219 220	idx = mt76_wcid_alloc(dev);221	if (idx < 0) {222		ret = -ENOSPC;223		goto out;224	}225 226	msta->wcid.idx = idx;227	msta->wcid.hw_key_idx = -1;228	mt7601u_mac_wcid_setup(dev, idx, mvif->idx, sta->addr);229	mt76_clear(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx));230	rcu_assign_pointer(dev->wcid[idx], &msta->wcid);231	mt7601u_mac_set_ampdu_factor(dev);232 233out:234	mutex_unlock(&dev->mutex);235 236	return ret;237}238 239static int240mt7601u_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,241		   struct ieee80211_sta *sta)242{243	struct mt7601u_dev *dev = hw->priv;244	struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;245	int idx = msta->wcid.idx;246 247	mutex_lock(&dev->mutex);248	rcu_assign_pointer(dev->wcid[idx], NULL);249	mt76_set(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx));250	dev->wcid_mask[idx / BITS_PER_LONG] &= ~BIT(idx % BITS_PER_LONG);251	mt7601u_mac_wcid_setup(dev, idx, 0, NULL);252	mt7601u_mac_set_ampdu_factor(dev);253	mutex_unlock(&dev->mutex);254 255	return 0;256}257 258static void259mt7601u_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,260		   enum sta_notify_cmd cmd, struct ieee80211_sta *sta)261{262}263 264static void265mt7601u_sw_scan(struct ieee80211_hw *hw,266		struct ieee80211_vif *vif,267		const u8 *mac_addr)268{269	struct mt7601u_dev *dev = hw->priv;270 271	mt7601u_agc_save(dev);272	set_bit(MT7601U_STATE_SCANNING, &dev->state);273}274 275static void276mt7601u_sw_scan_complete(struct ieee80211_hw *hw,277			 struct ieee80211_vif *vif)278{279	struct mt7601u_dev *dev = hw->priv;280 281	mt7601u_agc_restore(dev);282	clear_bit(MT7601U_STATE_SCANNING, &dev->state);283 284	ieee80211_queue_delayed_work(dev->hw, &dev->cal_work,285				     MT_CALIBRATE_INTERVAL);286	if (dev->freq_cal.enabled)287		ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work,288					     MT_FREQ_CAL_INIT_DELAY);289}290 291static int292mt7601u_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,293		struct ieee80211_vif *vif, struct ieee80211_sta *sta,294		struct ieee80211_key_conf *key)295{296	struct mt7601u_dev *dev = hw->priv;297	struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;298	struct mt76_sta *msta = sta ? (struct mt76_sta *) sta->drv_priv : NULL;299	struct mt76_wcid *wcid = msta ? &msta->wcid : &mvif->group_wcid;300	int idx = key->keyidx;301	int ret;302 303	/* fall back to sw encryption for unsupported ciphers */304	switch (key->cipher) {305	case WLAN_CIPHER_SUITE_WEP40:306	case WLAN_CIPHER_SUITE_WEP104:307	case WLAN_CIPHER_SUITE_TKIP:308	case WLAN_CIPHER_SUITE_CCMP:309		break;310	default:311		return -EOPNOTSUPP;312	}313 314	if (cmd == SET_KEY) {315		key->hw_key_idx = wcid->idx;316		wcid->hw_key_idx = idx;317	} else {318		if (idx == wcid->hw_key_idx)319			wcid->hw_key_idx = -1;320 321		key = NULL;322	}323 324	if (!msta) {325		if (key || wcid->hw_key_idx == idx) {326			ret = mt76_mac_wcid_set_key(dev, wcid->idx, key);327			if (ret)328				return ret;329		}330 331		return mt76_mac_shared_key_setup(dev, mvif->idx, idx, key);332	}333 334	return mt76_mac_wcid_set_key(dev, msta->wcid.idx, key);335}336 337static int mt7601u_set_rts_threshold(struct ieee80211_hw *hw, u32 value)338{339	struct mt7601u_dev *dev = hw->priv;340 341	mt76_rmw_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH, value);342 343	return 0;344}345 346static int347mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,348		  struct ieee80211_ampdu_params *params)349{350	struct mt7601u_dev *dev = hw->priv;351	struct ieee80211_sta *sta = params->sta;352	enum ieee80211_ampdu_mlme_action action = params->action;353	u16 tid = params->tid;354	u16 ssn = params->ssn;355	struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;356 357	WARN_ON(msta->wcid.idx > GROUP_WCID(0));358 359	switch (action) {360	case IEEE80211_AMPDU_RX_START:361		mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid));362		break;363	case IEEE80211_AMPDU_RX_STOP:364		mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4,365			   BIT(16 + tid));366		break;367	case IEEE80211_AMPDU_TX_OPERATIONAL:368		ieee80211_send_bar(vif, sta->addr, tid, msta->agg_ssn[tid]);369		break;370	case IEEE80211_AMPDU_TX_STOP_FLUSH:371	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:372		break;373	case IEEE80211_AMPDU_TX_START:374		msta->agg_ssn[tid] = ssn << 4;375		return IEEE80211_AMPDU_TX_START_IMMEDIATE;376	case IEEE80211_AMPDU_TX_STOP_CONT:377		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);378		break;379	}380 381	return 0;382}383 384static void385mt76_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif,386			 struct ieee80211_sta *sta)387{388	struct mt7601u_dev *dev = hw->priv;389	struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;390	struct ieee80211_sta_rates *rates;391	struct ieee80211_tx_rate rate = {};392 393	rcu_read_lock();394	rates = rcu_dereference(sta->rates);395 396	if (!rates)397		goto out;398 399	rate.idx = rates->rate[0].idx;400	rate.flags = rates->rate[0].flags;401	mt76_mac_wcid_set_rate(dev, &msta->wcid, &rate);402 403out:404	rcu_read_unlock();405}406 407const struct ieee80211_ops mt7601u_ops = {408	.add_chanctx = ieee80211_emulate_add_chanctx,409	.remove_chanctx = ieee80211_emulate_remove_chanctx,410	.change_chanctx = ieee80211_emulate_change_chanctx,411	.switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx,412	.tx = mt7601u_tx,413	.wake_tx_queue = ieee80211_handle_wake_tx_queue,414	.start = mt7601u_start,415	.stop = mt7601u_stop,416	.add_interface = mt7601u_add_interface,417	.remove_interface = mt7601u_remove_interface,418	.config = mt7601u_config,419	.configure_filter = mt76_configure_filter,420	.bss_info_changed = mt7601u_bss_info_changed,421	.sta_add = mt7601u_sta_add,422	.sta_remove = mt7601u_sta_remove,423	.sta_notify = mt7601u_sta_notify,424	.set_key = mt7601u_set_key,425	.conf_tx = mt7601u_conf_tx,426	.sw_scan_start = mt7601u_sw_scan,427	.sw_scan_complete = mt7601u_sw_scan_complete,428	.ampdu_action = mt76_ampdu_action,429	.sta_rate_tbl_update = mt76_sta_rate_tbl_update,430	.set_rts_threshold = mt7601u_set_rts_threshold,431};432