wifi: mt76: mt7921: introduce chanctx support
Subsystems (2)
[email protected]
reviewerv4 cover wifi: mt76: mt7921: introduce chanctx support
From: Sean Wang <[email protected]>
Update the driver to adapt the new firmware can have the capability to manage the channel context scheduling on multiple roles running on the device including Station, AP and P2P GC/GO mode (will be extended based on the future patchset) to help users sharing the network with others on a single device.
=== v2 ===
(at 1/7)
1. remove unneeded newline
2. squash this one with "wifi: mt76: connac: rely on mt76_connac_mcu_uni_set_chctx"
(at 3/7)
1. remove unneeded newline and use 'u8 rsv' instead of origin one
(at 4/7)
1. drop mt7921_mcu_bss_event that is unused any more
(at 6/7)
1. move mt7921_check_offload_capability prior to ieee80211_alloc_hw and decie what ieee80211_ops instance we should use by the firmware capability bit.
(at 7/7)
1. decide the feature by the firmware capability bit
2. decide the channel by the hardware value in mt7921_get_status_freq_info()
=== v3 ===
(at 6/7)
1. fix mt7921/usb.c:231:7: error: no member named 'ops' in 'struct mt7921_dev'
2. fix mt7921/main.c:425:13: warning: variable 'err' set but not used [-Wunused-but-set-variable]
3. fix mt7921/init.c:173:9: warning: variable 'features' is used uninitialized whenever 'while' loop exits because its condition is false [-Wsometimes-uninitialized]
(at 7/7)
1. enhance the git message
== v4 ===
(at 1/2 and 2/2)
1. reuse mt7921_ops to set up ieee80211 ops for chanctx
2. drop the patch 1/7 to 5/7 as they are being merged
Sean Wang (2):
wifi: mt76: mt7921: introduce remain_on_channel support
wifi: mt76: mt7921: introduce chanctx support
.../net/wireless/mediatek/mt76/mt7921/init.c | 90 ++++++- .../net/wireless/mediatek/mt76/mt7921/mac.c | 8 - .../net/wireless/mediatek/mt76/mt7921/main.c | 223 +++++++++++++++++- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 24 ++ .../wireless/mediatek/mt76/mt7921/mt7921.h | 49 ++++ .../net/wireless/mediatek/mt76/mt7921/pci.c | 40 +++- .../net/wireless/mediatek/mt76/mt7921/sdio.c | 30 ++- .../net/wireless/mediatek/mt76/mt7921/usb.c | 20 +- 8 files changed, 458 insertions(+), 26 deletions(-)
Signature · 1 line
2.25.1
[email protected]
reviewerPATCH v4 2/2 wifi: mt76: mt7921: introduce chanctx support
From: Sean Wang <[email protected]>
The firmware can have the capability to manage the channel context scheduling on multiple roles running on the device including Station, AP and P2P GC/GO mode (will be extended based on the future patchset) to help users sharing the network with others on a single device.
The firmware is able to support the channel chanctx up to 2 interface simultaneously running on the different channels.
Another thing to be noted is that before the driver is going sent out the management frames, the driver has to get the privilege from the firmware to occupy the current channel context until the frame handshake is completed and then get the privilege back to the firmware.
--- .../net/wireless/mediatek/mt76/mt7921/init.c | 33 +++++- .../net/wireless/mediatek/mt76/mt7921/mac.c | 8 -- .../net/wireless/mediatek/mt76/mt7921/main.c | 111 +++++++++++++++++- .../wireless/mediatek/mt76/mt7921/mt7921.h | 1 + .../net/wireless/mediatek/mt76/mt7921/pci.c | 7 ++ .../net/wireless/mediatek/mt76/mt7921/sdio.c | 7 ++ .../net/wireless/mediatek/mt76/mt7921/usb.c | 7 ++ 7 files changed, 157 insertions(+), 17 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7921/init.c +28 -5
@@ -26,6 +26,27 @@ static const struct ieee80211_iface_combination if_comb[] = { .max_interfaces = MT7921_MAX_INTERFACES, .num_different_channels = 1, .beacon_int_infra_match = true, + }, +}; + +static const struct ieee80211_iface_limit if_limits_chanctx[] = { + { + .max =2 , + .types =BIT (NL80211_IFTYPE_STATION ), + }, + { + .max =1 , + .types =BIT (NL80211_IFTYPE_AP ), + } +}; + +static const struct ieee80211_iface_combination if_comb_chanctx[] = { + { + .limits = if_limits_chanctx, + .n_limits =ARRAY_SIZE (if_limits_chanctx), + .max_interfaces =2 , + .num_different_channels =2 , + .beacon_int_infra_match = false, } };
@@ -66,17 +87,19 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) hw->sta_data_size =sizeof (struct mt7921_sta ); hw->vif_data_size =sizeof (struct mt7921_vif ); -if (dev->fw_features &MT7921_FW_CAP_CNM ) +if (dev->fw_features &MT7921_FW_CAP_CNM ) { wiphy->flags |=WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL ; -else + wiphy->iface_combinations = if_comb_chanctx; + wiphy->n_iface_combinations =ARRAY_SIZE (if_comb_chanctx); + }else { wiphy->flags &= ~WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL ; - - wiphy->iface_combinations = if_comb; + wiphy->iface_combinations = if_comb; + wiphy->n_iface_combinations =ARRAY_SIZE (if_comb); + } wiphy->flags &= ~(WIPHY_FLAG_IBSS_RSN |WIPHY_FLAG_4ADDR_AP |WIPHY_FLAG_4ADDR_STATION ); wiphy->interface_modes =BIT (NL80211_IFTYPE_STATION ) |BIT (NL80211_IFTYPE_AP ); - 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_ssids =4 ;
drivers/net/wireless/mediatek/mt76/mt7921/mac.c +0 -8
@@ -168,14 +168,6 @@ static void mt7921_get_status_freq_info(struct mt7921_dev *dev, struct mt76_phy *mphy, struct mt76_rx_status *status, u8 chfreq) { - if (!test_bit(MT76_HW_SCANNING, &mphy->state) && - !test_bit(MT76_HW_SCHED_SCANNING, &mphy->state) && - !test_bit(MT76_STATE_ROC, &mphy->state)) { - status->freq = mphy->chandef.chan->center_freq; - status->band = mphy->chandef.chan->band; -return ; - } - if (chfreq > 180) { status->band = NL80211_BAND_6GHZ; chfreq = (chfreq -181 ) *4 +1 ;
drivers/net/wireless/mediatek/mt76/mt7921/main.c +107 -4
146 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +1 -0
@@ -171,6 +171,7 @@ struct mt7921_vif {struct ewma_rssi rssi;struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS ]; +struct ieee80211_chanctx_conf *ctx; };struct mib_stats {
drivers/net/wireless/mediatek/mt76/mt7921/pci.c +7 -0
@@ -297,6 +297,13 @@ static int mt7921_pci_probe(struct pci_dev *pdev,if (!(features &MT7921_FW_CAP_CNM )) { ops->remain_on_channel =NULL ; ops->cancel_remain_on_channel =NULL ; + ops->add_chanctx =NULL ; + ops->remove_chanctx =NULL ; + ops->change_chanctx =NULL ; + ops->assign_vif_chanctx =NULL ; + ops->unassign_vif_chanctx =NULL ; + ops->mgd_prepare_tx =NULL ; + ops->mgd_complete_tx =NULL ; } mdev =mt76_alloc_device (&pdev->dev,sizeof (*dev), ops, &drv_ops);
drivers/net/wireless/mediatek/mt76/mt7921/sdio.c +7 -0
@@ -140,6 +140,13 @@ static int mt7921s_probe(struct sdio_func *func,if (!(features &MT7921_FW_CAP_CNM )) { ops->remain_on_channel =NULL ; ops->cancel_remain_on_channel =NULL ; + ops->add_chanctx =NULL ; + ops->remove_chanctx =NULL ; + ops->change_chanctx =NULL ; + ops->assign_vif_chanctx =NULL ; + ops->unassign_vif_chanctx =NULL ; + ops->mgd_prepare_tx =NULL ; + ops->mgd_complete_tx =NULL ; } mdev =mt76_alloc_device (&func->dev,sizeof (*dev), ops, &drv_ops);
drivers/net/wireless/mediatek/mt76/mt7921/usb.c +7 -0
@@ -219,6 +219,13 @@ static int mt7921u_probe(struct usb_interface *usb_intf,if (!(features &MT7921_FW_CAP_CNM )) { ops->remain_on_channel =NULL ; ops->cancel_remain_on_channel =NULL ; + ops->add_chanctx =NULL ; + ops->remove_chanctx =NULL ; + ops->change_chanctx =NULL ; + ops->assign_vif_chanctx =NULL ; + ops->unassign_vif_chanctx =NULL ; + ops->mgd_prepare_tx =NULL ; + ops->mgd_complete_tx =NULL ; } ops->stop = mt7921u_stop;
Signature · 1 line
2.25.1
[email protected]
reviewerPATCH v4 1/2 wifi: mt76: mt7921: introduce remain_on_channel support
In reply to [email protected]From: Sean Wang <[email protected]>
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.
--- .../net/wireless/mediatek/mt76/mt7921/init.c | 63 ++++++++++ .../net/wireless/mediatek/mt76/mt7921/main.c | 112 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7921/mcu.c | 24 ++++ .../wireless/mediatek/mt76/mt7921/mt7921.h | 48 ++++++++ .../net/wireless/mediatek/mt76/mt7921/pci.c | 33 ++++-- .../net/wireless/mediatek/mt76/mt7921/sdio.c | 23 +++- .../net/wireless/mediatek/mt76/mt7921/usb.c | 13 +- 7 files changed, 304 insertions(+), 12 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7921/init.c +63 -0
@@ -2,6 +2,7 @@/* Copyright (C) 2020 MediaTek Inc. */ #include <linux/etherdevice.h> +#include <linux/firmware.h> #include "mt7921.h" #include "mac.h" #include "mcu.h"
@@ -65,12 +66,18 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) hw->sta_data_size =sizeof (struct mt7921_sta ); 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->flags &= ~(WIPHY_FLAG_IBSS_RSN |WIPHY_FLAG_4ADDR_AP |WIPHY_FLAG_4ADDR_STATION ); wiphy->interface_modes =BIT (NL80211_IFTYPE_STATION ) |BIT (NL80211_IFTYPE_AP ); 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_ssids =4 ; 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 ); } +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 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->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.stats.last_wake_event = jiffies; dev->pm.stats.last_doze_event = jiffies;
drivers/net/wireless/mediatek/mt76/mt7921/main.c +112 -0
124 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +24 -0
@@ -154,6 +154,29 @@ void mt7921_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)#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 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) {case MCU_UNI_EVENT_ROC : +mt7921_mcu_uni_roc_event (dev, skb);break ;default :break ;
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +48 -0
82 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/pci.c +26 -7
@@ -13,10 +13,14 @@#include "../trace.h" static const struct pci_device_id mt7921_pci_device_table[] = { - {PCI_DEVICE (PCI_VENDOR_ID_MEDIATEK ,0x7961 ) }, - {PCI_DEVICE (PCI_VENDOR_ID_MEDIATEK ,0x7922 ) }, - {PCI_DEVICE (PCI_VENDOR_ID_MEDIATEK ,0x0608 ) }, - {PCI_DEVICE (PCI_VENDOR_ID_MEDIATEK ,0x0616 ) }, + {PCI_DEVICE (PCI_VENDOR_ID_MEDIATEK ,0x7961 ), + .driver_data = (kernel_ulong_t )MT7921_FIRMWARE_WM }, + {PCI_DEVICE (PCI_VENDOR_ID_MEDIATEK ,0x7922 ), + .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, }; +struct ieee80211_ops *ops;struct mt76_bus_ops *bus_ops;struct mt7921_dev *dev;struct mt76_dev *mdev; +u8 features;int ret; ret =pcim_enable_device (pdev);
@@ -279,8 +285,21 @@ static int mt7921_pci_probe(struct pci_dev *pdev,if (mt7921_disable_aspm)mt76_pci_disable_aspm (pdev); - mdev =mt76_alloc_device (&pdev->dev,sizeof (*dev), &mt7921_ops, - &drv_ops); + features =mt7921_check_offload_capability (&pdev->dev, (const char *) + 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) { ret = -ENOMEM ; goto err_free_pci_vec;
@@ -289,8 +308,8 @@ static int mt7921_pci_probe(struct pci_dev *pdev,pci_set_drvdata (pdev, mdev); dev = container_of(mdev, struct mt7921_dev, mt76); + dev->fw_features = features; dev->hif_ops = &mt7921_pcie_ops; -mt76_mmio_init (&dev->mt76,pcim_iomap_table (pdev)[0 ]);tasklet_init (&dev->irq_tasklet, mt7921_irq_tasklet, (unsigned long )dev);
drivers/net/wireless/mediatek/mt76/mt7921/sdio.c +19 -4
@@ -17,7 +17,8 @@#include "mcu.h" 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 */ };
@@ -122,18 +123,32 @@ static int mt7921s_probe(struct sdio_func *func, .fw_own = mt7921s_mcu_fw_pmctrl, }; +struct ieee80211_ops *ops;struct mt7921_dev *dev;struct mt76_dev *mdev; +u8 features;int ret; - mdev =mt76_alloc_device (&func->dev,sizeof (*dev), &mt7921_ops, - &drv_ops); + features =mt7921_check_offload_capability (&func->dev, (const char *) + 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)return -ENOMEM ; dev = container_of(mdev, struct mt7921_dev, mt76); + dev->fw_features = features; dev->hif_ops = &mt7921_sdio_ops; -sdio_set_drvdata (func, dev); ret =mt76s_init (mdev, func, &mt7921s_ops);
drivers/net/wireless/mediatek/mt76/mt7921/usb.c +12 -1
@@ -13,7 +13,8 @@#include "mac.h" 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,22 @@ static int mt7921u_probe(struct usb_interface *usb_intf,struct ieee80211_hw *hw;struct mt7921_dev *dev;struct mt76_dev *mdev; +const void *ops_src; +u8 features;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),GFP_KERNEL );if (!ops)return -ENOMEM ; +if (!(features &MT7921_FW_CAP_CNM )) { + ops->remain_on_channel =NULL ; + ops->cancel_remain_on_channel =NULL ; + } + ops->stop = mt7921u_stop; mdev =mt76_alloc_device (&usb_intf->dev,sizeof (*dev), ops, &drv_ops);
@@ -218,6 +228,7 @@ static int mt7921u_probe(struct usb_interface *usb_intf,return -ENOMEM ; dev = container_of(mdev, struct mt7921_dev, mt76); + dev->fw_features = features; dev->hif_ops = &hif_ops; udev =usb_get_dev (udev);
Signature · 1 line
2.25.1