From 06662264ce2ad6810af4233424d501036a273223 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 30 Jan 2019 17:02:13 +0100 Subject: [PATCH 01/43] mt76x02: use mask for vifs Use vif_mask to count interfaces to allow to set mac address in HW if there is only one interface and report error if we create interface with wrong BSSID resulting in already used index. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index 6d96766a6ed3..be077443bdb0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -73,6 +73,8 @@ struct mt76x02_dev { struct mutex phy_mutex; + u16 vif_mask; + u8 txdone_seq; DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x02_tx_status); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 062614ad0d51..c9340096c187 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -309,6 +309,15 @@ mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) if (vif->type == NL80211_IFTYPE_STATION) idx += 8; + if (dev->vif_mask & BIT(idx)) + return -EBUSY; + + /* Allow to change address in HW if we create first interface. */ + if (!dev->vif_mask && !ether_addr_equal(dev->mt76.macaddr, vif->addr)) + mt76x02_mac_setaddr(dev, vif->addr); + + dev->vif_mask |= BIT(idx); + mt76x02_vif_init(dev, vif, idx); return 0; } @@ -318,8 +327,10 @@ void mt76x02_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt76x02_dev *dev = hw->priv; + struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; mt76_txq_remove(&dev->mt76, vif->txq); + dev->vif_mask &= ~BIT(mvif->idx); } EXPORT_SYMBOL_GPL(mt76x02_remove_interface); From f9a043c582193cc6e2ab26ac36630432a4521508 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 30 Jan 2019 17:02:14 +0100 Subject: [PATCH 02/43] mt76x02: use commmon add interface for mt76x2u Since we now support mt76x2u feature to allow set mac address when creating interface in common code we can use it for mt76x2u. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02.h | 3 +-- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 6 +++--- .../net/wireless/mediatek/mt76/mt76x2/usb_main.c | 15 +-------------- 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index be077443bdb0..6d9d9ddacc32 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -130,8 +130,7 @@ void mt76x02_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void mt76x02_config_mac_addr_list(struct mt76x02_dev *dev); -void mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif, - unsigned int idx); + int mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void mt76x02_remove_interface(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index c9340096c187..18434b06e706 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -268,8 +268,9 @@ void mt76x02_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt76x02_sta_remove); -void mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif, - unsigned int idx) +static void +mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif, + unsigned int idx) { struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; struct mt76_txq *mtxq; @@ -282,7 +283,6 @@ void mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif, mt76_txq_init(&dev->mt76, vif->txq); } -EXPORT_SYMBOL_GPL(mt76x02_vif_init); int mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c index 286c7f451090..5256c6f879a7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -46,19 +46,6 @@ static void mt76x2u_stop(struct ieee80211_hw *hw) mutex_unlock(&dev->mt76.mutex); } -static int mt76x2u_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct mt76x02_dev *dev = hw->priv; - unsigned int idx = 8; - - if (!ether_addr_equal(dev->mt76.macaddr, vif->addr)) - mt76x02_mac_setaddr(dev, vif->addr); - - mt76x02_vif_init(dev, vif, idx); - return 0; -} - static int mt76x2u_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) @@ -125,7 +112,7 @@ const struct ieee80211_ops mt76x2u_ops = { .tx = mt76x02_tx, .start = mt76x2u_start, .stop = mt76x2u_stop, - .add_interface = mt76x2u_add_interface, + .add_interface = mt76x02_add_interface, .remove_interface = mt76x02_remove_interface, .sta_state = mt76_sta_state, .set_key = mt76x02_set_key, From 0b2d27e5b82c78ac98a1106b3387910c643ee09c Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 30 Jan 2019 17:02:15 +0100 Subject: [PATCH 03/43] mt76x02: initialize mutli bss mode when set up address BSSID is not strtirct related with beaconing (for example we can have 2 STA vifs) and more related with MAC address, so initaize BSSID when setting MAC address. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 15 ++++++++++++++- drivers/net/wireless/mediatek/mt76/mt76x02_mac.h | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 13 ++----------- .../net/wireless/mediatek/mt76/mt76x2/pci_init.c | 4 +--- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 63fa27d2c404..ae1727e433f3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -548,8 +548,11 @@ mt76x02_mac_process_rate(struct mt76x02_dev *dev, return 0; } -void mt76x02_mac_setaddr(struct mt76x02_dev *dev, u8 *addr) +void mt76x02_mac_setaddr(struct mt76x02_dev *dev, const u8 *addr) { + static const u8 null_addr[ETH_ALEN] = {}; + int i; + ether_addr_copy(dev->mt76.macaddr, addr); if (!is_valid_ether_addr(dev->mt76.macaddr)) { @@ -563,6 +566,16 @@ void mt76x02_mac_setaddr(struct mt76x02_dev *dev, u8 *addr) mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dev->mt76.macaddr + 4) | FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff)); + + mt76_wr(dev, MT_MAC_BSSID_DW0, + get_unaligned_le32(dev->mt76.macaddr)); + mt76_wr(dev, MT_MAC_BSSID_DW1, + get_unaligned_le16(dev->mt76.macaddr + 4) | + FIELD_PREP(MT_MAC_BSSID_DW1_MBSS_MODE, 3) | /* 8 APs + 8 STAs */ + MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT); + + for (i = 0; i < 16; i++) + mt76x02_mac_set_bssid(dev, i, null_addr); } EXPORT_SYMBOL_GPL(mt76x02_mac_setaddr); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 940c07f665cd..76e564b8f5da 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -191,7 +191,7 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, void mt76x02_mac_set_tx_protection(struct mt76x02_dev *dev, bool legacy_prot, int ht_mode); void mt76x02_mac_set_rts_thresh(struct mt76x02_dev *dev, u32 val); -void mt76x02_mac_setaddr(struct mt76x02_dev *dev, u8 *addr); +void mt76x02_mac_setaddr(struct mt76x02_dev *dev, const u8 *addr); void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int len); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 18434b06e706..1ecd4ef83c82 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -668,16 +668,8 @@ static void mt76x02_set_beacon_offsets(struct mt76x02_dev *dev) void mt76x02_init_beacon_config(struct mt76x02_dev *dev) { - static const u8 null_addr[ETH_ALEN] = {}; int i; - mt76_wr(dev, MT_MAC_BSSID_DW0, - get_unaligned_le32(dev->mt76.macaddr)); - mt76_wr(dev, MT_MAC_BSSID_DW1, - get_unaligned_le16(dev->mt76.macaddr + 4) | - FIELD_PREP(MT_MAC_BSSID_DW1_MBSS_MODE, 3) | /* 8 beacons */ - MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT); - /* Fire a pre-TBTT interrupt 8 ms before TBTT */ mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_PRE_TBTT, 8 << 4); @@ -687,10 +679,9 @@ void mt76x02_init_beacon_config(struct mt76x02_dev *dev) mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xffff); - for (i = 0; i < 8; i++) { - mt76x02_mac_set_bssid(dev, i, null_addr); + for (i = 0; i < 8; i++) mt76x02_mac_set_beacon(dev, i, NULL); - } + mt76x02_set_beacon_offsets(dev); } EXPORT_SYMBOL_GPL(mt76x02_init_beacon_config); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 4347d5e7a915..0ccaa64d97ec 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -119,9 +119,7 @@ static int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard) mt76_wr(dev, MT_MCU_CLOCK_CTL, 0x1401); mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN); - mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(macaddr)); - mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(macaddr + 4)); - + mt76x02_mac_setaddr(dev, macaddr); mt76x02_init_beacon_config(dev); if (!hard) return 0; From 39834c1293ca6bfd1456b8d0063e7bd76f94eaf1 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 30 Jan 2019 17:02:16 +0100 Subject: [PATCH 04/43] mt76x02: minor beaconing init changes Disable BEACON timer during init and configure interrupt registers only for mmio devices. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x02_util.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 1ecd4ef83c82..4bc0520da1c6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -670,13 +670,19 @@ void mt76x02_init_beacon_config(struct mt76x02_dev *dev) { int i; - /* Fire a pre-TBTT interrupt 8 ms before TBTT */ - mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_PRE_TBTT, - 8 << 4); - mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_GP_TIMER, - MT_DFS_GP_INTERVAL); - mt76_wr(dev, MT_INT_TIMER_EN, 0); + if (mt76_is_mmio(dev)) { + /* Fire a pre-TBTT interrupt 8 ms before TBTT */ + mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_PRE_TBTT, + 8 << 4); + mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_GP_TIMER, + MT_DFS_GP_INTERVAL); + mt76_wr(dev, MT_INT_TIMER_EN, 0); + } + mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN | + MT_BEACON_TIME_CFG_SYNC_MODE | + MT_BEACON_TIME_CFG_TBTT_EN | + MT_BEACON_TIME_CFG_BEACON_TX)); mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xffff); for (i = 0; i < 8; i++) From b08ca4dc95bf3605335c0c7fdcfd8be62f3b08b1 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 30 Jan 2019 17:02:17 +0100 Subject: [PATCH 05/43] mt76x02: init beacon config for mt76x2u Initialize beaconing also on mt76x2u. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index 0be3784f44fb..3737e9fa8295 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -207,11 +207,7 @@ int mt76x2u_init_hardware(struct mt76x02_dev *dev) mt76x02_mac_shared_key_setup(dev, i, k, NULL); } - mt76_clear(dev, MT_BEACON_TIME_CFG, - MT_BEACON_TIME_CFG_TIMER_EN | - MT_BEACON_TIME_CFG_SYNC_MODE | - MT_BEACON_TIME_CFG_TBTT_EN | - MT_BEACON_TIME_CFG_BEACON_TX); + mt76x02_init_beacon_config(dev); mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e); mt76_wr(dev, MT_TXOP_CTRL_CFG, 0x583f); From dbb2b22b11cc085e088d37cdc65764b9668e8c3f Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 30 Jan 2019 17:02:18 +0100 Subject: [PATCH 06/43] mt76: beaconing fixes for USB Configure beaconing on USB devices without PS buffering support. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 29 +++++++++++++++++-- .../net/wireless/mediatek/mt76/mt76x02_mac.h | 4 +-- .../net/wireless/mediatek/mt76/mt76x02_util.c | 8 ++--- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index ae1727e433f3..2dc80ea26752 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -1060,8 +1060,9 @@ int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, return 0; } -void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, - u8 vif_idx, bool val) +static void +__mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, u8 vif_idx, + bool val, struct sk_buff *skb) { u8 old_mask = dev->beacon_mask; bool en; @@ -1069,6 +1070,8 @@ void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, if (val) { dev->beacon_mask |= BIT(vif_idx); + if (skb) + mt76x02_mac_set_beacon(dev, vif_idx, skb); } else { dev->beacon_mask &= ~BIT(vif_idx); mt76x02_mac_set_beacon(dev, vif_idx, NULL); @@ -1079,14 +1082,34 @@ void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, en = dev->beacon_mask; - mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_PRE_TBTT_EN, en); reg = MT_BEACON_TIME_CFG_BEACON_TX | MT_BEACON_TIME_CFG_TBTT_EN | MT_BEACON_TIME_CFG_TIMER_EN; mt76_rmw(dev, MT_BEACON_TIME_CFG, reg, reg * en); + if (mt76_is_usb(dev)) + return; + + mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_PRE_TBTT_EN, en); if (en) mt76x02_irq_enable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT); else mt76x02_irq_disable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT); } + +void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, + struct ieee80211_vif *vif, bool val) +{ + u8 vif_idx = ((struct mt76x02_vif *)vif->drv_priv)->idx; + struct sk_buff *skb = NULL; + + if (mt76_is_mmio(dev)) + tasklet_disable(&dev->pre_tbtt_tasklet); + else if (val) + skb = ieee80211_beacon_get(mt76_hw(dev), vif); + + __mt76x02_mac_set_beacon_enable(dev, vif_idx, val, skb); + + if (mt76_is_mmio(dev)) + tasklet_enable(&dev->pre_tbtt_tasklet); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 76e564b8f5da..3b04b1bd0abd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -204,8 +204,8 @@ void mt76x02_mac_work(struct work_struct *work); void mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr); int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, struct sk_buff *skb); -void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, u8 vif_idx, - bool val); +void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, + struct ieee80211_vif *vif, bool val); void mt76x02_edcca_init(struct mt76x02_dev *dev); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 4bc0520da1c6..724b13d91898 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -705,12 +705,8 @@ void mt76x02_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BSSID) mt76x02_mac_set_bssid(dev, mvif->idx, info->bssid); - if (changed & BSS_CHANGED_BEACON_ENABLED) { - tasklet_disable(&dev->pre_tbtt_tasklet); - mt76x02_mac_set_beacon_enable(dev, mvif->idx, - info->enable_beacon); - tasklet_enable(&dev->pre_tbtt_tasklet); - } + if (changed & BSS_CHANGED_BEACON_ENABLED) + mt76x02_mac_set_beacon_enable(dev, vif, info->enable_beacon); if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) mt76x02_mac_set_tx_protection(dev, info->use_cts_prot, From 2bd7f3d2a93a20448e5c68eacbc925c4594640b4 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 30 Jan 2019 17:02:19 +0100 Subject: [PATCH 07/43] mt76x02: enable support for IBSS and MESH Since we implement beconing on USB now, similar interfaces should be supported for USB as are for MMIO. Tested only on IBSS mode and AP mode (not enabled due to lack of PS buffering). Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x02_util.c | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 724b13d91898..87ed00768bc7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -140,10 +140,16 @@ void mt76x02_init_device(struct mt76x02_dev *dev) hw->max_rate_tries = 1; hw->extra_tx_headroom = 2; + wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_ADHOC); + if (mt76_is_usb(dev)) { hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN; - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); } else { INIT_DELAYED_WORK(&dev->wdt_work, mt76x02_wdt_work); @@ -152,18 +158,9 @@ void mt76x02_init_device(struct mt76x02_dev *dev) wiphy->reg_notifier = mt76x02_regd_notifier; wiphy->iface_combinations = mt76x02_if_comb; wiphy->n_iface_combinations = ARRAY_SIZE(mt76x02_if_comb); - wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP) | -#ifdef CONFIG_MAC80211_MESH - BIT(NL80211_IFTYPE_MESH_POINT) | -#endif - BIT(NL80211_IFTYPE_ADHOC); - + wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; - wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); - /* init led callbacks */ if (IS_ENABLED(CONFIG_MT76_LEDS)) { dev->mt76.led_cdev.brightness_set = @@ -172,6 +169,8 @@ void mt76x02_init_device(struct mt76x02_dev *dev) } } + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); + hw->sta_data_size = sizeof(struct mt76x02_sta); hw->vif_data_size = sizeof(struct mt76x02_vif); From b29e46b76552c2b1a76344602a0bcdc8ba8629da Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 5 Feb 2019 15:06:34 +0100 Subject: [PATCH 08/43] mt76x0: eeprom: fix VHT mcs{8,9} rate power offset Fix rate power configuration for VHT mcs 8 and 9 in mt76x0_get_tx_power_per_rate. Moreover use the rate power offset used for HT/VHT mcs 6 even for HT/VHT mcs 7 Fixes: b37bbc8c8251 ("mt76x0: remove eeprom dependency from mt76x0_set_tx_power_per_rate") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index b2cabce1d74d..64f96567bae9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -189,7 +189,7 @@ void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev) addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 8 : 0x126; val = mt76x02_eeprom_get(dev, addr); t->ht[4] = t->ht[5] = t->vht[4] = t->vht[5] = s6_to_s8(val); - t->ht[6] = t->vht[6] = s6_to_s8(val >> 8); + t->ht[6] = t->ht[7] = t->vht[6] = t->vht[7] = s6_to_s8(val >> 8); /* ht-vht mcs 1ss 0, 1, 2, 3 stbc */ addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 14 : 0xec; @@ -205,8 +205,8 @@ void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev) /* vht mcs 8, 9 5GHz */ val = mt76x02_eeprom_get(dev, 0x132); - t->vht[7] = s6_to_s8(val); - t->vht[8] = s6_to_s8(val >> 8); + t->vht[8] = s6_to_s8(val); + t->vht[9] = s6_to_s8(val >> 8); delta = mt76x0_tssi_enabled(dev) ? 0 : mt76x0_get_delta(dev); mt76x02_add_rate_power_offset(t, delta); From 9df0fab9d1cad3cbdd47683e5b4f3c7c09a91bd3 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 4 Feb 2019 17:51:27 +0100 Subject: [PATCH 09/43] mt76: move mt76_mcu_msg_alloc in mt76-core Move mt76_mcu_msg_alloc in mt76-core module and remove duplicated code. mt76_mcu_msg_alloc will be reused adding support for mt7603 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Makefile | 3 +- drivers/net/wireless/mediatek/mt76/mcu.c | 36 +++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 4 +++ .../net/wireless/mediatek/mt76/mt76x02_mcu.c | 12 ------- .../net/wireless/mediatek/mt76/mt76x02_mcu.h | 6 ++++ .../wireless/mediatek/mt76/mt76x02_usb_mcu.c | 17 +-------- 6 files changed, 49 insertions(+), 29 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mcu.c diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index 1a45cb30f39f..fa7a44edd02d 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -4,7 +4,8 @@ obj-$(CONFIG_MT76x02_LIB) += mt76x02-lib.o obj-$(CONFIG_MT76x02_USB) += mt76x02-usb.o mt76-y := \ - mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o tx.o agg-rx.o + mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \ + tx.o agg-rx.o mcu.o mt76-usb-y := usb.o usb_trace.o usb_mcu.o diff --git a/drivers/net/wireless/mediatek/mt76/mcu.c b/drivers/net/wireless/mediatek/mt76/mcu.c new file mode 100644 index 000000000000..f4c38ec78654 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mcu.c @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2019 Lorenzo Bianconi + * + * 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 "mt76.h" + +struct sk_buff * +mt76_mcu_msg_alloc(const void *data, int head_len, + int data_len, int tail_len) +{ + struct sk_buff *skb; + + skb = alloc_skb(head_len + data_len + tail_len, + GFP_KERNEL); + if (!skb) + return NULL; + + skb_reserve(skb, head_len); + if (data && data_len) + skb_put_data(skb, data, data_len); + + return skb; +} +EXPORT_SYMBOL_GPL(mt76_mcu_msg_alloc); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 2bb9db4ed80a..155d981d1328 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -751,6 +751,10 @@ void mt76u_stop_queues(struct mt76_dev *dev); void mt76u_stop_stat_wk(struct mt76_dev *dev); void mt76u_queues_deinit(struct mt76_dev *dev); +struct sk_buff * +mt76_mcu_msg_alloc(const void *data, int head_len, + int data_len, int tail_len); + void mt76u_mcu_complete_urb(struct urb *urb); int mt76u_mcu_init_rx(struct mt76_dev *dev); void mt76u_mcu_deinit(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c index b7f4edb729e3..d184551b9845 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c @@ -21,18 +21,6 @@ #include "mt76x02_mcu.h" -static struct sk_buff *mt76x02_mcu_msg_alloc(const void *data, int len) -{ - struct sk_buff *skb; - - skb = alloc_skb(len, GFP_KERNEL); - if (!skb) - return NULL; - memcpy(skb_put(skb, len), data, len); - - return skb; -} - static struct sk_buff * mt76x02_mcu_get_response(struct mt76x02_dev *dev, unsigned long expires) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h index 7e4004120102..a7b0d3e5df1d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h @@ -96,6 +96,12 @@ struct mt76x02_patch_header { u8 pad[2]; }; +static inline struct sk_buff * +mt76x02_mcu_msg_alloc(const void *data, int len) +{ + return mt76_mcu_msg_alloc(data, 0, len, 0); +} + int mt76x02_mcu_cleanup(struct mt76x02_dev *dev); int mt76x02_mcu_calibrate(struct mt76x02_dev *dev, int type, u32 param); int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c index 6db789f90269..ff070f8fbc61 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c @@ -28,21 +28,6 @@ #define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8 -static struct sk_buff * -mt76x02u_mcu_msg_alloc(const void *data, int len) -{ - struct sk_buff *skb; - - skb = alloc_skb(MT_CMD_HDR_LEN + len + 8, GFP_KERNEL); - if (!skb) - return NULL; - - skb_reserve(skb, MT_CMD_HDR_LEN); - skb_put_data(skb, data, len); - - return skb; -} - static void mt76x02u_multiple_mcu_reads(struct mt76_dev *dev, u8 *data, int len) { @@ -166,7 +151,7 @@ mt76x02u_mcu_send_msg(struct mt76_dev *dev, int cmd, const void *data, struct sk_buff *skb; int err; - skb = mt76x02u_mcu_msg_alloc(data, len); + skb = mt76_mcu_msg_alloc(data, MT_CMD_HDR_LEN, len, 8); if (!skb) return -ENOMEM; From 680abb25f71caf3871c8619bee3bbc3818dcd3a7 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 4 Feb 2019 17:51:28 +0100 Subject: [PATCH 10/43] mt76: move mt76_mcu_get_response in mt76-core Move mt76_mcu_get_response in mt76-core module and remove duplicated code. mt76_mcu_get_response will be reused adding support for mt7603 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mcu.c | 17 +++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 2 ++ .../net/wireless/mediatek/mt76/mt76x02_mcu.c | 17 +---------------- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mcu.c b/drivers/net/wireless/mediatek/mt76/mcu.c index f4c38ec78654..0fd71a97a197 100644 --- a/drivers/net/wireless/mediatek/mt76/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mcu.c @@ -34,3 +34,20 @@ mt76_mcu_msg_alloc(const void *data, int head_len, return skb; } EXPORT_SYMBOL_GPL(mt76_mcu_msg_alloc); + +/* mmio */ +struct sk_buff *mt76_mcu_get_response(struct mt76_dev *dev, + unsigned long expires) +{ + unsigned long timeout; + + if (!time_is_after_jiffies(expires)) + return NULL; + + timeout = expires - jiffies; + wait_event_timeout(dev->mmio.mcu.wait, + !skb_queue_empty(&dev->mmio.mcu.res_q), + timeout); + return skb_dequeue(&dev->mmio.mcu.res_q); +} +EXPORT_SYMBOL_GPL(mt76_mcu_get_response); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 155d981d1328..534e418c6d80 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -754,6 +754,8 @@ void mt76u_queues_deinit(struct mt76_dev *dev); struct sk_buff * mt76_mcu_msg_alloc(const void *data, int head_len, int data_len, int tail_len); +struct sk_buff *mt76_mcu_get_response(struct mt76_dev *dev, + unsigned long expires); void mt76u_mcu_complete_urb(struct urb *urb); int mt76u_mcu_init_rx(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c index d184551b9845..b44d128f6f93 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c @@ -21,21 +21,6 @@ #include "mt76x02_mcu.h" -static struct sk_buff * -mt76x02_mcu_get_response(struct mt76x02_dev *dev, unsigned long expires) -{ - unsigned long timeout; - - if (!time_is_after_jiffies(expires)) - return NULL; - - timeout = expires - jiffies; - wait_event_timeout(dev->mt76.mmio.mcu.wait, - !skb_queue_empty(&dev->mt76.mmio.mcu.res_q), - timeout); - return skb_dequeue(&dev->mt76.mmio.mcu.res_q); -} - static int mt76x02_tx_queue_mcu(struct mt76x02_dev *dev, enum mt76_txq_id qid, struct sk_buff *skb, int cmd, int seq) @@ -94,7 +79,7 @@ int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, u32 *rxfce; bool check_seq = false; - skb = mt76x02_mcu_get_response(dev, expires); + skb = mt76_mcu_get_response(&dev->mt76, expires); if (!skb) { dev_err(mdev->dev, "MCU message %d (seq %d) timed out\n", cmd, From c07a49d475b427e33d15780364bdeb64507d338a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 4 Feb 2019 17:51:29 +0100 Subject: [PATCH 11/43] mt76: move mt76_mcu_rx_event in mt76-core Move mt76_mcu_rx_event i mt76-core module and remove duplicated code. mt76_mcu_rx_event will be reused adding support for mt7603 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mcu.c | 7 +++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c | 3 +-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mcu.c b/drivers/net/wireless/mediatek/mt76/mcu.c index 0fd71a97a197..dbb57b593a87 100644 --- a/drivers/net/wireless/mediatek/mt76/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mcu.c @@ -51,3 +51,10 @@ struct sk_buff *mt76_mcu_get_response(struct mt76_dev *dev, return skb_dequeue(&dev->mmio.mcu.res_q); } EXPORT_SYMBOL_GPL(mt76_mcu_get_response); + +void mt76_mcu_rx_event(struct mt76_dev *dev, struct sk_buff *skb) +{ + skb_queue_tail(&dev->mmio.mcu.res_q, skb); + wake_up(&dev->mmio.mcu.wait); +} +EXPORT_SYMBOL_GPL(mt76_mcu_rx_event); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 534e418c6d80..a6cc9a2ff97e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -754,6 +754,7 @@ void mt76u_queues_deinit(struct mt76_dev *dev); struct sk_buff * mt76_mcu_msg_alloc(const void *data, int head_len, int data_len, int tail_len); +void mt76_mcu_rx_event(struct mt76_dev *dev, struct sk_buff *skb); struct sk_buff *mt76_mcu_get_response(struct mt76_dev *dev, unsigned long expires); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c index a5413a309a0a..7861a832940b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c @@ -58,8 +58,7 @@ void mt76x02_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, if (q == MT_RXQ_MCU) { /* this is used just by mmio code */ - skb_queue_tail(&mdev->mmio.mcu.res_q, skb); - wake_up(&mdev->mmio.mcu.wait); + mt76_mcu_rx_event(&dev->mt76, skb); return; } From 6f02aeabc9c5113f56828742ace975f91d5b9470 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 5 Feb 2019 16:52:25 +0100 Subject: [PATCH 12/43] mt76x0: mcu: remove useless commented configuration Remove useless commented out configuration in mt76x0u_load_firmware routine Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c index f391d2d21fbc..4a282761ca58 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c @@ -140,12 +140,6 @@ static int mt76x0u_load_firmware(struct mt76x02_dev *dev) FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20)); mt76x02u_mcu_fw_reset(dev); usleep_range(5000, 6000); -/* - mt76x0_rmw(dev, MT_PBF_CFG, 0, (MT_PBF_CFG_TX0Q_EN | - MT_PBF_CFG_TX1Q_EN | - MT_PBF_CFG_TX2Q_EN | - MT_PBF_CFG_TX3Q_EN)); -*/ mt76_wr(dev, MT_FCE_PSE_CTRL, 1); From 5ed31128782cbb2a687a3d958473aa5bd05ff2fb Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 7 Feb 2019 11:10:57 +0100 Subject: [PATCH 13/43] mt76: move mt76_dma_tx_queue_skb_raw in mt76-core module Move mt76_dma_tx_queue_skb_raw routine in dma.c and add the corresponding entry in mt76_queue_ops data structure. mt76_dma_tx_queue_skb_raw will be reused adding support for mt7603 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 25 ++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 4 ++ .../net/wireless/mediatek/mt76/mt76x02_mcu.c | 40 ++++--------------- 3 files changed, 37 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index e769c8a555dd..ac1da2ee01a6 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -242,6 +242,30 @@ mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q) iowrite32(q->head, &q->regs->cpu_idx); } +static int +mt76_dma_tx_queue_skb_raw(struct mt76_dev *dev, enum mt76_txq_id qid, + struct sk_buff *skb, u32 tx_info) +{ + struct mt76_queue *q = &dev->q_tx[qid]; + struct mt76_queue_buf buf; + dma_addr_t addr; + + addr = dma_map_single(dev->dev, skb->data, skb->len, + DMA_TO_DEVICE); + if (dma_mapping_error(dev->dev, addr)) + return -ENOMEM; + + buf.addr = addr; + buf.len = skb->len; + + spin_lock_bh(&q->lock); + mt76_dma_add_buf(dev, q, &buf, 1, tx_info, skb, NULL); + mt76_dma_kick_queue(dev, q); + spin_unlock_bh(&q->lock); + + return 0; +} + int mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta) @@ -523,6 +547,7 @@ static const struct mt76_queue_ops mt76_dma_ops = { .init = mt76_dma_init, .alloc = mt76_dma_alloc_queue, .add_buf = mt76_dma_add_buf, + .tx_queue_skb_raw = mt76_dma_tx_queue_skb_raw, .tx_queue_skb = mt76_dma_tx_queue_skb, .tx_cleanup = mt76_dma_tx_cleanup, .rx_reset = mt76_dma_rx_reset, diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index a6cc9a2ff97e..1d761b45a172 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -157,6 +157,9 @@ struct mt76_queue_ops { struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta); + int (*tx_queue_skb_raw)(struct mt76_dev *dev, enum mt76_txq_id qid, + struct sk_buff *skb, u32 tx_info); + void *(*dequeue)(struct mt76_dev *dev, struct mt76_queue *q, bool flush, int *len, u32 *info, bool *more); @@ -563,6 +566,7 @@ static inline u16 mt76_rev(struct mt76_dev *dev) #define mt76_init_queues(dev) (dev)->mt76.queue_ops->init(&((dev)->mt76)) #define mt76_queue_alloc(dev, ...) (dev)->mt76.queue_ops->alloc(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_add_buf(dev, ...) (dev)->mt76.queue_ops->add_buf(&((dev)->mt76), __VA_ARGS__) +#define mt76_tx_queue_skb_raw(dev, ...) (dev)->mt76.queue_ops->tx_queue_skb_raw(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_rx_reset(dev, ...) (dev)->mt76.queue_ops->rx_reset(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_kick(dev, ...) (dev)->mt76.queue_ops->kick(&((dev)->mt76), __VA_ARGS__) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c index b44d128f6f93..4752c104abf3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c @@ -21,43 +21,13 @@ #include "mt76x02_mcu.h" -static int -mt76x02_tx_queue_mcu(struct mt76x02_dev *dev, enum mt76_txq_id qid, - struct sk_buff *skb, int cmd, int seq) -{ - struct mt76_queue *q = &dev->mt76.q_tx[qid]; - struct mt76_queue_buf buf; - dma_addr_t addr; - u32 tx_info; - - tx_info = MT_MCU_MSG_TYPE_CMD | - FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) | - FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) | - FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) | - FIELD_PREP(MT_MCU_MSG_LEN, skb->len); - - addr = dma_map_single(dev->mt76.dev, skb->data, skb->len, - DMA_TO_DEVICE); - if (dma_mapping_error(dev->mt76.dev, addr)) - return -ENOMEM; - - buf.addr = addr; - buf.len = skb->len; - - spin_lock_bh(&q->lock); - mt76_queue_add_buf(dev, q, &buf, 1, tx_info, skb, NULL); - mt76_queue_kick(dev, q); - spin_unlock_bh(&q->lock); - - return 0; -} - int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, int len, bool wait_resp) { struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); unsigned long expires = jiffies + HZ; struct sk_buff *skb; + u32 tx_info; int ret; u8 seq; @@ -71,7 +41,13 @@ int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, if (!seq) seq = ++mdev->mmio.mcu.msg_seq & 0xf; - ret = mt76x02_tx_queue_mcu(dev, MT_TXQ_MCU, skb, cmd, seq); + tx_info = MT_MCU_MSG_TYPE_CMD | + FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) | + FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) | + FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) | + FIELD_PREP(MT_MCU_MSG_LEN, skb->len); + + ret = mt76_tx_queue_skb_raw(dev, MT_TXQ_MCU, skb, tx_info); if (ret) goto out; From e6287c337c30a1e7f3e697887534a75b1713a538 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 7 Feb 2019 11:14:34 +0100 Subject: [PATCH 14/43] mt76: remove add_buf pointer in mt76_queue_ops Remove add_buf function pointer in mt76_queue_ops data structure since it is no longer used Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 1 - drivers/net/wireless/mediatek/mt76/mt76.h | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index ac1da2ee01a6..bfbfc0c2ec29 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -546,7 +546,6 @@ mt76_dma_init(struct mt76_dev *dev) static const struct mt76_queue_ops mt76_dma_ops = { .init = mt76_dma_init, .alloc = mt76_dma_alloc_queue, - .add_buf = mt76_dma_add_buf, .tx_queue_skb_raw = mt76_dma_tx_queue_skb_raw, .tx_queue_skb = mt76_dma_tx_queue_skb, .tx_cleanup = mt76_dma_tx_cleanup, diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 1d761b45a172..3894d72d4016 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -565,7 +565,6 @@ static inline u16 mt76_rev(struct mt76_dev *dev) #define mt76_init_queues(dev) (dev)->mt76.queue_ops->init(&((dev)->mt76)) #define mt76_queue_alloc(dev, ...) (dev)->mt76.queue_ops->alloc(&((dev)->mt76), __VA_ARGS__) -#define mt76_queue_add_buf(dev, ...) (dev)->mt76.queue_ops->add_buf(&((dev)->mt76), __VA_ARGS__) #define mt76_tx_queue_skb_raw(dev, ...) (dev)->mt76.queue_ops->tx_queue_skb_raw(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_rx_reset(dev, ...) (dev)->mt76.queue_ops->rx_reset(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__) From 128b75bf5cf93bca71da740d3cb623c1febb6bf6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 31 Jan 2019 21:01:24 +0100 Subject: [PATCH 15/43] mt76: fix software encryption issues Software encrypted packets can be passed not just through the drv_tx callback, but also through the intermediate tx queue. In order to deal with that, move the override to mt76x02_mac_write_txwi and also take care of filling in the per-packet rate information Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 7 +++++++ drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c | 9 +-------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 2dc80ea26752..6bd7f87644a4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -291,6 +291,13 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, memset(txwi, 0, sizeof(*txwi)); + if (!info->control.hw_key && wcid && wcid->hw_key_idx != 0xff && + ieee80211_has_protected(hdr->frame_control)) { + wcid = NULL; + ieee80211_get_tx_rates(info->control.vif, sta, skb, + info->control.rates, 1); + } + if (wcid) txwi->wcid = wcid->idx; else diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c index 7861a832940b..94f47248c59f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c @@ -22,7 +22,6 @@ void mt76x02_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct mt76x02_dev *dev = hw->priv; struct ieee80211_vif *vif = info->control.vif; @@ -33,13 +32,7 @@ void mt76x02_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, msta = (struct mt76x02_sta *)control->sta->drv_priv; wcid = &msta->wcid; - /* sw encrypted frames */ - if (!info->control.hw_key && wcid->hw_key_idx != 0xff && - ieee80211_has_protected(hdr->frame_control)) - control->sta = NULL; - } - - if (vif && !control->sta) { + } else if (vif) { struct mt76x02_vif *mvif; mvif = (struct mt76x02_vif *)vif->drv_priv; From 1564fa92fbf92abdc5bb82c006956826718ced5e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 3 Feb 2019 13:52:12 +0100 Subject: [PATCH 16/43] mt76: mt76x2: avoid running DPD calibration if tx is blocked Doing so could lead to hangs Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2/phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c index e2ee5e498da7..1848e8ab2e21 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c @@ -241,7 +241,7 @@ void mt76x2_phy_tssi_compensate(struct mt76x02_dev *dev) t.offset1 = txp.chain[1].tssi_offset; mt76x2_mcu_tssi_comp(dev, &t); - if (t.pa_mode || dev->cal.dpd_cal_done) + if (t.pa_mode || dev->cal.dpd_cal_done || dev->ed_tx_blocked) return; usleep_range(10000, 20000); From 20c06572c1910f2735cb8cc1fd5d413824a387ae Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 3 Feb 2019 13:59:06 +0100 Subject: [PATCH 17/43] mt76: explicitly disable energy detect cca during scan Avoid reusing the previous channel's tx blocking state Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 6 ++++-- drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76x02_mac.h | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c | 6 ++++-- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 1117cdc15b04..cb70b04d38a5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -1006,14 +1006,16 @@ int mt76x0_phy_set_channel(struct mt76x02_dev *dev, /* enable vco */ mt76x0_rf_set(dev, MT_RF(0, 4), BIT(7)); - if (scan) + if (scan) { + mt76x02_edcca_init(dev, false); return 0; + } mt76x02_init_agc_gain(dev); mt76x0_phy_calibrate(dev, false); mt76x0_phy_set_txpower(dev); - mt76x02_edcca_init(dev); + mt76x02_edcca_init(dev, true); ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, MT_CALIBRATE_INTERVAL); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c index 19fdcab746a0..e4649103efd4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c @@ -886,7 +886,7 @@ mt76x02_dfs_set_domain(struct mt76x02_dev *dev, tasklet_disable(&dfs_pd->dfs_tasklet); dev->ed_monitor = region == NL80211_DFS_ETSI; - mt76x02_edcca_init(dev); + mt76x02_edcca_init(dev, true); dfs_pd->region = region; mt76x02_dfs_init_params(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 6bd7f87644a4..636e69a7a407 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -891,12 +891,12 @@ mt76x02_edcca_tx_enable(struct mt76x02_dev *dev, bool enable) dev->ed_tx_blocked = !enable; } -void mt76x02_edcca_init(struct mt76x02_dev *dev) +void mt76x02_edcca_init(struct mt76x02_dev *dev, bool enable) { dev->ed_trigger = 0; dev->ed_silent = 0; - if (dev->ed_monitor) { + if (dev->ed_monitor && enable) { struct ieee80211_channel *chan = dev->mt76.chandef.chan; u8 ed_th = chan->band == NL80211_BAND_5GHZ ? 0x0e : 0x20; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 3b04b1bd0abd..6b1f25d2f64c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -207,5 +207,5 @@ int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, struct ieee80211_vif *vif, bool val); -void mt76x02_edcca_init(struct mt76x02_dev *dev); +void mt76x02_edcca_init(struct mt76x02_dev *dev, bool enable); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c index 65ed62229a5b..97ec575699d0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c @@ -240,8 +240,10 @@ int mt76x2_phy_set_channel(struct mt76x02_dev *dev, mt76_wr(dev, MT_BBP(AGC, 2), 0x00007070); mt76_wr(dev, MT_TXOP_CTRL_CFG, 0x04101B3F); - if (scan) + if (scan) { + mt76x02_edcca_init(dev, false); return 0; + } mt76x2_phy_channel_calibrate(dev, true); mt76x02_init_agc_gain(dev); @@ -254,7 +256,7 @@ int mt76x2_phy_set_channel(struct mt76x02_dev *dev, 0x38); } - mt76x02_edcca_init(dev); + mt76x02_edcca_init(dev, true); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work, MT_CALIBRATE_INTERVAL); From 2e4050240a6ba96b95c778b6710fbdfadac0ba2e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 3 Feb 2019 14:13:06 +0100 Subject: [PATCH 18/43] mt76: run MAC work every 100ms ED/CCA Tx blocking checks need to be run every 100 ms in order to avoid triggering too late and keeping tx blocking on for too long Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 1472c8699b29..6992b3d7dfec 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -30,7 +30,7 @@ static int mt76x0e_start(struct ieee80211_hw *hw) mt76x02_mac_start(dev); mt76x0_phy_calibrate(dev, true); ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work, - MT_CALIBRATE_INTERVAL); + MT_MAC_WORK_INTERVAL); ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, MT_CALIBRATE_INTERVAL); set_bit(MT76_STATE_RUNNING, &dev->mt76.state); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 3987adaaf2bd..91d8afd9a0ed 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -118,7 +118,7 @@ static int mt76x0u_start(struct ieee80211_hw *hw) mt76x0_phy_calibrate(dev, true); ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work, - MT_CALIBRATE_INTERVAL); + MT_MAC_WORK_INTERVAL); ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, MT_CALIBRATE_INTERVAL); set_bit(MT76_STATE_RUNNING, &dev->mt76.state); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index 6d9d9ddacc32..7e405297028f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -27,6 +27,7 @@ #include "mt76x02_dma.h" #define MT_CALIBRATE_INTERVAL HZ +#define MT_MAC_WORK_INTERVAL (HZ / 10) #define MT_WATCHDOG_TIME (HZ / 10) #define MT_TX_HANG_TH 10 diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 636e69a7a407..89c7368cbd52 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -929,7 +929,7 @@ static void mt76x02_edcca_check(struct mt76x02_dev *dev) u32 val, busy; val = mt76_rr(dev, MT_ED_CCA_TIMER); - busy = (val * 100) / jiffies_to_usecs(MT_CALIBRATE_INTERVAL); + busy = (val * 100) / jiffies_to_usecs(MT_MAC_WORK_INTERVAL); busy = min_t(u32, busy, 100); if (busy > MT_EDCCA_TH) { @@ -975,7 +975,7 @@ void mt76x02_mac_work(struct work_struct *work) mt76_tx_status_check(&dev->mt76, NULL, false); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work, - MT_CALIBRATE_INTERVAL); + MT_MAC_WORK_INTERVAL); } void mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index 06a26a152ba4..878ce92405ed 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -33,7 +33,7 @@ mt76x2_start(struct ieee80211_hw *hw) goto out; ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work, - MT_CALIBRATE_INTERVAL); + MT_MAC_WORK_INTERVAL); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->wdt_work, MT_WATCHDOG_TIME); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c index 5256c6f879a7..10633b8de8e8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -28,7 +28,7 @@ static int mt76x2u_start(struct ieee80211_hw *hw) goto out; ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work, - MT_CALIBRATE_INTERVAL); + MT_MAC_WORK_INTERVAL); set_bit(MT76_STATE_RUNNING, &dev->mt76.state); out: From c15b7cef2af8ea2dfac61af5f4f2b27aaed8d7e6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 3 Feb 2019 14:15:58 +0100 Subject: [PATCH 19/43] mt76: clear CCA timer stats in mt76x02_edcca_init Avoid triggering too early Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 89c7368cbd52..aecf514bb89b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -919,6 +919,9 @@ void mt76x02_edcca_init(struct mt76x02_dev *dev, bool enable) } } mt76x02_edcca_tx_enable(dev, true); + + /* clear previous CCA timer value */ + mt76_rr(dev, MT_ED_CCA_TIMER); } EXPORT_SYMBOL_GPL(mt76x02_edcca_init); From ccdaf7b4f22f50dcd1e0af39f3712677195b8351 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 3 Feb 2019 14:41:22 +0100 Subject: [PATCH 20/43] mt76: measure the time between mt76x02_edcca_check runs Based on system load and time needed by other calibration runs, the time between dev->mac_work runs can vary quite a bit. Calculate busy time based on the actual time difference in order to avoid potentially over-estimating busy time, which could lead to unnecessary tx blocking. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index 7e405297028f..3464b4ca2ea8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -117,6 +117,7 @@ struct mt76x02_dev { bool ed_monitor; u8 ed_trigger; u8 ed_silent; + ktime_t ed_time; }; extern struct ieee80211_rate mt76x02_rates[12]; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index aecf514bb89b..462ac030c08a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -922,6 +922,7 @@ void mt76x02_edcca_init(struct mt76x02_dev *dev, bool enable) /* clear previous CCA timer value */ mt76_rr(dev, MT_ED_CCA_TIMER); + dev->ed_time = ktime_get_boottime(); } EXPORT_SYMBOL_GPL(mt76x02_edcca_init); @@ -929,10 +930,16 @@ EXPORT_SYMBOL_GPL(mt76x02_edcca_init); #define MT_EDCCA_BLOCK_TH 2 static void mt76x02_edcca_check(struct mt76x02_dev *dev) { - u32 val, busy; + ktime_t cur_time; + u32 active, val, busy; + cur_time = ktime_get_boottime(); val = mt76_rr(dev, MT_ED_CCA_TIMER); - busy = (val * 100) / jiffies_to_usecs(MT_MAC_WORK_INTERVAL); + + active = ktime_to_us(ktime_sub(cur_time, dev->ed_time)); + dev->ed_time = cur_time; + + busy = (val * 100) / active; busy = min_t(u32, busy, 100); if (busy > MT_EDCCA_TH) { From f1906fb24901460fdc0ba7c8bbfe416fb705c8a6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 3 Feb 2019 20:35:31 +0100 Subject: [PATCH 21/43] mt76: increase ED/CCA tx block threshold Block only when the busy time reaches 92%, as lower values can be reached with heavy 802.11 traffic as well. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 462ac030c08a..bf39624c9b98 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -926,7 +926,7 @@ void mt76x02_edcca_init(struct mt76x02_dev *dev, bool enable) } EXPORT_SYMBOL_GPL(mt76x02_edcca_init); -#define MT_EDCCA_TH 90 +#define MT_EDCCA_TH 92 #define MT_EDCCA_BLOCK_TH 2 static void mt76x02_edcca_check(struct mt76x02_dev *dev) { From c0f7b25ab8d33adbead530dfc54b999fb69d5ede Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 31 Jan 2019 17:55:54 +0100 Subject: [PATCH 22/43] mt76: move alloc_device common code in mt76_alloc_device Move mt76x{0,2} alloc_device common code in mt76_alloc_device and remove duplicated code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 7 ++++++- drivers/net/wireless/mediatek/mt76/mt76.h | 5 +++-- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 5 +---- drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c | 5 ++--- drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c | 5 ++--- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index ee3b65a14870..c7abf4f54867 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -269,7 +269,9 @@ mt76_check_sband(struct mt76_dev *dev, int band) } struct mt76_dev * -mt76_alloc_device(unsigned int size, const struct ieee80211_ops *ops) +mt76_alloc_device(struct device *pdev, unsigned int size, + const struct ieee80211_ops *ops, + const struct mt76_driver_ops *drv_ops) { struct ieee80211_hw *hw; struct mt76_dev *dev; @@ -280,6 +282,9 @@ mt76_alloc_device(unsigned int size, const struct ieee80211_ops *ops) dev = hw->priv; dev->hw = hw; + dev->dev = pdev; + dev->drv = drv_ops; + spin_lock_init(&dev->rx_lock); spin_lock_init(&dev->lock); spin_lock_init(&dev->cc_lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 3894d72d4016..e9cc108e60d3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -585,8 +585,9 @@ mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c) return &msband->chan[idx]; } -struct mt76_dev *mt76_alloc_device(unsigned int size, - const struct ieee80211_ops *ops); +struct mt76_dev *mt76_alloc_device(struct device *pdev, unsigned int size, + const struct ieee80211_ops *ops, + const struct mt76_driver_ops *drv_ops); int mt76_register_device(struct mt76_dev *dev, bool vht, struct ieee80211_rate *rates, int n_rates); void mt76_unregister_device(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 87b575fe1c74..34db3ec24e6e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -270,13 +270,10 @@ mt76x0_alloc_device(struct device *pdev, struct mt76x02_dev *dev; struct mt76_dev *mdev; - mdev = mt76_alloc_device(sizeof(*dev), ops); + mdev = mt76_alloc_device(pdev, sizeof(*dev), ops, drv_ops); if (!mdev) return NULL; - mdev->dev = pdev; - mdev->drv = drv_ops; - dev = container_of(mdev, struct mt76x02_dev, mt76); mutex_init(&dev->phy_mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 0ccaa64d97ec..d5816c7f359f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -329,13 +329,12 @@ struct mt76x02_dev *mt76x2_alloc_device(struct device *pdev) struct mt76x02_dev *dev; struct mt76_dev *mdev; - mdev = mt76_alloc_device(sizeof(*dev), &mt76x2_ops); + mdev = mt76_alloc_device(pdev, sizeof(*dev), &mt76x2_ops, + &drv_ops); if (!mdev) return NULL; dev = container_of(mdev, struct mt76x02_dev, mt76); - mdev->dev = pdev; - mdev->drv = &drv_ops; return dev; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index 3737e9fa8295..11ce106391e1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -147,13 +147,12 @@ struct mt76x02_dev *mt76x2u_alloc_device(struct device *pdev) struct mt76x02_dev *dev; struct mt76_dev *mdev; - mdev = mt76_alloc_device(sizeof(*dev), &mt76x2u_ops); + mdev = mt76_alloc_device(pdev, sizeof(*dev), &mt76x2u_ops, + &drv_ops); if (!mdev) return NULL; dev = container_of(mdev, struct mt76x02_dev, mt76); - mdev->dev = pdev; - mdev->drv = &drv_ops; return dev; } From 3bfaa974de302cb453999d94a3fd22269fe9b293 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 31 Jan 2019 17:55:55 +0100 Subject: [PATCH 23/43] mt76x2u: remove mt76x2u_alloc_device routine Remove mt76x2u_alloc_device since it just runs mt76_alloc_device. Move mt76_alloc_device call in mt76x2u_probe Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x2/mt76x2u.h | 1 - .../net/wireless/mediatek/mt76/mt76x2/usb.c | 24 ++++++++++++++----- .../wireless/mediatek/mt76/mt76x2/usb_init.c | 23 ------------------ 3 files changed, 18 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h index 0b0075411b34..787cdfdf5db5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h @@ -29,7 +29,6 @@ extern const struct ieee80211_ops mt76x2u_ops; -struct mt76x02_dev *mt76x2u_alloc_device(struct device *pdev); int mt76x2u_register_device(struct mt76x02_dev *dev); int mt76x2u_init_hardware(struct mt76x02_dev *dev); void mt76x2u_cleanup(struct mt76x02_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index 4d1788eb3812..f81a85e96922 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -36,24 +36,36 @@ static const struct usb_device_id mt76x2u_device_table[] = { static int mt76x2u_probe(struct usb_interface *intf, const struct usb_device_id *id) { + static const struct mt76_driver_ops drv_ops = { + .tx_prepare_skb = mt76x02u_tx_prepare_skb, + .tx_complete_skb = mt76x02u_tx_complete_skb, + .tx_status_data = mt76x02_tx_status_data, + .rx_skb = mt76x02_queue_rx_skb, + .sta_add = mt76x02_sta_add, + .sta_remove = mt76x02_sta_remove, + }; struct usb_device *udev = interface_to_usbdev(intf); struct mt76x02_dev *dev; + struct mt76_dev *mdev; int err; - dev = mt76x2u_alloc_device(&intf->dev); - if (!dev) + mdev = mt76_alloc_device(&intf->dev, sizeof(*dev), &mt76x2u_ops, + &drv_ops); + if (!mdev) return -ENOMEM; + dev = container_of(mdev, struct mt76x02_dev, mt76); + udev = usb_get_dev(udev); usb_reset_device(udev); - mt76x02u_init_mcu(&dev->mt76); - err = mt76u_init(&dev->mt76, intf); + mt76x02u_init_mcu(mdev); + err = mt76u_init(mdev, intf); if (err < 0) goto err; - dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION); - dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev); + mdev->rev = mt76_rr(dev, MT_ASIC_VERSION); + dev_info(mdev->dev, "ASIC revision: %08x\n", mdev->rev); err = mt76x2u_register_device(dev); if (err < 0) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index 11ce106391e1..006e430e374e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -134,29 +134,6 @@ static int mt76x2u_init_eeprom(struct mt76x02_dev *dev) return 0; } -struct mt76x02_dev *mt76x2u_alloc_device(struct device *pdev) -{ - static const struct mt76_driver_ops drv_ops = { - .tx_prepare_skb = mt76x02u_tx_prepare_skb, - .tx_complete_skb = mt76x02u_tx_complete_skb, - .tx_status_data = mt76x02_tx_status_data, - .rx_skb = mt76x02_queue_rx_skb, - .sta_add = mt76x02_sta_add, - .sta_remove = mt76x02_sta_remove, - }; - struct mt76x02_dev *dev; - struct mt76_dev *mdev; - - mdev = mt76_alloc_device(pdev, sizeof(*dev), &mt76x2u_ops, - &drv_ops); - if (!mdev) - return NULL; - - dev = container_of(mdev, struct mt76x02_dev, mt76); - - return dev; -} - int mt76x2u_init_hardware(struct mt76x02_dev *dev) { int i, k, err; From fa2355265c52b883cf115a617ad793aa16249db2 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 31 Jan 2019 17:55:56 +0100 Subject: [PATCH 24/43] mt76x0: remove mt76x0u_alloc_device routine Remove mt76x0u_alloc_device since it just runs mt76_alloc_device. Move mt76_alloc_device call in mt76x0u_probe and in mt76x0e_probe Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x0/init.c | 19 ---------------- .../wireless/mediatek/mt76/mt76x0/mt76x0.h | 4 ---- .../net/wireless/mediatek/mt76/mt76x0/pci.c | 17 +++++++++----- .../net/wireless/mediatek/mt76/mt76x0/usb.c | 22 +++++++++++-------- 4 files changed, 24 insertions(+), 38 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 34db3ec24e6e..820632e40c1b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -262,25 +262,6 @@ int mt76x0_init_hardware(struct mt76x02_dev *dev) } EXPORT_SYMBOL_GPL(mt76x0_init_hardware); -struct mt76x02_dev * -mt76x0_alloc_device(struct device *pdev, - const struct mt76_driver_ops *drv_ops, - const struct ieee80211_ops *ops) -{ - struct mt76x02_dev *dev; - struct mt76_dev *mdev; - - mdev = mt76_alloc_device(pdev, sizeof(*dev), ops, drv_ops); - if (!mdev) - return NULL; - - dev = container_of(mdev, struct mt76x02_dev, mt76); - mutex_init(&dev->phy_mutex); - - return dev; -} -EXPORT_SYMBOL_GPL(mt76x0_alloc_device); - int mt76x0_register_device(struct mt76x02_dev *dev) { int ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 46629f61673b..51fbd75dff31 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -50,10 +50,6 @@ static inline bool is_mt7630(struct mt76x02_dev *dev) } /* Init */ -struct mt76x02_dev * -mt76x0_alloc_device(struct device *pdev, - const struct mt76_driver_ops *drv_ops, - const struct ieee80211_ops *ops); int mt76x0_init_hardware(struct mt76x02_dev *dev); int mt76x0_register_device(struct mt76x02_dev *dev); void mt76x0_chip_onoff(struct mt76x02_dev *dev, bool enable, bool reset); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 6992b3d7dfec..f302162036d0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -174,6 +174,7 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) .sta_remove = mt76x02_sta_remove, }; struct mt76x02_dev *dev; + struct mt76_dev *mdev; int ret; ret = pcim_enable_device(pdev); @@ -190,16 +191,20 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; - dev = mt76x0_alloc_device(&pdev->dev, &drv_ops, &mt76x0e_ops); - if (!dev) + mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt76x0e_ops, + &drv_ops); + if (!mdev) return -ENOMEM; - mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); + dev = container_of(mdev, struct mt76x02_dev, mt76); + mutex_init(&dev->phy_mutex); - dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION); - dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev); + mt76_mmio_init(mdev, pcim_iomap_table(pdev)[0]); - ret = devm_request_irq(dev->mt76.dev, pdev->irq, mt76x02_irq_handler, + mdev->rev = mt76_rr(dev, MT_ASIC_VERSION); + dev_info(mdev->dev, "ASIC revision: %08x\n", mdev->rev); + + ret = devm_request_irq(mdev->dev, pdev->irq, mt76x02_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) goto error; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 91d8afd9a0ed..2f259bc0ad9e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -233,14 +233,18 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, }; struct usb_device *usb_dev = interface_to_usbdev(usb_intf); struct mt76x02_dev *dev; + struct mt76_dev *mdev; u32 asic_rev, mac_rev; int ret; - dev = mt76x0_alloc_device(&usb_intf->dev, &drv_ops, - &mt76x0u_ops); - if (!dev) + mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), &mt76x0u_ops, + &drv_ops); + if (!mdev) return -ENOMEM; + dev = container_of(mdev, struct mt76x02_dev, mt76); + mutex_init(&dev->phy_mutex); + /* Quirk for Archer T1U */ if (id->driver_info) dev->no_2ghz = true; @@ -250,27 +254,27 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, usb_set_intfdata(usb_intf, dev); - mt76x02u_init_mcu(&dev->mt76); - ret = mt76u_init(&dev->mt76, usb_intf); + mt76x02u_init_mcu(mdev); + ret = mt76u_init(mdev, usb_intf); if (ret) goto err; /* Disable the HW, otherwise MCU fail to initalize on hot reboot */ mt76x0_chip_onoff(dev, false, false); - if (!mt76x02_wait_for_mac(&dev->mt76)) { + if (!mt76x02_wait_for_mac(mdev)) { ret = -ETIMEDOUT; goto err; } asic_rev = mt76_rr(dev, MT_ASIC_VERSION); mac_rev = mt76_rr(dev, MT_MAC_CSR0); - dev_info(dev->mt76.dev, "ASIC revision: %08x MAC revision: %08x\n", + dev_info(mdev->dev, "ASIC revision: %08x MAC revision: %08x\n", asic_rev, mac_rev); /* Note: vendor driver skips this check for MT76X0U */ if (!(mt76_rr(dev, MT_EFUSE_CTRL) & MT_EFUSE_CTRL_SEL)) - dev_warn(dev->mt76.dev, "Warning: eFUSE not present\n"); + dev_warn(mdev->dev, "Warning: eFUSE not present\n"); ret = mt76x0u_register_device(dev); if (ret < 0) @@ -282,7 +286,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); - ieee80211_free_hw(dev->mt76.hw); + ieee80211_free_hw(mdev->hw); return ret; } From ecd25b547d96fe64b8bf67623e773cec29b690c1 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 31 Jan 2019 17:55:57 +0100 Subject: [PATCH 25/43] mt76x2: remove mt76x2_alloc_device routine Remove mt76x2_alloc_device since it just runs mt76_alloc_device. Move mt76_alloc_device call in mt76x2_probe Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x2/mt76x2.h | 1 - .../net/wireless/mediatek/mt76/mt76x2/pci.c | 26 ++++++++++++++----- .../wireless/mediatek/mt76/mt76x2/pci_init.c | 26 ------------------- 3 files changed, 20 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index 28ec19acf9db..6c619f1c65c9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -49,7 +49,6 @@ static inline bool mt76x2_channel_silent(struct mt76x02_dev *dev) extern const struct ieee80211_ops mt76x2_ops; -struct mt76x02_dev *mt76x2_alloc_device(struct device *pdev); int mt76x2_register_device(struct mt76x02_dev *dev); void mt76x2_phy_power_on(struct mt76x02_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c index 92432fe97312..6274655e1f7e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c @@ -30,7 +30,19 @@ static const struct pci_device_id mt76pci_device_table[] = { static int mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + static const struct mt76_driver_ops drv_ops = { + .txwi_size = sizeof(struct mt76x02_txwi), + .update_survey = mt76x02_update_channel, + .tx_prepare_skb = mt76x02_tx_prepare_skb, + .tx_complete_skb = mt76x02_tx_complete_skb, + .rx_skb = mt76x02_queue_rx_skb, + .rx_poll_complete = mt76x02_rx_poll_complete, + .sta_ps = mt76x02_sta_ps, + .sta_add = mt76x02_sta_add, + .sta_remove = mt76x02_sta_remove, + }; struct mt76x02_dev *dev; + struct mt76_dev *mdev; int ret; ret = pcim_enable_device(pdev); @@ -47,17 +59,19 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; - dev = mt76x2_alloc_device(&pdev->dev); - if (!dev) + mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt76x2_ops, + &drv_ops); + if (!mdev) return -ENOMEM; - mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); + dev = container_of(mdev, struct mt76x02_dev, mt76); + mt76_mmio_init(mdev, pcim_iomap_table(pdev)[0]); mt76x2_reset_wlan(dev, false); - dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION); - dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev); + mdev->rev = mt76_rr(dev, MT_ASIC_VERSION); + dev_info(mdev->dev, "ASIC revision: %08x\n", mdev->rev); - ret = devm_request_irq(dev->mt76.dev, pdev->irq, mt76x02_irq_handler, + ret = devm_request_irq(mdev->dev, pdev->irq, mt76x02_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) goto error; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index d5816c7f359f..d4e3d7c11d74 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -313,32 +313,6 @@ void mt76x2_cleanup(struct mt76x02_dev *dev) mt76x02_mcu_cleanup(dev); } -struct mt76x02_dev *mt76x2_alloc_device(struct device *pdev) -{ - static const struct mt76_driver_ops drv_ops = { - .txwi_size = sizeof(struct mt76x02_txwi), - .update_survey = mt76x02_update_channel, - .tx_prepare_skb = mt76x02_tx_prepare_skb, - .tx_complete_skb = mt76x02_tx_complete_skb, - .rx_skb = mt76x02_queue_rx_skb, - .rx_poll_complete = mt76x02_rx_poll_complete, - .sta_ps = mt76x02_sta_ps, - .sta_add = mt76x02_sta_add, - .sta_remove = mt76x02_sta_remove, - }; - struct mt76x02_dev *dev; - struct mt76_dev *mdev; - - mdev = mt76_alloc_device(pdev, sizeof(*dev), &mt76x2_ops, - &drv_ops); - if (!mdev) - return NULL; - - dev = container_of(mdev, struct mt76x02_dev, mt76); - - return dev; -} - int mt76x2_register_device(struct mt76x02_dev *dev) { int ret; From bceac167b00fbc2f5e93eecd578179a467863d85 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Mon, 11 Feb 2019 10:13:41 +0800 Subject: [PATCH 26/43] mt76: change the return type of mt76_dma_attach() There is no need to retun 0 in mt76_dma_attach(), so switch it to void. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 3 +-- drivers/net/wireless/mediatek/mt76/dma.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index bfbfc0c2ec29..6eedc0ec7661 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -553,10 +553,9 @@ static const struct mt76_queue_ops mt76_dma_ops = { .kick = mt76_dma_kick_queue, }; -int mt76_dma_attach(struct mt76_dev *dev) +void mt76_dma_attach(struct mt76_dev *dev) { dev->queue_ops = &mt76_dma_ops; - return 0; } EXPORT_SYMBOL_GPL(mt76_dma_attach); diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h index 357cc356342d..e3292df5e9b2 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.h +++ b/drivers/net/wireless/mediatek/mt76/dma.h @@ -54,7 +54,7 @@ enum mt76_mcu_evt_type { EVT_EVENT_DFS_DETECT_RSP, }; -int mt76_dma_attach(struct mt76_dev *dev); +void mt76_dma_attach(struct mt76_dev *dev); void mt76_dma_cleanup(struct mt76_dev *dev); #endif From 0bee1ff6922d2ba704b41911423d3d7b7322956f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 28 Jan 2019 10:31:12 +0100 Subject: [PATCH 27/43] mt76x0: phy: report target_power in debugfs Initialize target_power variable in mt76x0_phy_set_txpower in order to report target_power in debugfs Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index cb70b04d38a5..3dfcad552be0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -855,6 +855,7 @@ void mt76x0_phy_set_txpower(struct mt76x02_dev *dev) dev->mt76.txpower_cur = mt76x02_get_max_rate_power(t); mt76x02_add_rate_power_offset(t, -info); + dev->target_power = info; mt76x02_phy_set_txpower(dev, info, info); } From 1ffe410ee3bd445383b737739012d9d85283eb73 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 28 Jan 2019 10:31:13 +0100 Subject: [PATCH 28/43] mt76x0: init: introduce mt76x0_init_txpower routine Add mt76x0_init_txpower in order to initialize max_power per channel at device bootstrap. Modify mt76x0_get_tx_power_per_rate and mt76x0_get_power_info signature in order to compute tx power for non-operating channels Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76x0/eeprom.c | 10 +++---- .../wireless/mediatek/mt76/mt76x0/eeprom.h | 7 +++-- .../net/wireless/mediatek/mt76/mt76x0/init.c | 29 +++++++++++++++++-- .../net/wireless/mediatek/mt76/mt76x0/phy.c | 4 +-- 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 64f96567bae9..ab6dfc026acb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -152,11 +152,11 @@ static s8 mt76x0_get_delta(struct mt76x02_dev *dev) return mt76x02_rate_power_val(val); } -void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev) +void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev, + struct ieee80211_channel *chan, + struct mt76_rate_power *t) { - struct ieee80211_channel *chan = dev->mt76.chandef.chan; bool is_2ghz = chan->band == NL80211_BAND_2GHZ; - struct mt76_rate_power *t = &dev->mt76.rate_power; u16 val, addr; s8 delta; @@ -212,7 +212,8 @@ void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev) mt76x02_add_rate_power_offset(t, delta); } -void mt76x0_get_power_info(struct mt76x02_dev *dev, s8 *tp) +void mt76x0_get_power_info(struct mt76x02_dev *dev, + struct ieee80211_channel *chan, s8 *tp) { struct mt76x0_chan_map { u8 chan; @@ -226,7 +227,6 @@ void mt76x0_get_power_info(struct mt76x02_dev *dev, s8 *tp) { 140, 26 }, { 151, 28 }, { 157, 30 }, { 161, 32 }, { 167, 34 }, { 171, 36 }, { 175, 38 }, }; - struct ieee80211_channel *chan = dev->mt76.chandef.chan; u8 offset, addr; int i, idx = 0; u16 data; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h index 42b259f90b6d..7f73034a23b1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h @@ -25,8 +25,11 @@ struct mt76x02_dev; int mt76x0_eeprom_init(struct mt76x02_dev *dev); void mt76x0_read_rx_gain(struct mt76x02_dev *dev); -void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev); -void mt76x0_get_power_info(struct mt76x02_dev *dev, s8 *tp); +void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev, + struct ieee80211_channel *chan, + struct mt76_rate_power *t); +void mt76x0_get_power_info(struct mt76x02_dev *dev, + struct ieee80211_channel *chan, s8 *tp); static inline s8 s6_to_s8(u32 val) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 820632e40c1b..a529ce111c20 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -18,6 +18,7 @@ #include "eeprom.h" #include "mcu.h" #include "initvals.h" +#include "../mt76x02_phy.h" static void mt76x0_vht_cap_mask(struct ieee80211_supported_band *sband) { @@ -262,6 +263,25 @@ int mt76x0_init_hardware(struct mt76x02_dev *dev) } EXPORT_SYMBOL_GPL(mt76x0_init_hardware); +static void +mt76x0_init_txpower(struct mt76x02_dev *dev, + struct ieee80211_supported_band *sband) +{ + struct ieee80211_channel *chan; + struct mt76_rate_power t; + s8 tp; + int i; + + for (i = 0; i < sband->n_channels; i++) { + chan = &sband->channels[i]; + + mt76x0_get_tx_power_per_rate(dev, chan, &t); + mt76x0_get_power_info(dev, chan, &tp); + + chan->max_power = (mt76x02_get_max_rate_power(&t) + tp) / 2; + } +} + int mt76x0_register_device(struct mt76x02_dev *dev) { int ret; @@ -274,9 +294,14 @@ int mt76x0_register_device(struct mt76x02_dev *dev) if (ret) return ret; - /* overwrite unsupported features */ - if (dev->mt76.cap.has_5ghz) + if (dev->mt76.cap.has_5ghz) { + /* overwrite unsupported features */ mt76x0_vht_cap_mask(&dev->mt76.sband_5g.sband); + mt76x0_init_txpower(dev, &dev->mt76.sband_5g.sband); + } + + if (dev->mt76.cap.has_2ghz) + mt76x0_init_txpower(dev, &dev->mt76.sband_2g.sband); mt76x02_init_debugfs(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 3dfcad552be0..3467a32f5fda 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -847,8 +847,8 @@ void mt76x0_phy_set_txpower(struct mt76x02_dev *dev) struct mt76_rate_power *t = &dev->mt76.rate_power; s8 info; - mt76x0_get_tx_power_per_rate(dev); - mt76x0_get_power_info(dev, &info); + mt76x0_get_tx_power_per_rate(dev, dev->mt76.chandef.chan, t); + mt76x0_get_power_info(dev, dev->mt76.chandef.chan, &info); mt76x02_add_rate_power_offset(t, info); mt76x02_limit_rate_power(t, dev->mt76.txpower_conf); From 5de4db8fcb6d6fc7d9064c22841211790c0ab81b Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 11 Feb 2019 09:16:14 +0100 Subject: [PATCH 29/43] mt76x02u: use usb_bulk_msg to upload firmware We don't need to send firmware data asynchronously, much simpler is just use synchronous usb_bulk_msg(). Tested-by: Lorenzo Bianconi Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 13 +++++ .../wireless/mediatek/mt76/mt76x02_usb_mcu.c | 52 ++++++------------- drivers/net/wireless/mediatek/mt76/usb.c | 1 - 3 files changed, 29 insertions(+), 37 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index e9cc108e60d3..13f6febc9b0f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -736,6 +736,19 @@ static inline bool mt76u_check_sg(struct mt76_dev *dev) udev->speed == USB_SPEED_WIRELESS)); } +static inline int +mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int timeout) +{ + struct usb_interface *intf = to_usb_interface(dev->dev); + struct usb_device *udev = interface_to_usbdev(intf); + struct mt76_usb *usb = &dev->usb; + unsigned int pipe; + int sent; + + pipe = usb_sndbulkpipe(udev, usb->out_ep[MT_EP_OUT_INBAND_CMD]); + return usb_bulk_msg(udev, pipe, data, len, &sent, timeout); +} + int mt76u_vendor_request(struct mt76_dev *dev, u8 req, u8 req_type, u16 val, u16 offset, void *buf, size_t len); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c index ff070f8fbc61..64c777298cee 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c @@ -106,18 +106,14 @@ static int __mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, int cmd, bool wait_resp) { - struct usb_interface *intf = to_usb_interface(dev->dev); - struct usb_device *udev = interface_to_usbdev(intf); struct mt76_usb *usb = &dev->usb; - unsigned int pipe; - int ret, sent; + int ret; u8 seq = 0; u32 info; if (test_bit(MT76_REMOVED, &dev->state)) return 0; - pipe = usb_sndbulkpipe(udev, usb->out_ep[MT_EP_OUT_INBAND_CMD]); if (wait_resp) { seq = ++usb->mcu.msg_seq & 0xf; if (!seq) @@ -131,7 +127,7 @@ __mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, if (ret) return ret; - ret = usb_bulk_msg(udev, pipe, skb->data, skb->len, &sent, 500); + ret = mt76u_bulk_msg(dev, skb->data, skb->len, 500); if (ret) return ret; @@ -253,14 +249,12 @@ void mt76x02u_mcu_fw_reset(struct mt76x02_dev *dev) EXPORT_SYMBOL_GPL(mt76x02u_mcu_fw_reset); static int -__mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, struct mt76u_buf *buf, +__mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, u8 *data, const void *fw_data, int len, u32 dst_addr) { - u8 *data = sg_virt(&buf->urb->sg[0]); - DECLARE_COMPLETION_ONSTACK(cmpl); __le32 info; u32 val; - int err; + int err, data_len; info = cpu_to_le32(FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) | FIELD_PREP(MT_MCU_MSG_LEN, len) | @@ -276,25 +270,12 @@ __mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, struct mt76u_buf *buf, mt76u_single_wr(&dev->mt76, MT_VEND_WRITE_FCE, MT_FCE_DMA_LEN, len << 16); - buf->len = MT_CMD_HDR_LEN + len + sizeof(info); - err = mt76u_submit_buf(&dev->mt76, USB_DIR_OUT, - MT_EP_OUT_INBAND_CMD, - buf, GFP_KERNEL, - mt76u_mcu_complete_urb, &cmpl); - if (err < 0) + data_len = MT_CMD_HDR_LEN + len + sizeof(info); + + err = mt76u_bulk_msg(&dev->mt76, data, data_len, 1000); + if (err) { + dev_err(dev->mt76.dev, "firmware upload failed: %d\n", err); return err; - - if (!wait_for_completion_timeout(&cmpl, - msecs_to_jiffies(1000))) { - dev_err(dev->mt76.dev, "firmware upload timed out\n"); - usb_kill_urb(buf->urb); - return -ETIMEDOUT; - } - - if (mt76u_urb_error(buf->urb)) { - dev_err(dev->mt76.dev, "firmware upload failed: %d\n", - buf->urb->status); - return buf->urb->status; } val = mt76_rr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX); @@ -307,17 +288,16 @@ __mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, struct mt76u_buf *buf, int mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, const void *data, int data_len, u32 max_payload, u32 offset) { - int err, len, pos = 0, max_len = max_payload - 8; - struct mt76u_buf buf; + int len, err = 0, pos = 0, max_len = max_payload - 8; + u8 *buf; - err = mt76u_buf_alloc(&dev->mt76, &buf, 1, max_payload, max_payload, - GFP_KERNEL); - if (err < 0) - return err; + buf = kmalloc(max_payload, GFP_KERNEL); + if (!buf) + return -ENOMEM; while (data_len > 0) { len = min_t(int, data_len, max_len); - err = __mt76x02u_mcu_fw_send_data(dev, &buf, data + pos, + err = __mt76x02u_mcu_fw_send_data(dev, buf, data + pos, len, offset + pos); if (err < 0) break; @@ -326,7 +306,7 @@ int mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, const void *data, pos += len; usleep_range(5000, 10000); } - mt76u_buf_free(&buf); + kfree(buf); return err; } diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 6a2507524c6c..018a8cf0941e 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -326,7 +326,6 @@ int mt76u_buf_alloc(struct mt76_dev *dev, struct mt76u_buf *buf, return mt76u_fill_rx_sg(dev, buf, nsgs, len, sglen); } -EXPORT_SYMBOL_GPL(mt76u_buf_alloc); void mt76u_buf_free(struct mt76u_buf *buf) { From bdba48d57a5509a6531e162394f157250d893aaf Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 10 Feb 2019 22:49:13 +0100 Subject: [PATCH 30/43] mt76: usb: fix possible NULL pointer dereference in mt76u_mcu_deinit Fix possible NULL pointer dereference in mt76u_mcu_deinit routine that can occur if initialization path fails before calling mt76u_mcu_init_rx Fixes: ee676cd5017c ("mt76: add driver code for MT76x2u based devices") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/usb_mcu.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/usb_mcu.c index 036be4163e69..9527e1216f3d 100644 --- a/drivers/net/wireless/mediatek/mt76/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/usb_mcu.c @@ -48,9 +48,11 @@ EXPORT_SYMBOL_GPL(mt76u_mcu_init_rx); void mt76u_mcu_deinit(struct mt76_dev *dev) { - struct mt76_usb *usb = &dev->usb; + struct mt76u_buf *buf = &dev->usb.mcu.res; - usb_kill_urb(usb->mcu.res.urb); - mt76u_buf_free(&usb->mcu.res); + if (buf->urb) { + usb_kill_urb(buf->urb); + mt76u_buf_free(buf); + } } EXPORT_SYMBOL_GPL(mt76u_mcu_deinit); From cb83585e1121bd6d6c039cf09fa32380bf8b6258 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 10 Feb 2019 22:49:14 +0100 Subject: [PATCH 31/43] mt76: usb: fix possible memory leak in mt76u_buf_free Move q->ndesc initialization before the for loop in mt76u_alloc_rx since otherwise allocated urbs will not be freed in mt76u_buf_free Double-check scatterlist pointer in mt76u_buf_free Fixes: b40b15e1521f ("mt76: add usb support to mt76 layer") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/usb.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 018a8cf0941e..aee5ff124055 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -330,10 +330,16 @@ int mt76u_buf_alloc(struct mt76_dev *dev, struct mt76u_buf *buf, void mt76u_buf_free(struct mt76u_buf *buf) { struct urb *urb = buf->urb; + struct scatterlist *sg; int i; - for (i = 0; i < urb->num_sgs; i++) - skb_free_frag(sg_virt(&urb->sg[i])); + for (i = 0; i < urb->num_sgs; i++) { + sg = &urb->sg[i]; + if (!sg) + continue; + + skb_free_frag(sg_virt(sg)); + } usb_free_urb(buf->urb); } EXPORT_SYMBOL_GPL(mt76u_buf_free); @@ -537,7 +543,8 @@ static int mt76u_alloc_rx(struct mt76_dev *dev) nsgs = 1; } - for (i = 0; i < MT_NUM_RX_ENTRIES; i++) { + q->ndesc = MT_NUM_RX_ENTRIES; + for (i = 0; i < q->ndesc; i++) { err = mt76u_buf_alloc(dev, &q->entry[i].ubuf, nsgs, q->buf_size, SKB_WITH_OVERHEAD(q->buf_size), @@ -545,7 +552,6 @@ static int mt76u_alloc_rx(struct mt76_dev *dev) if (err < 0) return err; } - q->ndesc = MT_NUM_RX_ENTRIES; return mt76u_submit_rx_buffers(dev); } From b3098121c42caaf3aea239b8655cf52d45be116f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 10 Feb 2019 22:49:15 +0100 Subject: [PATCH 32/43] mt76: usb: do not run mt76u_queues_deinit twice Do not call mt76u_queues_deinit routine in mt76u_alloc_queues error path since it will be run in mt76x0u_register_device or mt76x2u_register_device error path. Current implementation triggers the following kernel warning: [ 67.005516] WARNING: CPU: 2 PID: 761 at lib/refcount.c:187 refcount_sub_and_test_checked+0xa4/0xb8 [ 67.019513] refcount_t: underflow; use-after-free. [ 67.099872] Hardware name: BCM2835 [ 67.106268] Backtrace: [ 67.111584] [<8010c91c>] (dump_backtrace) from [<8010cc00>] (show_stack+0x20/0x24) [ 67.124974] r6:60000013 r5:ffffffff r4:00000000 r3:a50bade6 [ 67.132226] [<8010cbe0>] (show_stack) from [<807ca5f4>] (dump_stack+0xc8/0x114) [ 67.141225] [<807ca52c>] (dump_stack) from [<8011e65c>] (__warn+0xf4/0x120) [ 67.149849] r9:000000bb r8:804d0138 r7:00000009 r6:8099dc84 r5:00000000 r4:b66c7b58 [ 67.160767] [<8011e568>] (__warn) from [<8011e6d0>] (warn_slowpath_fmt+0x48/0x50) [ 67.171436] r9:7f65e128 r8:80d1419c r7:80c0bac4 r6:b97b3044 r5:b7368e00 r4:00000000 [ 67.182433] [<8011e68c>] (warn_slowpath_fmt) from [<804d0138>] (refcount_sub_and_test_checked+0xa4/0xb8) [ 67.195221] r3:80c91c25 r2:8099dc94 [ 67.200370] r4:00000000 [ 67.204397] [<804d0094>] (refcount_sub_and_test_checked) from [<804d0164>] (refcount_dec_and_test_checked+0x18/0x1c) [ 67.218046] r4:b7368e00 r3:00000001 [ 67.223125] [<804d014c>] (refcount_dec_and_test_checked) from [<805db49c>] (usb_free_urb+0x20/0x4c) [ 67.235358] [<805db47c>] (usb_free_urb) from [<7f639804>] (mt76u_buf_free+0x98/0xac [mt76_usb]) [ 67.247302] r4:00000001 r3:00000001 [ 67.252468] [<7f63976c>] (mt76u_buf_free [mt76_usb]) from [<7f639ef8>] (mt76u_queues_deinit+0x44/0x100 [mt76_usb]) [ 67.266102] r8:b8fe8600 r7:b5dac480 r6:b5dace20 r5:00000001 r4:00000000 r3:00000080 [ 67.277132] [<7f639eb4>] (mt76u_queues_deinit [mt76_usb]) from [<7f65c040>] (mt76x0u_cleanup+0x40/0x4c [mt76x0u]) [ 67.290737] r7:b5dac480 r6:b8fe8600 r5:ffffffea r4:b5dace20 [ 67.298069] [<7f65c000>] (mt76x0u_cleanup [mt76x0u]) from [<7f65c564>] (mt76x0u_probe+0x1f0/0x354 [mt76x0u]) [ 67.311174] r4:b5dace20 r3:00000000 [ 67.316312] [<7f65c374>] (mt76x0u_probe [mt76x0u]) from [<805e0b6c>] (usb_probe_interface+0x104/0x240) [ 67.328915] r7:00000000 r6:7f65e034 r5:b6634800 r4:b8fe8620 [ 67.336276] [<805e0a68>] (usb_probe_interface) from [<8056a8bc>] (really_probe+0x224/0x2f8) [ 67.347965] r10:b65f0a00 r9:00000019 r8:7f65e034 r7:80d3e124 r6:00000000 r5:80d3e120 [ 67.359175] r4:b8fe8620 r3:805e0a68 [ 67.364384] [<8056a698>] (really_probe) from [<8056ab60>] (driver_probe_device+0x6c/0x180) [ 67.375974] r10:b65f0a00 r9:7f65e2c0 r8:b8fe8620 r7:00000000 r6:7f65e034 r5:7f65e034 [ 67.387170] r4:b8fe8620 r3:00000000 [ 67.392378] [<8056aaf4>] (driver_probe_device) from [<8056ad54>] (__driver_attach+0xe0/0xe4) [ 67.404097] r9:7f65e2c0 r8:7f65d22c r7:00000000 r6:b8fe8654 r5:7f65e034 r4:b8fe8620 [ 67.415122] [<8056ac74>] (__driver_attach) from [<8056880c>] (bus_for_each_dev+0x68/0xa0) [ 67.426628] r6:8056ac74 r5:7f65e034 r4:00000000 r3:00000027 [ 67.434017] [<805687a4>] (bus_for_each_dev) from [<8056a1cc>] (driver_attach+0x28/0x30) [ 67.445394] r6:80c6ddc8 r5:b7368f80 r4:7f65e034 [ 67.451703] [<8056a1a4>] (driver_attach) from [<80569c24>] (bus_add_driver+0x194/0x21c) [ 67.463081] [<80569a90>] (bus_add_driver) from [<8056b504>] (driver_register+0x8c/0x124) [ 67.474560] r7:80c6ddc8 r6:7f65e034 r5:00000000 r4:7f65e034 [ 67.481964] [<8056b478>] (driver_register) from [<805df510>] (usb_register_driver+0x74/0x140) [ 67.493901] r5:00000000 r4:7f65e000 [ 67.499131] [<805df49c>] (usb_register_driver) from [<7f661024>] (mt76x0_driver_init+0x24/0x1000 [mt76x0u]) [ 67.512258] r9:00000001 r8:7f65e308 r7:00000000 r6:80c08d48 r5:7f661000 r4:7f65e2c0 [ 67.523404] [<7f661000>] (mt76x0_driver_init [mt76x0u]) from [<80102f6c>] (do_one_initcall+0x4c/0x210) [ 67.536142] [<80102f20>] (do_one_initcall) from [<801ae63c>] (do_init_module+0x6c/0x21c) [ 67.547639] r8:7f65e308 r7:80c08d48 r6:b65f0ac0 r5:7f65e2c0 r4:7f65e2c0 [ 67.556129] [<801ae5d0>] (do_init_module) from [<801ad68c>] (load_module+0x1d10/0x2304) Fixes: b40b15e1521f ("mt76: add usb support to mt76 layer") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/usb.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index aee5ff124055..d2c30a280c3a 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -843,16 +843,9 @@ int mt76u_alloc_queues(struct mt76_dev *dev) err = mt76u_alloc_rx(dev); if (err < 0) - goto err; + return err; - err = mt76u_alloc_tx(dev); - if (err < 0) - goto err; - - return 0; -err: - mt76u_queues_deinit(dev); - return err; + return mt76u_alloc_tx(dev); } EXPORT_SYMBOL_GPL(mt76u_alloc_queues); From 63a7de5dfbfd4d3d96b0e7420d69ff8ac9b4d51a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 12 Feb 2019 14:42:39 +0100 Subject: [PATCH 33/43] mt76: usb: move mt76u_check_sg in usb.c Move mt76u_check_sg routine in usb.c and introduce sg_en variable in mt76_usb in order to check if scatter-gather is supported by mt76u layer Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 11 +---------- drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 2 +- .../net/wireless/mediatek/mt76/mt76x2/usb_init.c | 2 +- drivers/net/wireless/mediatek/mt76/usb.c | 14 +++++++++++++- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 13f6febc9b0f..0eb9152c5d18 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -379,6 +379,7 @@ struct mt76_usb { u16 out_max_packet; u8 in_ep[__MT_EP_IN_MAX]; u16 in_max_packet; + bool sg_en; struct mt76u_mcu { struct mutex mutex; @@ -726,16 +727,6 @@ static inline u8 q2ep(u8 qid) return qid + 1; } -static inline bool mt76u_check_sg(struct mt76_dev *dev) -{ - struct usb_interface *intf = to_usb_interface(dev->dev); - struct usb_device *udev = interface_to_usbdev(intf); - - return (udev->bus->sg_tablesize > 0 && - (udev->bus->no_sg_constraint || - udev->speed == USB_SPEED_WIRELESS)); -} - static inline int mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int timeout) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 2f259bc0ad9e..da9d05f6074d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -206,7 +206,7 @@ static int mt76x0u_register_device(struct mt76x02_dev *dev) goto out_err; /* check hw sg support in order to enable AMSDU */ - if (mt76u_check_sg(&dev->mt76)) + if (dev->mt76.usb.sg_en) hw->max_tx_fragments = MT_SG_MAX_SIZE; else hw->max_tx_fragments = 1; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index 006e430e374e..090aaf71b3ef 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -228,7 +228,7 @@ int mt76x2u_register_device(struct mt76x02_dev *dev) goto fail; /* check hw sg support in order to enable AMSDU */ - if (mt76u_check_sg(&dev->mt76)) + if (dev->mt76.usb.sg_en) hw->max_tx_fragments = MT_SG_MAX_SIZE; else hw->max_tx_fragments = 1; diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index d2c30a280c3a..78b31b9ba8ad 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -241,6 +241,16 @@ mt76u_rd_rp(struct mt76_dev *dev, u32 base, return mt76u_req_rd_rp(dev, base, data, n); } +static bool mt76u_check_sg(struct mt76_dev *dev) +{ + struct usb_interface *intf = to_usb_interface(dev->dev); + struct usb_device *udev = interface_to_usbdev(intf); + + return (udev->bus->sg_tablesize > 0 && + (udev->bus->no_sg_constraint || + udev->speed == USB_SPEED_WIRELESS)); +} + static int mt76u_set_endpoints(struct usb_interface *intf, struct mt76_usb *usb) @@ -535,7 +545,7 @@ static int mt76u_alloc_rx(struct mt76_dev *dev) if (!q->entry) return -ENOMEM; - if (mt76u_check_sg(dev)) { + if (dev->usb.sg_en) { q->buf_size = MT_RX_BUF_SIZE; nsgs = MT_SG_MAX_SIZE; } else { @@ -880,6 +890,8 @@ int mt76u_init(struct mt76_dev *dev, dev->bus = &mt76u_ops; dev->queue_ops = &usb_queue_ops; + usb->sg_en = mt76u_check_sg(dev); + return mt76u_set_endpoints(intf, usb); } EXPORT_SYMBOL_GPL(mt76u_init); From d704d16f201ab75d9e348ab932b76d2c924fd472 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 12 Feb 2019 14:42:40 +0100 Subject: [PATCH 34/43] mt76: usb: do not use sg buffers for mcu messages Do not use scatter-gather buffers for mcu commands. Introduce mt76u_buf_alloc and mt76u_buf_alloc_sg routines. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 3 +- .../wireless/mediatek/mt76/mt76x02_usb_mcu.c | 3 +- drivers/net/wireless/mediatek/mt76/usb.c | 38 +++++++++++++++---- drivers/net/wireless/mediatek/mt76/usb_mcu.c | 5 +-- 4 files changed, 36 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 0eb9152c5d18..f55dc621e060 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -87,6 +87,7 @@ struct mt76u_buf { struct mt76_dev *dev; struct urb *urb; size_t len; + void *buf; bool done; }; @@ -748,7 +749,7 @@ void mt76u_single_wr(struct mt76_dev *dev, const u8 req, int mt76u_init(struct mt76_dev *dev, struct usb_interface *intf); void mt76u_deinit(struct mt76_dev *dev); int mt76u_buf_alloc(struct mt76_dev *dev, struct mt76u_buf *buf, - int nsgs, int len, int sglen, gfp_t gfp); + int len, int data_len, gfp_t gfp); void mt76u_buf_free(struct mt76u_buf *buf); int mt76u_submit_buf(struct mt76_dev *dev, int dir, int index, struct mt76u_buf *buf, gfp_t gfp, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c index 64c777298cee..e469e383cb88 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c @@ -63,9 +63,9 @@ static int mt76x02u_mcu_wait_resp(struct mt76_dev *dev, u8 seq) struct mt76_usb *usb = &dev->usb; struct mt76u_buf *buf = &usb->mcu.res; struct urb *urb = buf->urb; + u8 *data = buf->buf; int i, ret; u32 rxfce; - u8 *data; for (i = 0; i < 5; i++) { if (!wait_for_completion_timeout(&usb->mcu.cmpl, @@ -75,7 +75,6 @@ static int mt76x02u_mcu_wait_resp(struct mt76_dev *dev, u8 seq) if (urb->status) return -EIO; - data = sg_virt(&urb->sg[0]); if (usb->mcu.rp) mt76x02u_multiple_mcu_reads(dev, data + 4, urb->actual_length - 8); diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 78b31b9ba8ad..e32ec89781c6 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -319,8 +319,9 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf, return i ? : -ENOMEM; } -int mt76u_buf_alloc(struct mt76_dev *dev, struct mt76u_buf *buf, - int nsgs, int len, int sglen, gfp_t gfp) +static int +mt76u_buf_alloc_sg(struct mt76_dev *dev, struct mt76u_buf *buf, + int nsgs, int len, int sglen, gfp_t gfp) { buf->urb = usb_alloc_urb(0, gfp); if (!buf->urb) @@ -337,6 +338,25 @@ int mt76u_buf_alloc(struct mt76_dev *dev, struct mt76u_buf *buf, return mt76u_fill_rx_sg(dev, buf, nsgs, len, sglen); } +int mt76u_buf_alloc(struct mt76_dev *dev, struct mt76u_buf *buf, + int len, int data_len, gfp_t gfp) +{ + struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; + + buf->urb = usb_alloc_urb(0, gfp); + if (!buf->urb) + return -ENOMEM; + + buf->buf = page_frag_alloc(&q->rx_page, len, gfp); + if (!buf->buf) + return -ENOMEM; + + buf->len = data_len; + buf->dev = dev; + + return 0; +} + void mt76u_buf_free(struct mt76u_buf *buf) { struct urb *urb = buf->urb; @@ -350,6 +370,9 @@ void mt76u_buf_free(struct mt76u_buf *buf) skb_free_frag(sg_virt(sg)); } + if (buf->buf) + skb_free_frag(buf->buf); + usb_free_urb(buf->urb); } EXPORT_SYMBOL_GPL(mt76u_buf_free); @@ -360,6 +383,7 @@ int mt76u_submit_buf(struct mt76_dev *dev, int dir, int index, { struct usb_interface *intf = to_usb_interface(dev->dev); struct usb_device *udev = interface_to_usbdev(intf); + u8 *data = buf->urb->num_sgs ? NULL : buf->buf; unsigned int pipe; if (dir == USB_DIR_IN) @@ -367,7 +391,7 @@ int mt76u_submit_buf(struct mt76_dev *dev, int dir, int index, else pipe = usb_sndbulkpipe(udev, dev->usb.out_ep[index]); - usb_fill_bulk_urb(buf->urb, udev, pipe, NULL, buf->len, + usb_fill_bulk_urb(buf->urb, udev, pipe, data, buf->len, complete_fn, context); trace_submit_urb(dev, buf->urb); @@ -555,10 +579,10 @@ static int mt76u_alloc_rx(struct mt76_dev *dev) q->ndesc = MT_NUM_RX_ENTRIES; for (i = 0; i < q->ndesc; i++) { - err = mt76u_buf_alloc(dev, &q->entry[i].ubuf, - nsgs, q->buf_size, - SKB_WITH_OVERHEAD(q->buf_size), - GFP_KERNEL); + err = mt76u_buf_alloc_sg(dev, &q->entry[i].ubuf, + nsgs, q->buf_size, + SKB_WITH_OVERHEAD(q->buf_size), + GFP_KERNEL); if (err < 0) return err; } diff --git a/drivers/net/wireless/mediatek/mt76/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/usb_mcu.c index 9527e1216f3d..72c8607da4b4 100644 --- a/drivers/net/wireless/mediatek/mt76/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/usb_mcu.c @@ -29,9 +29,8 @@ int mt76u_mcu_init_rx(struct mt76_dev *dev) struct mt76_usb *usb = &dev->usb; int err; - err = mt76u_buf_alloc(dev, &usb->mcu.res, 1, - MCU_RESP_URB_SIZE, MCU_RESP_URB_SIZE, - GFP_KERNEL); + err = mt76u_buf_alloc(dev, &usb->mcu.res, MCU_RESP_URB_SIZE, + MCU_RESP_URB_SIZE, GFP_KERNEL); if (err < 0) return err; From f752294946ae79aa610dda08413e3d5721faed27 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 12 Feb 2019 14:42:41 +0100 Subject: [PATCH 35/43] mt76: usb: use a linear buffer for tx/rx datapath if sg is not supported Use linear fragment and not a single usb scatter-gather buffer in mt76u {tx,rx} datapath if the usb controller has sg data length constraints Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/usb.c | 87 +++++++++++++++--------- 1 file changed, 54 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index e32ec89781c6..0970a53d6ed5 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -432,10 +432,11 @@ static int mt76u_get_rx_entry_len(u8 *data, u32 data_len) } static int -mt76u_process_rx_entry(struct mt76_dev *dev, struct urb *urb) +mt76u_process_rx_entry(struct mt76_dev *dev, struct mt76u_buf *buf) { struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; - u8 *data = sg_virt(&urb->sg[0]); + struct urb *urb = buf->urb; + u8 *data = urb->num_sgs ? sg_virt(&urb->sg[0]) : buf->buf; int data_len, len, nsgs = 1; struct sk_buff *skb; @@ -446,7 +447,8 @@ mt76u_process_rx_entry(struct mt76_dev *dev, struct urb *urb) if (len < 0) return 0; - data_len = min_t(int, len, urb->sg[0].length - MT_DMA_HDR_LEN); + data_len = urb->num_sgs ? urb->sg[0].length : buf->len; + data_len = min_t(int, len, data_len - MT_DMA_HDR_LEN); if (MT_DMA_HDR_LEN + data_len > SKB_WITH_OVERHEAD(q->buf_size)) return 0; @@ -458,7 +460,7 @@ mt76u_process_rx_entry(struct mt76_dev *dev, struct urb *urb) __skb_put(skb, data_len); len -= data_len; - while (len > 0) { + while (len > 0 && urb->num_sgs) { data_len = min_t(int, len, urb->sg[nsgs].length); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, sg_page(&urb->sg[nsgs]), @@ -503,12 +505,26 @@ static void mt76u_complete_rx(struct urb *urb) spin_unlock_irqrestore(&q->lock, flags); } +static int +mt76u_refill_rx(struct mt76_dev *dev, struct mt76_queue *q, + struct mt76u_buf *buf, int nsgs) +{ + if (dev->usb.sg_en) { + return mt76u_fill_rx_sg(dev, buf, nsgs, q->buf_size, + SKB_WITH_OVERHEAD(q->buf_size)); + } else { + buf->buf = page_frag_alloc(&q->rx_page, q->buf_size, + GFP_ATOMIC); + return buf->buf ? 0 : -ENOMEM; + } +} + static void mt76u_rx_tasklet(unsigned long data) { struct mt76_dev *dev = (struct mt76_dev *)data; struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; - int err, nsgs, buf_len = q->buf_size; struct mt76u_buf *buf; + int err, count; rcu_read_lock(); @@ -517,11 +533,9 @@ static void mt76u_rx_tasklet(unsigned long data) if (!buf) break; - nsgs = mt76u_process_rx_entry(dev, buf->urb); - if (nsgs > 0) { - err = mt76u_fill_rx_sg(dev, buf, nsgs, - buf_len, - SKB_WITH_OVERHEAD(buf_len)); + count = mt76u_process_rx_entry(dev, buf); + if (count > 0) { + err = mt76u_refill_rx(dev, q, buf, count); if (err < 0) break; } @@ -559,7 +573,7 @@ EXPORT_SYMBOL_GPL(mt76u_submit_rx_buffers); static int mt76u_alloc_rx(struct mt76_dev *dev) { struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; - int i, err, nsgs; + int i, err; spin_lock_init(&q->rx_page_lock); spin_lock_init(&q->lock); @@ -569,20 +583,19 @@ static int mt76u_alloc_rx(struct mt76_dev *dev) if (!q->entry) return -ENOMEM; - if (dev->usb.sg_en) { - q->buf_size = MT_RX_BUF_SIZE; - nsgs = MT_SG_MAX_SIZE; - } else { - q->buf_size = PAGE_SIZE; - nsgs = 1; - } - + q->buf_size = dev->usb.sg_en ? MT_RX_BUF_SIZE : PAGE_SIZE; q->ndesc = MT_NUM_RX_ENTRIES; for (i = 0; i < q->ndesc; i++) { - err = mt76u_buf_alloc_sg(dev, &q->entry[i].ubuf, - nsgs, q->buf_size, - SKB_WITH_OVERHEAD(q->buf_size), - GFP_KERNEL); + if (dev->usb.sg_en) + err = mt76u_buf_alloc_sg(dev, &q->entry[i].ubuf, + MT_SG_MAX_SIZE, q->buf_size, + SKB_WITH_OVERHEAD(q->buf_size), + GFP_KERNEL); + else + err = mt76u_buf_alloc(dev, &q->entry[i].ubuf, + q->buf_size, + SKB_WITH_OVERHEAD(q->buf_size), + GFP_KERNEL); if (err < 0) return err; } @@ -730,7 +743,7 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, { struct usb_interface *intf = to_usb_interface(dev->dev); struct usb_device *udev = interface_to_usbdev(intf); - u8 ep = q2ep(q->hw_idx); + u8 *data = NULL, ep = q2ep(q->hw_idx); struct mt76u_buf *buf; u16 idx = q->tail; unsigned int pipe; @@ -747,12 +760,16 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, buf = &q->entry[idx].ubuf; buf->done = false; - err = mt76u_tx_build_sg(skb, buf->urb); - if (err < 0) - return err; + if (dev->usb.sg_en) { + err = mt76u_tx_build_sg(skb, buf->urb); + if (err < 0) + return err; + } else { + data = skb->data; + } pipe = usb_sndbulkpipe(udev, dev->usb.out_ep[ep]); - usb_fill_bulk_urb(buf->urb, udev, pipe, NULL, skb->len, + usb_fill_bulk_urb(buf->urb, udev, pipe, data, skb->len, mt76u_complete_tx, buf); q->tail = (q->tail + 1) % q->ndesc; @@ -788,10 +805,8 @@ static int mt76u_alloc_tx(struct mt76_dev *dev) { struct mt76u_buf *buf; struct mt76_queue *q; - size_t size; int i, j; - size = MT_SG_MAX_SIZE * sizeof(struct scatterlist); for (i = 0; i < IEEE80211_NUM_ACS; i++) { q = &dev->q_tx[i]; spin_lock_init(&q->lock); @@ -813,9 +828,15 @@ static int mt76u_alloc_tx(struct mt76_dev *dev) if (!buf->urb) return -ENOMEM; - buf->urb->sg = devm_kzalloc(dev->dev, size, GFP_KERNEL); - if (!buf->urb->sg) - return -ENOMEM; + if (dev->usb.sg_en) { + size_t size = MT_SG_MAX_SIZE * + sizeof(struct scatterlist); + + buf->urb->sg = devm_kzalloc(dev->dev, size, + GFP_KERNEL); + if (!buf->urb->sg) + return -ENOMEM; + } } } return 0; From c2908a0dfd7ab13381f09fde636f1429d4bb5eaa Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 12 Feb 2019 14:42:42 +0100 Subject: [PATCH 36/43] mt76: usb: introduce disable_usb_sg parameter Add disable_usb_sg module parameter to disable scatter-gather on demand Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/usb.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 0970a53d6ed5..c9f095c1f161 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -22,6 +22,10 @@ #define MT_VEND_REQ_MAX_RETRY 10 #define MT_VEND_REQ_TOUT_MS 300 +static bool disable_usb_sg; +module_param_named(disable_usb_sg, disable_usb_sg, bool, 0644); +MODULE_PARM_DESC(disable_usb_sg, "Disable usb scatter-gather support"); + /* should be called with usb_ctrl_mtx locked */ static int __mt76u_vendor_request(struct mt76_dev *dev, u8 req, u8 req_type, u16 val, u16 offset, @@ -246,7 +250,7 @@ static bool mt76u_check_sg(struct mt76_dev *dev) struct usb_interface *intf = to_usb_interface(dev->dev); struct usb_device *udev = interface_to_usbdev(intf); - return (udev->bus->sg_tablesize > 0 && + return (!disable_usb_sg && udev->bus->sg_tablesize > 0 && (udev->bus->no_sg_constraint || udev->speed == USB_SPEED_WIRELESS)); } From 4bfff1ec2599d737470daa3b80711fbc2e8ccfd2 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 12 Feb 2019 00:45:55 +0100 Subject: [PATCH 37/43] mt76: usb: use dev_err_ratelimited instead of dev_err in mt76u_complete_rx During device removal the driver can report multiple error messages. Use dev_err_ratelimited instead of dev_err to display urb errors Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/usb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index c9f095c1f161..78191968b4fa 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -492,7 +492,8 @@ static void mt76u_complete_rx(struct urb *urb) case -ENOENT: return; default: - dev_err(dev->dev, "rx urb failed: %d\n", urb->status); + dev_err_ratelimited(dev->dev, "rx urb failed: %d\n", + urb->status); /* fall through */ case 0: break; From 3eeb7c062d88cd3d9a7c0deac71bb1b48ac99c30 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 12 Feb 2019 10:24:42 +0100 Subject: [PATCH 38/43] mt76x02u: remove bogus check and comment padding In mt76x02u_skb_dma_info() pad is always non-zero. Patch removes bogus check and add comments to the function. Signed-off-by: Stanislaw Gruszka Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76x02_usb_core.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index 098d05e109e7..43f07461c8d3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -49,7 +49,12 @@ int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags) FIELD_PREP(MT_TXD_INFO_DPORT, port) | flags; put_unaligned_le32(info, skb_push(skb, sizeof(info))); + /* Add zero pad of 4 - 7 bytes */ pad = round_up(skb->len, 4) + 4 - skb->len; + + /* First packet of a A-MSDU burst keeps track of the whole burst + * length, need to update lenght of it and the last packet. + */ skb_walk_frags(skb, iter) { last = iter; if (!iter->next) { @@ -59,11 +64,10 @@ int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags) } } - if (unlikely(pad)) { - if (skb_pad(last, pad)) - return -ENOMEM; - __skb_put(last, pad); - } + if (skb_pad(last, pad)) + return -ENOMEM; + __skb_put(last, pad); + return 0; } From d0ff23c1107e8c6ddc7534cafb65844b292b1540 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 12 Feb 2019 15:36:24 +0000 Subject: [PATCH 39/43] mt76: Use the correct hweight8() function mt76_init_stream_cap() and mt76_get_txpower() call __sw_hweight8() directly, but that's only defined if CONFIG_GENERIC_HWEIGHT is enabled. The function that works on all architectures is hweight8(). Fixes: 551e1ef4d291 ("mt76: add mt76_init_stream_cap routine") Fixes: 9313faacbb4e ("mt76: move mt76x02_get_txpower to mt76 core") Signed-off-by: Ben Hutchings Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index c7abf4f54867..82e9f78ef328 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -124,7 +124,7 @@ static void mt76_init_stream_cap(struct mt76_dev *dev, bool vht) { struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; - int i, nstream = __sw_hweight8(dev->antenna_mask); + int i, nstream = hweight8(dev->antenna_mask); struct ieee80211_sta_vht_cap *vht_cap; u16 mcs_map = 0; @@ -726,7 +726,7 @@ int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm) { struct mt76_dev *dev = hw->priv; - int n_chains = __sw_hweight8(dev->antenna_mask); + int n_chains = hweight8(dev->antenna_mask); *dbm = dev->txpower_cur / 2; From b231cd7f557d59b7922a3b8dc29ef1f23338f1fc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 25 Jan 2019 15:10:52 +0100 Subject: [PATCH 40/43] mt76: fix tx status timeout processing Remove bogus check for MT_PACKET_ID_NO_ACK in mt76_tx_status_skb_get, which is already handled in callers and turns timeout calls into no-ops Do not clean up pending status items on reordering of tx status information if the timeout is not reached yet Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/tx.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index ef38e8626da9..5a349fe3e576 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -205,9 +205,6 @@ mt76_tx_status_skb_get(struct mt76_dev *dev, struct mt76_wcid *wcid, int pktid, { struct sk_buff *skb, *tmp; - if (pktid == MT_PACKET_ID_NO_ACK) - return NULL; - skb_queue_walk_safe(&dev->status_list, skb, tmp) { struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb); @@ -217,7 +214,7 @@ mt76_tx_status_skb_get(struct mt76_dev *dev, struct mt76_wcid *wcid, int pktid, if (cb->pktid == pktid) return skb; - if (!pktid && + if (pktid >= 0 && !time_after(jiffies, cb->jiffies + MT_TX_STATUS_SKB_TIMEOUT)) continue; From 906d2d3f874a54183df5a609fda180adf0462428 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 25 Jan 2019 17:59:06 +0100 Subject: [PATCH 41/43] mt76: fix corrupted software generated tx CCMP PN Since ccmp_pn is u8 *, the second half needs to start at array index 4 instead of 0. Fixes a connection stall after a certain amount of traffic Fixes: 23405236460b9 ("mt76: fix transmission of encrypted management frames") Cc: stable@vger.kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index bf39624c9b98..eab713723b7e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -314,7 +314,7 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, ccmp_pn[6] = pn >> 32; ccmp_pn[7] = pn >> 40; txwi->iv = *((__le32 *)&ccmp_pn[0]); - txwi->eiv = *((__le32 *)&ccmp_pn[1]); + txwi->eiv = *((__le32 *)&ccmp_pn[4]); } spin_lock_bh(&dev->mt76.lock); From f2f6a47b504b8fe19922e835231552a01ef30e01 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 25 Jan 2019 18:00:11 +0100 Subject: [PATCH 42/43] mt76: fix resetting software IV flag on key delete It needs to be unset instead of set Fixes: 23405236460b9 ("mt76: fix transmission of encrypted management frames") Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 87ed00768bc7..11b5f664f5b1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -431,7 +431,7 @@ int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } else { if (idx == wcid->hw_key_idx) { wcid->hw_key_idx = -1; - wcid->sw_iv = true; + wcid->sw_iv = false; } key = NULL; From 9f688473408b6334c5da5ec085f9ea1954675fe7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 18 Feb 2019 20:29:11 +0100 Subject: [PATCH 43/43] mt76: mt76x2: simplify per-chain signal strength handling There is no need to use a for loop here, supported chips can only support up to 2 chains. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index eab713723b7e..be2979f34f31 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -608,7 +608,7 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, u16 rate = le16_to_cpu(rxwi->rate); u16 tid_sn = le16_to_cpu(rxwi->tid_sn); bool unicast = rxwi->rxinfo & cpu_to_le32(MT_RXINFO_UNICAST); - int i, pad_len = 0, nstreams = dev->mt76.chainmask & 0xf; + int pad_len = 0, nstreams = dev->mt76.chainmask & 0xf; s8 signal; u8 pn_len; u8 wcid; @@ -668,12 +668,13 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, status->chains = BIT(0); signal = mt76x02_mac_get_rssi(dev, rxwi->rssi[0], 0); - for (i = 0; i < nstreams; i++) { - status->chains |= BIT(i); - status->chain_signal[i] = mt76x02_mac_get_rssi(dev, - rxwi->rssi[i], - i); - signal = max_t(s8, signal, status->chain_signal[i]); + status->chain_signal[0] = signal; + if (nstreams > 1) { + status->chains |= BIT(1); + status->chain_signal[1] = mt76x02_mac_get_rssi(dev, + rxwi->rssi[1], + 1); + signal = max_t(s8, signal, status->chain_signal[1]); } status->signal = signal; status->freq = dev->mt76.chandef.chan->center_freq;