diff options
author | Lorenzo Bianconi <lorenzo.bianconi@redhat.com> | 2018-07-31 10:09:20 +0200 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2018-08-02 21:48:17 +0300 |
commit | ee676cd5017c5f71b8aac1f2d1016ba0f6e4f348 (patch) | |
tree | 0c39299ed9e70d11166b8ddd3a2babcc6b388e98 /drivers/net/wireless/mediatek/mt76/mt76x2u_main.c | |
parent | b40b15e1521f7764ea8c68d5a00ecc971b673d21 (diff) | |
download | talos-op-linux-ee676cd5017c5f71b8aac1f2d1016ba0f6e4f348.tar.gz talos-op-linux-ee676cd5017c5f71b8aac1f2d1016ba0f6e4f348.zip |
mt76: add driver code for MT76x2u based devices
MT76x2u is a 2x2 USB 802.11ac chipset by MediaTek. This driver currently
support station mode
Tested-by: <cug_yangyuancong@hotmail.com>
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt76x2u_main.c')
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt76x2u_main.c | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c new file mode 100644 index 000000000000..7367ba111119 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt76x2u_main.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> + * + * 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 "mt76x2u.h" + +static int mt76x2u_start(struct ieee80211_hw *hw) +{ + struct mt76x2_dev *dev = hw->priv; + int ret; + + mutex_lock(&dev->mutex); + + ret = mt76x2u_mac_start(dev); + if (ret) + goto out; + + set_bit(MT76_STATE_RUNNING, &dev->mt76.state); + +out: + mutex_unlock(&dev->mutex); + return ret; +} + +static void mt76x2u_stop(struct ieee80211_hw *hw) +{ + struct mt76x2_dev *dev = hw->priv; + + mutex_lock(&dev->mutex); + clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); + mt76x2u_stop_hw(dev); + mutex_unlock(&dev->mutex); +} + +static int mt76x2u_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt76x2_dev *dev = hw->priv; + struct mt76x2_vif *mvif = (struct mt76x2_vif *)vif->drv_priv; + unsigned int idx = 0; + + if (!ether_addr_equal(dev->mt76.macaddr, vif->addr)) + mt76x2u_mac_setaddr(dev, vif->addr); + + mvif->idx = idx; + mvif->group_wcid.idx = MT_VIF_WCID(idx); + mvif->group_wcid.hw_key_idx = -1; + mt76x2_txq_init(dev, vif->txq); + + return 0; +} + +static int +mt76x2u_set_channel(struct mt76x2_dev *dev, + struct cfg80211_chan_def *chandef) +{ + int err; + + cancel_delayed_work_sync(&dev->cal_work); + set_bit(MT76_RESET, &dev->mt76.state); + + mt76_set_channel(&dev->mt76); + + mt76_clear(dev, MT_TXOP_CTRL_CFG, BIT(20)); + mt76_clear(dev, MT_TXOP_HLDR_ET, BIT(1)); + mt76x2_mac_stop(dev, false); + + err = mt76x2u_phy_set_channel(dev, chandef); + + mt76x2u_mac_resume(dev); + + clear_bit(MT76_RESET, &dev->mt76.state); + mt76_txq_schedule_all(&dev->mt76); + + return err; +} + +static void +mt76x2u_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, u32 changed) +{ + struct mt76x2_dev *dev = hw->priv; + + mutex_lock(&dev->mutex); + + if (changed & BSS_CHANGED_ASSOC) { + mt76x2u_phy_channel_calibrate(dev); + mt76x2_apply_gain_adj(dev); + } + + if (changed & BSS_CHANGED_BSSID) { + mt76_wr(dev, MT_MAC_BSSID_DW0, + get_unaligned_le32(info->bssid)); + mt76_wr(dev, MT_MAC_BSSID_DW1, + get_unaligned_le16(info->bssid + 4)); + } + + mutex_unlock(&dev->mutex); +} + +static int +mt76x2u_config(struct ieee80211_hw *hw, u32 changed) +{ + struct mt76x2_dev *dev = hw->priv; + int err = 0; + + mutex_lock(&dev->mutex); + + if (changed & IEEE80211_CONF_CHANGE_MONITOR) { + if (!(hw->conf.flags & IEEE80211_CONF_MONITOR)) + dev->rxfilter |= MT_RX_FILTR_CFG_PROMISC; + else + dev->rxfilter &= ~MT_RX_FILTR_CFG_PROMISC; + mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); + } + + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + ieee80211_stop_queues(hw); + err = mt76x2u_set_channel(dev, &hw->conf.chandef); + ieee80211_wake_queues(hw); + } + + if (changed & IEEE80211_CONF_CHANGE_POWER) { + dev->txpower_conf = hw->conf.power_level * 2; + + /* convert to per-chain power for 2x2 devices */ + dev->txpower_conf -= 6; + + if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) + mt76x2_phy_set_txpower(dev); + } + + mutex_unlock(&dev->mutex); + + return err; +} + +static void +mt76x2u_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + const u8 *mac) +{ + struct mt76x2_dev *dev = hw->priv; + + set_bit(MT76_SCANNING, &dev->mt76.state); +} + +static void +mt76x2u_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt76x2_dev *dev = hw->priv; + + clear_bit(MT76_SCANNING, &dev->mt76.state); +} + +const struct ieee80211_ops mt76x2u_ops = { + .tx = mt76x2_tx, + .start = mt76x2u_start, + .stop = mt76x2u_stop, + .add_interface = mt76x2u_add_interface, + .remove_interface = mt76x2_remove_interface, + .sta_add = mt76x2_sta_add, + .sta_remove = mt76x2_sta_remove, + .set_key = mt76x2_set_key, + .ampdu_action = mt76x2_ampdu_action, + .config = mt76x2u_config, + .wake_tx_queue = mt76_wake_tx_queue, + .bss_info_changed = mt76x2u_bss_info_changed, + .configure_filter = mt76x2_configure_filter, + .conf_tx = mt76x2_conf_tx, + .sw_scan_start = mt76x2u_sw_scan, + .sw_scan_complete = mt76x2u_sw_scan_complete, + .sta_rate_tbl_update = mt76x2_sta_rate_tbl_update, +}; |