mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 18:09:56 +00:00
wifi: mt76: mt7921: introduce remain_on_channel support
Introduce remain_on_channel support. Additionally, we add mt7921_check_offload_capability to disable .remain_on_channel and .cancel_remain_on_channel and related configuration because those operations would rely on the fundamental MCU commands that will be only supported with newer firmware. Co-developed-by: Deren Wu <deren.wu@mediatek.com> Signed-off-by: Deren Wu <deren.wu@mediatek.com> Signed-off-by: Sean Wang <sean.wang@mediatek.com> Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
/* Copyright (C) 2020 MediaTek Inc. */
|
/* Copyright (C) 2020 MediaTek Inc. */
|
||||||
|
|
||||||
#include <linux/etherdevice.h>
|
#include <linux/etherdevice.h>
|
||||||
|
#include <linux/firmware.h>
|
||||||
#include "mt7921.h"
|
#include "mt7921.h"
|
||||||
#include "mac.h"
|
#include "mac.h"
|
||||||
#include "mcu.h"
|
#include "mcu.h"
|
||||||
@@ -65,12 +66,18 @@ mt7921_init_wiphy(struct ieee80211_hw *hw)
|
|||||||
hw->sta_data_size = sizeof(struct mt7921_sta);
|
hw->sta_data_size = sizeof(struct mt7921_sta);
|
||||||
hw->vif_data_size = sizeof(struct mt7921_vif);
|
hw->vif_data_size = sizeof(struct mt7921_vif);
|
||||||
|
|
||||||
|
if (dev->fw_features & MT7921_FW_CAP_CNM)
|
||||||
|
wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
|
||||||
|
else
|
||||||
|
wiphy->flags &= ~WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
|
||||||
|
|
||||||
wiphy->iface_combinations = if_comb;
|
wiphy->iface_combinations = if_comb;
|
||||||
wiphy->flags &= ~(WIPHY_FLAG_IBSS_RSN | WIPHY_FLAG_4ADDR_AP |
|
wiphy->flags &= ~(WIPHY_FLAG_IBSS_RSN | WIPHY_FLAG_4ADDR_AP |
|
||||||
WIPHY_FLAG_4ADDR_STATION);
|
WIPHY_FLAG_4ADDR_STATION);
|
||||||
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
||||||
BIT(NL80211_IFTYPE_AP);
|
BIT(NL80211_IFTYPE_AP);
|
||||||
wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
|
wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
|
||||||
|
wiphy->max_remain_on_channel_duration = 5000;
|
||||||
wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN;
|
wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN;
|
||||||
wiphy->max_scan_ssids = 4;
|
wiphy->max_scan_ssids = 4;
|
||||||
wiphy->max_sched_scan_plan_interval =
|
wiphy->max_sched_scan_plan_interval =
|
||||||
@@ -129,6 +136,58 @@ mt7921_mac_init_band(struct mt7921_dev *dev, u8 band)
|
|||||||
mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN);
|
mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u8 mt7921_check_offload_capability(struct device *dev, const char *fw_wm)
|
||||||
|
{
|
||||||
|
struct mt7921_fw_features *features = NULL;
|
||||||
|
const struct mt76_connac2_fw_trailer *hdr;
|
||||||
|
struct mt7921_realease_info *rel_info;
|
||||||
|
const struct firmware *fw;
|
||||||
|
int ret, i, offset = 0;
|
||||||
|
const u8 *data, *end;
|
||||||
|
|
||||||
|
ret = request_firmware(&fw, fw_wm, dev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
|
||||||
|
dev_err(dev, "Invalid firmware\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = fw->data;
|
||||||
|
hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));
|
||||||
|
|
||||||
|
for (i = 0; i < hdr->n_region; i++) {
|
||||||
|
const struct mt76_connac2_fw_region *region;
|
||||||
|
|
||||||
|
region = (const void *)((const u8 *)hdr -
|
||||||
|
(hdr->n_region - i) * sizeof(*region));
|
||||||
|
offset += le32_to_cpu(region->len);
|
||||||
|
}
|
||||||
|
|
||||||
|
data += offset + 16;
|
||||||
|
rel_info = (struct mt7921_realease_info *)data;
|
||||||
|
data += sizeof(*rel_info);
|
||||||
|
end = data + le16_to_cpu(rel_info->len);
|
||||||
|
|
||||||
|
while (data < end) {
|
||||||
|
rel_info = (struct mt7921_realease_info *)data;
|
||||||
|
data += sizeof(*rel_info);
|
||||||
|
|
||||||
|
if (rel_info->tag == MT7921_FW_TAG_FEATURE) {
|
||||||
|
features = (struct mt7921_fw_features *)data;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
data += le16_to_cpu(rel_info->len) + rel_info->pad_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
release_firmware(fw);
|
||||||
|
|
||||||
|
return features ? features->data : 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mt7921_check_offload_capability);
|
||||||
|
|
||||||
int mt7921_mac_init(struct mt7921_dev *dev)
|
int mt7921_mac_init(struct mt7921_dev *dev)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -278,6 +337,10 @@ int mt7921_register_device(struct mt7921_dev *dev)
|
|||||||
INIT_WORK(&dev->reset_work, mt7921_mac_reset_work);
|
INIT_WORK(&dev->reset_work, mt7921_mac_reset_work);
|
||||||
INIT_WORK(&dev->init_work, mt7921_init_work);
|
INIT_WORK(&dev->init_work, mt7921_init_work);
|
||||||
|
|
||||||
|
INIT_WORK(&dev->phy.roc_work, mt7921_roc_work);
|
||||||
|
timer_setup(&dev->phy.roc_timer, mt7921_roc_timer, 0);
|
||||||
|
init_waitqueue_head(&dev->phy.roc_wait);
|
||||||
|
|
||||||
dev->pm.idle_timeout = MT7921_PM_TIMEOUT;
|
dev->pm.idle_timeout = MT7921_PM_TIMEOUT;
|
||||||
dev->pm.stats.last_wake_event = jiffies;
|
dev->pm.stats.last_wake_event = jiffies;
|
||||||
dev->pm.stats.last_doze_event = jiffies;
|
dev->pm.stats.last_doze_event = jiffies;
|
||||||
|
|||||||
@@ -386,6 +386,116 @@ static void mt7921_remove_interface(struct ieee80211_hw *hw,
|
|||||||
mt76_packet_id_flush(&dev->mt76, &msta->wcid);
|
mt76_packet_id_flush(&dev->mt76, &msta->wcid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mt7921_roc_iter(void *priv, u8 *mac,
|
||||||
|
struct ieee80211_vif *vif)
|
||||||
|
{
|
||||||
|
struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
|
||||||
|
struct mt7921_phy *phy = priv;
|
||||||
|
|
||||||
|
mt7921_mcu_abort_roc(phy, mvif, phy->roc_token_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mt7921_roc_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct mt7921_phy *phy;
|
||||||
|
|
||||||
|
phy = (struct mt7921_phy *)container_of(work, struct mt7921_phy,
|
||||||
|
roc_work);
|
||||||
|
|
||||||
|
if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
|
||||||
|
return;
|
||||||
|
|
||||||
|
mt7921_mutex_acquire(phy->dev);
|
||||||
|
ieee80211_iterate_active_interfaces(phy->mt76->hw,
|
||||||
|
IEEE80211_IFACE_ITER_RESUME_ALL,
|
||||||
|
mt7921_roc_iter, phy);
|
||||||
|
mt7921_mutex_release(phy->dev);
|
||||||
|
ieee80211_remain_on_channel_expired(phy->mt76->hw);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mt7921_roc_timer(struct timer_list *timer)
|
||||||
|
{
|
||||||
|
struct mt7921_phy *phy = from_timer(phy, timer, roc_timer);
|
||||||
|
|
||||||
|
ieee80211_queue_work(phy->mt76->hw, &phy->roc_work);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mt7921_abort_roc(struct mt7921_phy *phy, struct mt7921_vif *vif)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
del_timer_sync(&phy->roc_timer);
|
||||||
|
cancel_work_sync(&phy->roc_work);
|
||||||
|
err = mt7921_mcu_abort_roc(phy, vif, phy->roc_token_id);
|
||||||
|
clear_bit(MT76_STATE_ROC, &phy->mt76->state);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mt7921_set_roc(struct mt7921_phy *phy,
|
||||||
|
struct mt7921_vif *vif,
|
||||||
|
struct ieee80211_channel *chan,
|
||||||
|
int duration,
|
||||||
|
enum mt7921_roc_req type)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state))
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
phy->roc_grant = false;
|
||||||
|
|
||||||
|
err = mt7921_mcu_set_roc(phy, vif, chan, duration, type,
|
||||||
|
++phy->roc_token_id);
|
||||||
|
if (err < 0) {
|
||||||
|
clear_bit(MT76_STATE_ROC, &phy->mt76->state);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wait_event_timeout(phy->roc_wait, phy->roc_grant, HZ)) {
|
||||||
|
mt7921_mcu_abort_roc(phy, vif, phy->roc_token_id);
|
||||||
|
clear_bit(MT76_STATE_ROC, &phy->mt76->state);
|
||||||
|
err = -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mt7921_remain_on_channel(struct ieee80211_hw *hw,
|
||||||
|
struct ieee80211_vif *vif,
|
||||||
|
struct ieee80211_channel *chan,
|
||||||
|
int duration,
|
||||||
|
enum ieee80211_roc_type type)
|
||||||
|
{
|
||||||
|
struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
|
||||||
|
struct mt7921_phy *phy = mt7921_hw_phy(hw);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
mt7921_mutex_acquire(phy->dev);
|
||||||
|
err = mt7921_set_roc(phy, mvif, chan, duration, MT7921_ROC_REQ_ROC);
|
||||||
|
mt7921_mutex_release(phy->dev);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mt7921_cancel_remain_on_channel(struct ieee80211_hw *hw,
|
||||||
|
struct ieee80211_vif *vif)
|
||||||
|
{
|
||||||
|
struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
|
||||||
|
struct mt7921_phy *phy = mt7921_hw_phy(hw);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
mt7921_mutex_acquire(phy->dev);
|
||||||
|
err = mt7921_abort_roc(phy, mvif);
|
||||||
|
mt7921_mutex_release(phy->dev);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int mt7921_set_channel(struct mt7921_phy *phy)
|
static int mt7921_set_channel(struct mt7921_phy *phy)
|
||||||
{
|
{
|
||||||
struct mt7921_dev *dev = phy->dev;
|
struct mt7921_dev *dev = phy->dev;
|
||||||
@@ -1623,6 +1733,8 @@ const struct ieee80211_ops mt7921_ops = {
|
|||||||
#endif /* CONFIG_PM */
|
#endif /* CONFIG_PM */
|
||||||
.flush = mt7921_flush,
|
.flush = mt7921_flush,
|
||||||
.set_sar_specs = mt7921_set_sar_specs,
|
.set_sar_specs = mt7921_set_sar_specs,
|
||||||
|
.remain_on_channel = mt7921_remain_on_channel,
|
||||||
|
.cancel_remain_on_channel = mt7921_cancel_remain_on_channel,
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL_GPL(mt7921_ops);
|
EXPORT_SYMBOL_GPL(mt7921_ops);
|
||||||
|
|
||||||
|
|||||||
@@ -154,6 +154,29 @@ void mt7921_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
|
|||||||
|
|
||||||
#endif /* CONFIG_PM */
|
#endif /* CONFIG_PM */
|
||||||
|
|
||||||
|
static void
|
||||||
|
mt7921_mcu_uni_roc_event(struct mt7921_dev *dev, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct mt7921_roc_grant_tlv *grant;
|
||||||
|
struct mt76_connac2_mcu_rxd *rxd;
|
||||||
|
int duration;
|
||||||
|
|
||||||
|
rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
|
||||||
|
grant = (struct mt7921_roc_grant_tlv *)(rxd->tlv + 4);
|
||||||
|
|
||||||
|
/* should never happen */
|
||||||
|
WARN_ON_ONCE((le16_to_cpu(grant->tag) != UNI_EVENT_ROC_GRANT));
|
||||||
|
|
||||||
|
if (grant->reqtype == MT7921_ROC_REQ_ROC)
|
||||||
|
ieee80211_ready_on_channel(dev->mt76.phy.hw);
|
||||||
|
|
||||||
|
dev->phy.roc_grant = true;
|
||||||
|
wake_up(&dev->phy.roc_wait);
|
||||||
|
duration = le32_to_cpu(grant->max_interval);
|
||||||
|
mod_timer(&dev->phy.roc_timer,
|
||||||
|
round_jiffies_up(jiffies + msecs_to_jiffies(duration)));
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb)
|
mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
@@ -295,6 +318,7 @@ mt7921_mcu_uni_rx_unsolicited_event(struct mt7921_dev *dev,
|
|||||||
|
|
||||||
switch (rxd->eid) {
|
switch (rxd->eid) {
|
||||||
case MCU_UNI_EVENT_ROC:
|
case MCU_UNI_EVENT_ROC:
|
||||||
|
mt7921_mcu_uni_roc_event(dev, skb);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -32,6 +32,9 @@
|
|||||||
#define MT7921_MCU_INIT_RETRY_COUNT 10
|
#define MT7921_MCU_INIT_RETRY_COUNT 10
|
||||||
#define MT7921_WFSYS_INIT_RETRY_COUNT 2
|
#define MT7921_WFSYS_INIT_RETRY_COUNT 2
|
||||||
|
|
||||||
|
#define MT7921_FW_TAG_FEATURE 4
|
||||||
|
#define MT7921_FW_CAP_CNM BIT(7)
|
||||||
|
|
||||||
#define MT7921_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1.bin"
|
#define MT7921_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1.bin"
|
||||||
#define MT7921_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1_2_hdr.bin"
|
#define MT7921_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1_2_hdr.bin"
|
||||||
|
|
||||||
@@ -67,6 +70,41 @@ enum mt7921_roc_req {
|
|||||||
MT7921_ROC_REQ_NUM
|
MT7921_ROC_REQ_NUM
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
UNI_EVENT_ROC_GRANT = 0,
|
||||||
|
UNI_EVENT_ROC_TAG_NUM
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mt7921_realease_info {
|
||||||
|
__le16 len;
|
||||||
|
u8 pad_len;
|
||||||
|
u8 tag;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct mt7921_fw_features {
|
||||||
|
u8 segment;
|
||||||
|
u8 data;
|
||||||
|
u8 rsv[14];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct mt7921_roc_grant_tlv {
|
||||||
|
__le16 tag;
|
||||||
|
__le16 len;
|
||||||
|
u8 bss_idx;
|
||||||
|
u8 tokenid;
|
||||||
|
u8 status;
|
||||||
|
u8 primarychannel;
|
||||||
|
u8 rfsco;
|
||||||
|
u8 rfband;
|
||||||
|
u8 channelwidth;
|
||||||
|
u8 centerfreqseg1;
|
||||||
|
u8 centerfreqseg2;
|
||||||
|
u8 reqtype;
|
||||||
|
u8 dbdcband;
|
||||||
|
u8 rsv[1];
|
||||||
|
__le32 max_interval;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
enum mt7921_sdio_pkt_type {
|
enum mt7921_sdio_pkt_type {
|
||||||
MT7921_SDIO_TXD,
|
MT7921_SDIO_TXD,
|
||||||
MT7921_SDIO_DATA,
|
MT7921_SDIO_DATA,
|
||||||
@@ -214,6 +252,12 @@ struct mt7921_phy {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct mt7921_clc *clc[MT7921_CLC_MAX_NUM];
|
struct mt7921_clc *clc[MT7921_CLC_MAX_NUM];
|
||||||
|
|
||||||
|
struct work_struct roc_work;
|
||||||
|
struct timer_list roc_timer;
|
||||||
|
wait_queue_head_t roc_wait;
|
||||||
|
u8 roc_token_id;
|
||||||
|
bool roc_grant;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define mt7921_init_reset(dev) ((dev)->hif_ops->init_reset(dev))
|
#define mt7921_init_reset(dev) ((dev)->hif_ops->init_reset(dev))
|
||||||
@@ -250,6 +294,7 @@ struct mt7921_dev {
|
|||||||
struct work_struct init_work;
|
struct work_struct init_work;
|
||||||
|
|
||||||
u8 fw_debug;
|
u8 fw_debug;
|
||||||
|
u8 fw_features;
|
||||||
|
|
||||||
struct mt76_connac_pm pm;
|
struct mt76_connac_pm pm;
|
||||||
struct mt76_connac_coredump coredump;
|
struct mt76_connac_coredump coredump;
|
||||||
@@ -439,6 +484,8 @@ int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev,
|
|||||||
struct ieee80211_ampdu_params *params,
|
struct ieee80211_ampdu_params *params,
|
||||||
bool enable);
|
bool enable);
|
||||||
void mt7921_scan_work(struct work_struct *work);
|
void mt7921_scan_work(struct work_struct *work);
|
||||||
|
void mt7921_roc_work(struct work_struct *work);
|
||||||
|
void mt7921_roc_timer(struct timer_list *timer);
|
||||||
int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif);
|
int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif);
|
||||||
int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev);
|
int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev);
|
||||||
int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev);
|
int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev);
|
||||||
@@ -527,4 +574,5 @@ int mt7921_mcu_set_roc(struct mt7921_phy *phy, struct mt7921_vif *vif,
|
|||||||
enum mt7921_roc_req type, u8 token_id);
|
enum mt7921_roc_req type, u8 token_id);
|
||||||
int mt7921_mcu_abort_roc(struct mt7921_phy *phy, struct mt7921_vif *vif,
|
int mt7921_mcu_abort_roc(struct mt7921_phy *phy, struct mt7921_vif *vif,
|
||||||
u8 token_id);
|
u8 token_id);
|
||||||
|
u8 mt7921_check_offload_capability(struct device *dev, const char *fw_wm);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -13,10 +13,14 @@
|
|||||||
#include "../trace.h"
|
#include "../trace.h"
|
||||||
|
|
||||||
static const struct pci_device_id mt7921_pci_device_table[] = {
|
static const struct pci_device_id mt7921_pci_device_table[] = {
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7961) },
|
{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7961),
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7922) },
|
.driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0608) },
|
{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7922),
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0616) },
|
.driver_data = (kernel_ulong_t)MT7922_FIRMWARE_WM },
|
||||||
|
{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0608),
|
||||||
|
.driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM },
|
||||||
|
{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0616),
|
||||||
|
.driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM },
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -253,9 +257,11 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
|
|||||||
.fw_own = mt7921e_mcu_fw_pmctrl,
|
.fw_own = mt7921e_mcu_fw_pmctrl,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ieee80211_ops *ops;
|
||||||
struct mt76_bus_ops *bus_ops;
|
struct mt76_bus_ops *bus_ops;
|
||||||
struct mt7921_dev *dev;
|
struct mt7921_dev *dev;
|
||||||
struct mt76_dev *mdev;
|
struct mt76_dev *mdev;
|
||||||
|
u8 features;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = pcim_enable_device(pdev);
|
ret = pcim_enable_device(pdev);
|
||||||
@@ -279,8 +285,21 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
|
|||||||
if (mt7921_disable_aspm)
|
if (mt7921_disable_aspm)
|
||||||
mt76_pci_disable_aspm(pdev);
|
mt76_pci_disable_aspm(pdev);
|
||||||
|
|
||||||
mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7921_ops,
|
features = mt7921_check_offload_capability(&pdev->dev, (const char *)
|
||||||
&drv_ops);
|
id->driver_data);
|
||||||
|
ops = devm_kmemdup(&pdev->dev, &mt7921_ops, sizeof(mt7921_ops),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!ops) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto err_free_pci_vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(features & MT7921_FW_CAP_CNM)) {
|
||||||
|
ops->remain_on_channel = NULL;
|
||||||
|
ops->cancel_remain_on_channel = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), ops, &drv_ops);
|
||||||
if (!mdev) {
|
if (!mdev) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err_free_pci_vec;
|
goto err_free_pci_vec;
|
||||||
@@ -289,8 +308,8 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
|
|||||||
pci_set_drvdata(pdev, mdev);
|
pci_set_drvdata(pdev, mdev);
|
||||||
|
|
||||||
dev = container_of(mdev, struct mt7921_dev, mt76);
|
dev = container_of(mdev, struct mt7921_dev, mt76);
|
||||||
|
dev->fw_features = features;
|
||||||
dev->hif_ops = &mt7921_pcie_ops;
|
dev->hif_ops = &mt7921_pcie_ops;
|
||||||
|
|
||||||
mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
|
mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
|
||||||
tasklet_init(&dev->irq_tasklet, mt7921_irq_tasklet, (unsigned long)dev);
|
tasklet_init(&dev->irq_tasklet, mt7921_irq_tasklet, (unsigned long)dev);
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,8 @@
|
|||||||
#include "mcu.h"
|
#include "mcu.h"
|
||||||
|
|
||||||
static const struct sdio_device_id mt7921s_table[] = {
|
static const struct sdio_device_id mt7921s_table[] = {
|
||||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7901) },
|
{ SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7901),
|
||||||
|
.driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM },
|
||||||
{ } /* Terminating entry */
|
{ } /* Terminating entry */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -122,18 +123,32 @@ static int mt7921s_probe(struct sdio_func *func,
|
|||||||
.fw_own = mt7921s_mcu_fw_pmctrl,
|
.fw_own = mt7921s_mcu_fw_pmctrl,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ieee80211_ops *ops;
|
||||||
struct mt7921_dev *dev;
|
struct mt7921_dev *dev;
|
||||||
struct mt76_dev *mdev;
|
struct mt76_dev *mdev;
|
||||||
|
u8 features;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
mdev = mt76_alloc_device(&func->dev, sizeof(*dev), &mt7921_ops,
|
features = mt7921_check_offload_capability(&func->dev, (const char *)
|
||||||
&drv_ops);
|
id->driver_data);
|
||||||
|
|
||||||
|
ops = devm_kmemdup(&func->dev, &mt7921_ops, sizeof(mt7921_ops),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!ops)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (!(features & MT7921_FW_CAP_CNM)) {
|
||||||
|
ops->remain_on_channel = NULL;
|
||||||
|
ops->cancel_remain_on_channel = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mdev = mt76_alloc_device(&func->dev, sizeof(*dev), ops, &drv_ops);
|
||||||
if (!mdev)
|
if (!mdev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
dev = container_of(mdev, struct mt7921_dev, mt76);
|
dev = container_of(mdev, struct mt7921_dev, mt76);
|
||||||
|
dev->fw_features = features;
|
||||||
dev->hif_ops = &mt7921_sdio_ops;
|
dev->hif_ops = &mt7921_sdio_ops;
|
||||||
|
|
||||||
sdio_set_drvdata(func, dev);
|
sdio_set_drvdata(func, dev);
|
||||||
|
|
||||||
ret = mt76s_init(mdev, func, &mt7921s_ops);
|
ret = mt76s_init(mdev, func, &mt7921s_ops);
|
||||||
|
|||||||
@@ -13,7 +13,8 @@
|
|||||||
#include "mac.h"
|
#include "mac.h"
|
||||||
|
|
||||||
static const struct usb_device_id mt7921u_device_table[] = {
|
static const struct usb_device_id mt7921u_device_table[] = {
|
||||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7961, 0xff, 0xff, 0xff) },
|
{ USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7961, 0xff, 0xff, 0xff),
|
||||||
|
.driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM },
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -204,13 +205,21 @@ static int mt7921u_probe(struct usb_interface *usb_intf,
|
|||||||
struct ieee80211_hw *hw;
|
struct ieee80211_hw *hw;
|
||||||
struct mt7921_dev *dev;
|
struct mt7921_dev *dev;
|
||||||
struct mt76_dev *mdev;
|
struct mt76_dev *mdev;
|
||||||
|
u8 features;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
features = mt7921_check_offload_capability(&usb_intf->dev, (const char *)
|
||||||
|
id->driver_info);
|
||||||
ops = devm_kmemdup(&usb_intf->dev, &mt7921_ops, sizeof(mt7921_ops),
|
ops = devm_kmemdup(&usb_intf->dev, &mt7921_ops, sizeof(mt7921_ops),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!ops)
|
if (!ops)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (!(features & MT7921_FW_CAP_CNM)) {
|
||||||
|
ops->remain_on_channel = NULL;
|
||||||
|
ops->cancel_remain_on_channel = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
ops->stop = mt7921u_stop;
|
ops->stop = mt7921u_stop;
|
||||||
|
|
||||||
mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), ops, &drv_ops);
|
mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), ops, &drv_ops);
|
||||||
@@ -218,6 +227,7 @@ static int mt7921u_probe(struct usb_interface *usb_intf,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
dev = container_of(mdev, struct mt7921_dev, mt76);
|
dev = container_of(mdev, struct mt7921_dev, mt76);
|
||||||
|
dev->fw_features = features;
|
||||||
dev->hif_ops = &hif_ops;
|
dev->hif_ops = &hif_ops;
|
||||||
|
|
||||||
udev = usb_get_dev(udev);
|
udev = usb_get_dev(udev);
|
||||||
|
|||||||
Reference in New Issue
Block a user