From bdac593c981b3b8986a8d37e020946ba1f6dfaa4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 8 Feb 2021 23:49:39 +0100 Subject: [PATCH 001/170] mt76: mt7915: add MSI support Move IRQ processing to a tasklet, similar to MT7615/MT7663 Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/init.c | 1 + .../wireless/mediatek/mt76/mt7915/mt7915.h | 7 +++- .../net/wireless/mediatek/mt76/mt7915/pci.c | 39 ++++++++++++++++--- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 822f3aa6bb8b..a8fd822cc46e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -752,6 +752,7 @@ void mt7915_unregister_device(struct mt7915_dev *dev) mt7915_mcu_exit(dev); mt7915_tx_token_put(dev); mt7915_dma_cleanup(dev); + tasklet_disable(&dev->irq_tasklet); mt76_free_device(&dev->mt76); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 4ea8972d4e2f..7a3c172afc98 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -169,6 +169,7 @@ struct mt7915_dev { struct mt7915_hif *hif2; const struct mt76_bus_ops *bus_ops; + struct tasklet_struct irq_tasklet; struct mt7915_phy phy; u16 chainmask; @@ -374,9 +375,11 @@ void mt7915_dual_hif_set_irq_mask(struct mt7915_dev *dev, bool write_reg, static inline void mt7915_irq_enable(struct mt7915_dev *dev, u32 mask) { if (dev->hif2) - mt7915_dual_hif_set_irq_mask(dev, true, 0, mask); + mt7915_dual_hif_set_irq_mask(dev, false, 0, mask); else - mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, 0, mask); + mt76_set_irq_mask(&dev->mt76, 0, 0, mask); + + tasklet_schedule(&dev->irq_tasklet); } static inline void mt7915_irq_disable(struct mt7915_dev *dev, u32 mask) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c index 643f171884cf..aae2fb3ccad1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c @@ -94,11 +94,15 @@ mt7915_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) } /* TODO: support 2/4/6/8 MSI-X vectors */ -static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance) +static void mt7915_irq_tasklet(struct tasklet_struct *t) { - struct mt7915_dev *dev = dev_instance; + struct mt7915_dev *dev = from_tasklet(dev, t, irq_tasklet); u32 intr, intr1, mask; + mt76_wr(dev, MT_INT_MASK_CSR, 0); + if (dev->hif2) + mt76_wr(dev, MT_INT1_MASK_CSR, 0); + intr = mt76_rr(dev, MT_INT_SOURCE_CSR); intr &= dev->mt76.mmio.irqmask; mt76_wr(dev, MT_INT_SOURCE_CSR, intr); @@ -111,9 +115,6 @@ static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance) intr |= intr1; } - if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) - return IRQ_NONE; - trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); mask = intr & MT_INT_RX_DONE_ALL; @@ -150,6 +151,20 @@ static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance) wake_up(&dev->reset_wait); } } +} + +static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance) +{ + struct mt7915_dev *dev = dev_instance; + + mt76_wr(dev, MT_INT_MASK_CSR, 0); + if (dev->hif2) + mt76_wr(dev, MT_INT1_MASK_CSR, 0); + + if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) + return IRQ_NONE; + + tasklet_schedule(&dev->irq_tasklet); return IRQ_HANDLED; } @@ -250,10 +265,18 @@ static int mt7915_pci_probe(struct pci_dev *pdev, dev = container_of(mdev, struct mt7915_dev, mt76); + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) + goto free; + ret = mt7915_mmio_init(mdev, pcim_iomap_table(pdev)[0], pdev->irq); if (ret) goto error; + tasklet_setup(&dev->irq_tasklet, mt7915_irq_tasklet); + + mt76_wr(dev, MT_INT_MASK_CSR, 0); + /* master switch of PCIe tnterrupt enable */ mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); @@ -266,10 +289,14 @@ static int mt7915_pci_probe(struct pci_dev *pdev, ret = mt7915_register_device(dev); if (ret) - goto error; + goto free_irq; return 0; +free_irq: + devm_free_irq(mdev->dev, pdev->irq, dev); error: + pci_free_irq_vectors(pdev); +free: mt76_free_device(&dev->mt76); return ret; From 03b3dedc5de184735bb9b6b3e5871fe4384913f2 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 6 May 2021 19:03:03 +0200 Subject: [PATCH 002/170] mt76: mt7915: disable ASPM The same is done on the other chips already, so it is very likely needed on MT7915 as well Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c index aae2fb3ccad1..340b364da5f0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c @@ -255,6 +255,8 @@ static int mt7915_pci_probe(struct pci_dev *pdev, if (ret) return ret; + mt76_pci_disable_aspm(pdev); + if (id->device == 0x7916) return mt7915_pci_hif2_probe(pdev); From 338330bd26b1febc7923ce3ebb6b76f6a5d980b8 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 7 May 2021 12:52:42 +0200 Subject: [PATCH 003/170] mt76: mt7915: move mt7915_queue_rx_skb to mac.c It is not really DMA specific, and moving it makes it possible to make some functions in mac.c static Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/dma.c | 33 -------------- .../net/wireless/mediatek/mt76/mt7915/mac.c | 44 ++++++++++++++++--- .../wireless/mediatek/mt76/mt7915/mt7915.h | 3 -- 3 files changed, 39 insertions(+), 41 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c index 11d0b760abd7..69a7e3dce113 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -19,39 +19,6 @@ int mt7915_init_tx_queues(struct mt7915_phy *phy, int idx, int n_desc) return 0; } -void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, - struct sk_buff *skb) -{ - struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); - __le32 *rxd = (__le32 *)skb->data; - enum rx_pkt_type type; - - type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0])); - - switch (type) { - case PKT_TYPE_TXRX_NOTIFY: - mt7915_mac_tx_free(dev, skb); - break; - case PKT_TYPE_RX_EVENT: - mt7915_mcu_rx_event(dev, skb); - break; -#ifdef CONFIG_NL80211_TESTMODE - case PKT_TYPE_TXRXV: - mt7915_mac_fill_rx_vector(dev, skb); - break; -#endif - case PKT_TYPE_NORMAL: - if (!mt7915_mac_fill_rx(dev, skb)) { - mt76_rx(&dev->mt76, q, skb); - return; - } - fallthrough; - default: - dev_kfree_skb(skb); - break; - } -} - static void mt7915_tx_cleanup(struct mt7915_dev *dev) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 7a9759fb79d8..2c4516f8dbf1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -307,7 +307,8 @@ mt7915_mac_decode_he_radiotap(struct sk_buff *skb, } } -int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) +static int +mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_phy *mphy = &dev->mt76.phy; @@ -610,9 +611,10 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) return 0; } -#ifdef CONFIG_NL80211_TESTMODE -void mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb) +static void +mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb) { +#ifdef CONFIG_NL80211_TESTMODE struct mt7915_phy *phy = &dev->phy; __le32 *rxd = (__le32 *)skb->data; __le32 *rxv_hdr = rxd + 2; @@ -650,10 +652,10 @@ void mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb) phy->test.last_freq_offset = foe; phy->test.last_snr = snr; +#endif dev_kfree_skb(skb); } -#endif static void mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi, @@ -1129,7 +1131,8 @@ void mt7915_txp_skb_unmap(struct mt76_dev *dev, le16_to_cpu(txp->len[i]), DMA_TO_DEVICE); } -void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) +static void +mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) { struct mt7915_tx_free *free = (struct mt7915_tx_free *)skb->data; struct mt76_dev *mdev = &dev->mt76; @@ -1233,6 +1236,37 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) } } +void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb) +{ + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + __le32 *rxd = (__le32 *)skb->data; + enum rx_pkt_type type; + + type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0])); + + switch (type) { + case PKT_TYPE_TXRX_NOTIFY: + mt7915_mac_tx_free(dev, skb); + break; + case PKT_TYPE_RX_EVENT: + mt7915_mcu_rx_event(dev, skb); + break; + case PKT_TYPE_TXRXV: + mt7915_mac_fill_rx_vector(dev, skb); + break; + case PKT_TYPE_NORMAL: + if (!mt7915_mac_fill_rx(dev, skb)) { + mt76_rx(&dev->mt76, q, skb); + return; + } + fallthrough; + default: + dev_kfree_skb(skb); + break; + } +} + void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) { struct mt7915_dev *dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 7a3c172afc98..279332b557a8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -398,9 +398,6 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, bool beacon); void mt7915_mac_set_timing(struct mt7915_phy *phy); -int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb); -void mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb); -void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb); int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, From ec8f1a90d006f7cedcf86ef19fd034a406a213d6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 7 May 2021 14:07:53 +0200 Subject: [PATCH 004/170] mt76: mt7615: fix fixed-rate tx status reporting Rely on the txs fixed-rate bit instead of info->control.rates Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index e2dcfee6be81..7bdf3378a4d1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1235,22 +1235,20 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta, int first_idx = 0, last_idx; int i, idx, count; bool fixed_rate, ack_timeout; - bool probe, ampdu, cck = false; + bool ampdu, cck = false; bool rs_idx; u32 rate_set_tsf; u32 final_rate, final_rate_flags, final_nss, txs; - fixed_rate = info->status.rates[0].count; - probe = !!(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE); - txs = le32_to_cpu(txs_data[1]); - ampdu = !fixed_rate && (txs & MT_TXS1_AMPDU); + ampdu = txs & MT_TXS1_AMPDU; txs = le32_to_cpu(txs_data[3]); count = FIELD_GET(MT_TXS3_TX_COUNT, txs); last_idx = FIELD_GET(MT_TXS3_LAST_TX_RATE, txs); txs = le32_to_cpu(txs_data[0]); + fixed_rate = txs & MT_TXS0_FIXED_RATE; final_rate = FIELD_GET(MT_TXS0_TX_RATE, txs); ack_timeout = txs & MT_TXS0_ACK_TIMEOUT; @@ -1272,7 +1270,7 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta, first_idx = max_t(int, 0, last_idx - (count - 1) / MT7615_RATE_RETRY); - if (fixed_rate && !probe) { + if (fixed_rate) { info->status.rates[0].count = count; i = 0; goto out; From 7172534f63c493462f5bb96e3eb7fa03d889560e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 7 May 2021 19:46:23 +0200 Subject: [PATCH 005/170] mt76: mt7615: avoid use of ieee80211_tx_info_clear_status It overwrites mt76_tx_cb data in the skb Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 7bdf3378a4d1..7153f1da92d0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1389,7 +1389,7 @@ static bool mt7615_mac_add_txs_skb(struct mt7615_dev *dev, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (!mt7615_fill_txs(dev, sta, info, txs_data)) { - ieee80211_tx_info_clear_status(info); + info->status.rates[0].count = 0; info->status.rates[0].idx = -1; } From 1d85dc67c4c720c8332f869965fe8091c757cc0d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 7 May 2021 19:49:00 +0200 Subject: [PATCH 006/170] mt76: mt7603: avoid use of ieee80211_tx_info_clear_status It overwrites mt76_tx_cb data in the skb Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7603/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index fbceb07c5f37..4e76f9868b9b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -1213,7 +1213,7 @@ mt7603_mac_add_txs_skb(struct mt7603_dev *dev, struct mt7603_sta *sta, int pid, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (!mt7603_fill_txs(dev, sta, info, txs_data)) { - ieee80211_tx_info_clear_status(info); + info->status.rates[0].count = 0; info->status.rates[0].idx = -1; } From 6d51cae28c8de95ac41c64affec2b00ef8bcaf87 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 9 May 2021 22:49:07 +0200 Subject: [PATCH 007/170] mt76: intialize tx queue entry wcid to 0xffff by default Avoid accidentally mapping them to WCID 0 on completion Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 1 + drivers/net/wireless/mediatek/mt76/sdio.c | 1 + drivers/net/wireless/mediatek/mt76/usb.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 72b1cc0ecfda..75c1f54b1fe5 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -191,6 +191,7 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q, q->entry[idx].txwi = txwi; q->entry[idx].skb = skb; + q->entry[idx].wcid = 0xffff; return idx; } diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c index a18d2896ee1f..1665fe88ebb8 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/sdio.c @@ -256,6 +256,7 @@ mt76s_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, q->entry[q->head].skb = tx_info.skb; q->entry[q->head].buf_sz = len; + q->entry[q->head].wcid = 0xffff; smp_wmb(); diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 30bc54e98c58..1e9f60bb811a 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -925,6 +925,7 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, q->head = (q->head + 1) % q->ndesc; q->entry[idx].skb = tx_info.skb; + q->entry[idx].wcid = 0xffff; q->queued++; return idx; From 0fe88644c06063352b202f82dbead3c0df053c10 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 7 May 2021 17:01:45 +0200 Subject: [PATCH 008/170] mt76: improve tx status codepath Use ieee80211_tx_status_ext instead of ieee80211_free_skb and ieee80211_tx_status. This makes it compatible with 802.3 encap offload and improves performance by removing a redundant sta lookup Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 9 ++- drivers/net/wireless/mediatek/mt76/tx.c | 75 +++++++++++++++-------- 2 files changed, 56 insertions(+), 28 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 36ede65919f8..d3859eda2a4f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1056,7 +1056,14 @@ struct sk_buff *mt76_tx_status_skb_get(struct mt76_dev *dev, struct sk_buff_head *list); void mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, struct sk_buff_head *list); -void mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid, struct sk_buff *skb); +void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid, struct sk_buff *skb, + struct list_head *free_list); +static inline void +mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid, struct sk_buff *skb) +{ + __mt76_tx_complete_skb(dev, wcid, skb, NULL); +} + void mt76_tx_status_check(struct mt76_dev *dev, struct mt76_wcid *wcid, bool flush); int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 53ea8de82df0..70a830132a37 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -54,11 +54,23 @@ mt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list) spin_unlock_bh(&dev->status_list.lock); + rcu_read_lock(); while ((skb = __skb_dequeue(list)) != NULL) { - hw = mt76_tx_status_get_hw(dev, skb); - ieee80211_tx_status(hw, skb); - } + struct ieee80211_tx_status status = { + .skb = skb, + .info = IEEE80211_SKB_CB(skb), + }; + struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb); + struct mt76_wcid *wcid; + wcid = rcu_dereference(dev->wcid[cb->wcid]); + if (wcid) + status.sta = wcid_to_sta(wcid); + + hw = mt76_tx_status_get_hw(dev, skb); + ieee80211_tx_status_ext(hw, &status); + } + rcu_read_unlock(); } EXPORT_SYMBOL_GPL(mt76_tx_status_unlock); @@ -80,7 +92,7 @@ __mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, u8 flags, /* Tx status can be unreliable. if it fails, mark the frame as ACKed */ if (flags & MT_TX_CB_TXS_FAILED) { - ieee80211_tx_info_clear_status(info); + info->status.rates[0].count = 0; info->status.rates[0].idx = -1; info->flags |= IEEE80211_TX_STAT_ACK; } @@ -173,36 +185,37 @@ mt76_tx_status_check(struct mt76_dev *dev, struct mt76_wcid *wcid, bool flush) EXPORT_SYMBOL_GPL(mt76_tx_status_check); static void -mt76_tx_check_non_aql(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb) +mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid, + struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct mt76_wcid *wcid; int pending; - if (info->tx_time_est) + if (!wcid || info->tx_time_est) return; - if (wcid_idx >= ARRAY_SIZE(dev->wcid)) - return; - - rcu_read_lock(); - - wcid = rcu_dereference(dev->wcid[wcid_idx]); - if (wcid) { - pending = atomic_dec_return(&wcid->non_aql_packets); - if (pending < 0) - atomic_cmpxchg(&wcid->non_aql_packets, pending, 0); - } - - rcu_read_unlock(); + pending = atomic_dec_return(&wcid->non_aql_packets); + if (pending < 0) + atomic_cmpxchg(&wcid->non_aql_packets, pending, 0); } -void mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb) +void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb, + struct list_head *free_list) { + struct ieee80211_tx_status status = { + .skb = skb, + .free_list = free_list, + }; + struct mt76_wcid *wcid = NULL; struct ieee80211_hw *hw; struct sk_buff_head list; - mt76_tx_check_non_aql(dev, wcid_idx, skb); + rcu_read_lock(); + + if (wcid_idx < ARRAY_SIZE(dev->wcid)) + wcid = rcu_dereference(dev->wcid[wcid_idx]); + + mt76_tx_check_non_aql(dev, wcid, skb); #ifdef CONFIG_NL80211_TESTMODE if (mt76_is_testmode_skb(dev, skb, &hw)) { @@ -214,21 +227,25 @@ void mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *sk wake_up(&dev->tx_wait); dev_kfree_skb_any(skb); - return; + goto out; } #endif if (!skb->prev) { hw = mt76_tx_status_get_hw(dev, skb); - ieee80211_free_txskb(hw, skb); - return; + status.sta = wcid_to_sta(wcid); + ieee80211_tx_status_ext(hw, &status); + goto out; } mt76_tx_status_lock(dev, &list); __mt76_tx_status_skb_done(dev, skb, MT_TX_CB_DMA_DONE, &list); mt76_tx_status_unlock(dev, &list); + +out: + rcu_read_unlock(); } -EXPORT_SYMBOL_GPL(mt76_tx_complete_skb); +EXPORT_SYMBOL_GPL(__mt76_tx_complete_skb); static int __mt76_tx_queue_skb(struct mt76_phy *phy, int qid, struct sk_buff *skb, @@ -244,11 +261,15 @@ __mt76_tx_queue_skb(struct mt76_phy *phy, int qid, struct sk_buff *skb, non_aql = !info->tx_time_est; idx = dev->queue_ops->tx_queue_skb(dev, q, skb, wcid, sta); - if (idx < 0 || !sta || !non_aql) + if (idx < 0 || !sta) return idx; wcid = (struct mt76_wcid *)sta->drv_priv; q->entry[idx].wcid = wcid->idx; + + if (!non_aql) + return idx; + pending = atomic_inc_return(&wcid->non_aql_packets); if (stop && pending >= MT_MAX_NON_AQL_PKT) *stop = true; From 94e4f5794627a80ce036c35b32a9900daeb31be3 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 9 May 2021 20:23:01 +0200 Subject: [PATCH 009/170] mt76: dma: use ieee80211_tx_status_ext to free packets when tx fails Fixes AQL issues on full queues, especially with 802.3 encap offload Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 75c1f54b1fe5..5e1c1506a4c6 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -350,6 +350,9 @@ 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) { + struct ieee80211_tx_status status = { + .sta = sta, + }; struct mt76_tx_info tx_info = { .skb = skb, }; @@ -361,11 +364,9 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, u8 *txwi; t = mt76_get_txwi(dev); - if (!t) { - hw = mt76_tx_status_get_hw(dev, skb); - ieee80211_free_txskb(hw, skb); - return -ENOMEM; - } + if (!t) + goto free_skb; + txwi = mt76_get_txwi_ptr(dev, t); skb->prev = skb->next = NULL; @@ -428,8 +429,13 @@ free: } #endif - dev_kfree_skb(tx_info.skb); mt76_put_txwi(dev, t); + +free_skb: + status.skb = tx_info.skb; + hw = mt76_tx_status_get_hw(dev, tx_info.skb); + ieee80211_tx_status_ext(hw, &status); + return ret; } From 223fd4f843081059bc8f8d8ba6363bfcc2e5848f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 7 May 2021 18:51:41 +0200 Subject: [PATCH 010/170] mt76: mt7915: rework tx rate reporting Instead of attaching the last reported rate to tx packets, use ieee80211_tx_status_ext to immediately pass the rate to mac80211 after receiving it from the firmware. Preparation for implementing full tx status reporting Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/mac.c | 145 +++++++----------- .../net/wireless/mediatek/mt76/mt7915/mcu.c | 8 + .../wireless/mediatek/mt76/mt7915/mt7915.h | 2 - 3 files changed, 66 insertions(+), 89 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 2c4516f8dbf1..9b453e45fde0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1073,54 +1073,7 @@ mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) } static void -mt7915_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb, - struct ieee80211_sta *sta, u8 stat, - struct list_head *free_list) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_status status = { - .sta = sta, - .info = info, - .skb = skb, - .free_list = free_list, - }; - struct ieee80211_hw *hw; - - if (sta) { - struct mt7915_sta *msta; - - msta = (struct mt7915_sta *)sta->drv_priv; - status.rate = &msta->stats.tx_rate; - } - -#ifdef CONFIG_NL80211_TESTMODE - if (mt76_is_testmode_skb(mdev, skb, &hw)) { - struct mt7915_phy *phy = mt7915_hw_phy(hw); - struct ieee80211_vif *vif = phy->monitor_vif; - struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; - - mt76_tx_complete_skb(mdev, mvif->sta.wcid.idx, skb); - return; - } -#endif - - hw = mt76_tx_status_get_hw(mdev, skb); - - if (info->flags & IEEE80211_TX_CTL_AMPDU) - info->flags |= IEEE80211_TX_STAT_AMPDU; - - if (stat) - ieee80211_tx_info_clear_status(info); - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) - info->flags |= IEEE80211_TX_STAT_ACK; - - info->status.tx_time = 0; - ieee80211_tx_status_ext(hw, &status); -} - -void mt7915_txp_skb_unmap(struct mt76_dev *dev, - struct mt76_txwi_cache *t) +mt7915_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t) { struct mt7915_txp *txp; int i; @@ -1131,6 +1084,59 @@ void mt7915_txp_skb_unmap(struct mt76_dev *dev, le16_to_cpu(txp->len[i]), DMA_TO_DEVICE); } +static void +mt7915_txwi_free(struct mt7915_dev *dev, struct mt76_txwi_cache *t, + struct ieee80211_sta *sta, struct list_head *free_list) +{ + struct ieee80211_tx_status status = {}; + struct mt76_dev *mdev = &dev->mt76; + struct ieee80211_tx_info *info; + struct mt76_wcid *wcid; + __le32 *txwi; + u16 wcid_idx; + + mt7915_txp_skb_unmap(mdev, t); + if (!t->skb) + goto out; + + txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t); + if (sta) { + wcid = (struct mt76_wcid *)sta->drv_priv; + wcid_idx = wcid->idx; + + if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE))) + mt7915_tx_check_aggr(sta, txwi); + } else { + wcid_idx = FIELD_GET(MT_TXD1_WLAN_IDX, le32_to_cpu(txwi[1])); + } + + info = IEEE80211_SKB_CB(t->skb); + if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { + struct ieee80211_hw *hw; + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.rates[0].count = 0; + info->status.rates[0].idx = -1; + + status.skb = t->skb; + status.sta = sta; + status.info = info; + + hw = mt76_tx_status_get_hw(mdev, t->skb); + ieee80211_tx_status_ext(hw, &status); + + goto out; + } + + __mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list); + +out: + t->skb = NULL; + mt76_put_txwi(mdev, t); +} + static void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) { @@ -1197,28 +1203,7 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) if (!txwi) continue; - mt7915_txp_skb_unmap(mdev, txwi); - if (txwi->skb) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txwi->skb); - void *txwi_ptr = mt76_get_txwi_ptr(mdev, txwi); - - if (likely(txwi->skb->protocol != cpu_to_be16(ETH_P_PAE))) - mt7915_tx_check_aggr(sta, txwi_ptr); - - if (sta && !info->tx_time_est) { - struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; - int pending; - - pending = atomic_dec_return(&wcid->non_aql_packets); - if (pending < 0) - atomic_cmpxchg(&wcid->non_aql_packets, pending, 0); - } - - mt7915_tx_complete_status(mdev, txwi->skb, sta, stat, &free_list); - txwi->skb = NULL; - } - - mt76_put_txwi(mdev, txwi); + mt7915_txwi_free(dev, txwi, sta, &free_list); } mt7915_mac_sta_poll(dev); @@ -1288,15 +1273,8 @@ void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) e->skb = t ? t->skb : NULL; } - if (e->skb) { - struct mt76_tx_cb *cb = mt76_tx_skb_cb(e->skb); - struct mt76_wcid *wcid; - - wcid = rcu_dereference(dev->mt76.wcid[cb->wcid]); - - mt7915_tx_complete_status(mdev, e->skb, wcid_to_sta(wcid), 0, - NULL); - } + if (e->skb) + mt76_tx_complete_skb(mdev, e->wcid, e->skb); } void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy) @@ -1582,14 +1560,7 @@ void mt7915_tx_token_put(struct mt7915_dev *dev) spin_lock_bh(&dev->mt76.token_lock); idr_for_each_entry(&dev->mt76.token, txwi, id) { - mt7915_txp_skb_unmap(&dev->mt76, txwi); - if (txwi->skb) { - struct ieee80211_hw *hw; - - hw = mt76_tx_status_get_hw(&dev->mt76, txwi->skb); - ieee80211_free_txskb(hw, txwi->skb); - } - mt76_put_txwi(&dev->mt76, txwi); + mt7915_txwi_free(dev, txwi, NULL, NULL); dev->mt76.token_count--; } spin_unlock_bh(&dev->mt76.token_lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index b3f14ff67c5a..9ec414de317e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -469,6 +469,7 @@ mt7915_mcu_tx_rate_report(struct mt7915_dev *dev, struct sk_buff *skb) u16 attempts = le16_to_cpu(ra->attempts); u16 curr = le16_to_cpu(ra->curr_rate); u16 wcidx = le16_to_cpu(ra->wlan_idx); + struct ieee80211_tx_status status = {}; struct mt76_phy *mphy = &dev->mphy; struct mt7915_sta_stats *stats; struct mt7915_sta *msta; @@ -500,6 +501,13 @@ mt7915_mcu_tx_rate_report(struct mt7915_dev *dev, struct sk_buff *skb) stats->per = 1000 * (attempts - success) / attempts; } + + status.sta = wcid_to_sta(wcid); + if (!status.sta) + return; + + status.rate = &stats->tx_rate; + ieee80211_tx_status_ext(mphy->hw, &status); } static void diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 279332b557a8..0342729145e7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -417,8 +417,6 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); void mt7915_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps); void mt7915_stats_work(struct work_struct *work); -void mt7915_txp_skb_unmap(struct mt76_dev *dev, - struct mt76_txwi_cache *txwi); int mt76_dfs_start_rdd(struct mt7915_dev *dev, bool force); int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy); void mt7915_set_stream_he_caps(struct mt7915_phy *phy); From 3de4cb1756565a22321039eb9ae0193519bed967 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 7 May 2021 15:18:09 +0200 Subject: [PATCH 011/170] mt76: mt7915: add support for tx status reporting For now, this only reports ACK status Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/mac.c | 124 ++++++++++++++---- .../net/wireless/mediatek/mt76/mt7915/mac.h | 56 ++++++++ .../net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- .../wireless/mediatek/mt76/mt7915/mt7915.h | 2 +- 4 files changed, 154 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 9b453e45fde0..f8bb043f9be7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -887,7 +887,7 @@ mt7915_mac_write_txwi_80211(struct mt7915_dev *dev, __le32 *txwi, } void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, - struct sk_buff *skb, struct mt76_wcid *wcid, + struct sk_buff *skb, struct mt76_wcid *wcid, int pid, struct ieee80211_key_conf *key, bool beacon) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -946,7 +946,12 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, txwi[3] = cpu_to_le32(val); txwi[4] = 0; - txwi[5] = 0; + + val = FIELD_PREP(MT_TXD5_PID, pid); + if (pid >= MT_PACKET_ID_FIRST) + val |= MT_TXD5_TX_STATUS_HOST; + txwi[5] = cpu_to_le32(val); + txwi[6] = 0; txwi[7] = wcid->amsdu ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0; @@ -986,11 +991,11 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); struct ieee80211_key_conf *key = info->control.hw_key; struct ieee80211_vif *vif = info->control.vif; - struct mt76_tx_cb *cb = mt76_tx_skb_cb(tx_info->skb); struct mt76_txwi_cache *t; struct mt7915_txp *txp; int id, i, nbuf = tx_info->nbuf - 1; u8 *txwi = (u8 *)txwi_ptr; + int pid; if (unlikely(tx_info->skb->len <= ETH_HLEN)) return -EINVAL; @@ -998,10 +1003,10 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (!wcid) wcid = &dev->mt76.global_wcid; - mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key, - false); + pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); - cb->wcid = wcid->idx; + mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid, key, + false); txp = (struct mt7915_txp *)(txwi + MT_TXD_SIZE); for (i = 0; i < nbuf; i++) { @@ -1088,9 +1093,7 @@ static void mt7915_txwi_free(struct mt7915_dev *dev, struct mt76_txwi_cache *t, struct ieee80211_sta *sta, struct list_head *free_list) { - struct ieee80211_tx_status status = {}; struct mt76_dev *mdev = &dev->mt76; - struct ieee80211_tx_info *info; struct mt76_wcid *wcid; __le32 *txwi; u16 wcid_idx; @@ -1110,26 +1113,6 @@ mt7915_txwi_free(struct mt7915_dev *dev, struct mt76_txwi_cache *t, wcid_idx = FIELD_GET(MT_TXD1_WLAN_IDX, le32_to_cpu(txwi[1])); } - info = IEEE80211_SKB_CB(t->skb); - if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { - struct ieee80211_hw *hw; - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) - info->flags |= IEEE80211_TX_STAT_ACK; - - info->status.rates[0].count = 0; - info->status.rates[0].idx = -1; - - status.skb = t->skb; - status.sta = sta; - status.info = info; - - hw = mt76_tx_status_get_hw(mdev, t->skb); - ieee80211_tx_status_ext(hw, &status); - - goto out; - } - __mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list); out: @@ -1221,11 +1204,89 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) } } +static bool +mt7915_mac_add_txs_skb(struct mt7915_dev *dev, struct mt76_wcid *wcid, int pid, + __le32 *txs_data) +{ + struct mt76_dev *mdev = &dev->mt76; + struct ieee80211_tx_info *info; + struct sk_buff_head list; + struct sk_buff *skb; + + mt76_tx_status_lock(mdev, &list); + skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); + if (!skb) + goto out; + + info = IEEE80211_SKB_CB(skb); + if (!(txs_data[0] & le32_to_cpu(MT_TXS0_ACK_ERROR_MASK))) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.ampdu_len = 1; + info->status.ampdu_ack_len = !!(info->flags & + IEEE80211_TX_STAT_ACK); + + info->status.rates[0].idx = -1; + mt76_tx_status_skb_done(mdev, skb, &list); + +out: + mt76_tx_status_unlock(mdev, &list); + + return !!skb; +} + +static void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data) +{ + struct mt7915_sta *msta = NULL; + struct mt76_wcid *wcid; + __le32 *txs_data = data; + u16 wcidx; + u32 txs; + u8 pid; + + txs = le32_to_cpu(txs_data[0]); + if (FIELD_GET(MT_TXS0_TXS_FORMAT, txs) > 1) + return; + + txs = le32_to_cpu(txs_data[2]); + wcidx = FIELD_GET(MT_TXS2_WCID, txs); + + txs = le32_to_cpu(txs_data[3]); + pid = FIELD_GET(MT_TXS3_PID, txs); + + if (pid < MT_PACKET_ID_FIRST) + return; + + if (wcidx >= MT7915_WTBL_SIZE) + return; + + rcu_read_lock(); + + wcid = rcu_dereference(dev->mt76.wcid[wcidx]); + if (!wcid) + goto out; + + mt7915_mac_add_txs_skb(dev, wcid, pid, txs_data); + + if (!wcid->sta) + goto out; + + msta = container_of(wcid, struct mt7915_sta, wcid); + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&msta->poll_list)) + list_add_tail(&msta->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + +out: + rcu_read_unlock(); +} + void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb) { struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); __le32 *rxd = (__le32 *)skb->data; + __le32 *end = (__le32 *)&skb->data[skb->len]; enum rx_pkt_type type; type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0])); @@ -1240,6 +1301,11 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, case PKT_TYPE_TXRXV: mt7915_mac_fill_rx_vector(dev, skb); break; + case PKT_TYPE_TXS: + for (rxd += 2; rxd + 8 <= end; rxd += 8) + mt7915_mac_add_txs(dev, rxd); + dev_kfree_skb(skb); + break; case PKT_TYPE_NORMAL: if (!mt7915_mac_fill_rx(dev, skb)) { mt76_rx(&dev->mt76, q, skb); @@ -1775,6 +1841,8 @@ void mt7915_mac_work(struct work_struct *work) mutex_unlock(&mphy->dev->mutex); + mt76_tx_status_check(mphy->dev, NULL, false); + ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, MT7915_WATCHDOG_TIME); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h index 0f929fb53027..eb1885f4bd8e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -304,6 +304,62 @@ struct mt7915_tx_free { /* will support this field in further revision */ #define MT_TX_FREE_RATE GENMASK(13, 0) +#define MT_TXS0_FIXED_RATE BIT(31) +#define MT_TXS0_BW GENMASK(30, 29) +#define MT_TXS0_TID GENMASK(28, 26) +#define MT_TXS0_AMPDU BIT(25) +#define MT_TXS0_TXS_FORMAT GENMASK(24, 23) +#define MT_TXS0_BA_ERROR BIT(22) +#define MT_TXS0_PS_FLAG BIT(21) +#define MT_TXS0_TXOP_TIMEOUT BIT(20) +#define MT_TXS0_BIP_ERROR BIT(19) + +#define MT_TXS0_QUEUE_TIMEOUT BIT(18) +#define MT_TXS0_RTS_TIMEOUT BIT(17) +#define MT_TXS0_ACK_TIMEOUT BIT(16) +#define MT_TXS0_ACK_ERROR_MASK GENMASK(18, 16) + +#define MT_TXS0_TX_STATUS_HOST BIT(15) +#define MT_TXS0_TX_STATUS_MCU BIT(14) +#define MT_TXS0_TX_RATE GENMASK(13, 0) + +#define MT_TXS1_SEQNO GENMASK(31, 20) +#define MT_TXS1_RESP_RATE GENMASK(19, 16) +#define MT_TXS1_RXV_SEQNO GENMASK(15, 8) +#define MT_TXS1_TX_POWER_DBM GENMASK(7, 0) + +#define MT_TXS2_BF_STATUS GENMASK(31, 30) +#define MT_TXS2_LAST_TX_RATE GENMASK(29, 27) +#define MT_TXS2_SHARED_ANTENNA BIT(26) +#define MT_TXS2_WCID GENMASK(25, 16) +#define MT_TXS2_TX_DELAY GENMASK(15, 0) + +#define MT_TXS3_PID GENMASK(31, 24) +#define MT_TXS3_ANT_ID GENMASK(23, 0) + +#define MT_TXS4_TIMESTAMP GENMASK(31, 0) + +#define MT_TXS5_F0_FINAL_MPDU BIT(31) +#define MT_TXS5_F0_QOS BIT(30) +#define MT_TXS5_F0_TX_COUNT GENMASK(29, 25) +#define MT_TXS5_F0_FRONT_TIME GENMASK(24, 0) +#define MT_TXS5_F1_MPDU_TX_COUNT GENMASK(31, 24) +#define MT_TXS5_F1_MPDU_TX_BYTES GENMASK(23, 0) + +#define MT_TXS6_F0_NOISE_3 GENMASK(31, 24) +#define MT_TXS6_F0_NOISE_2 GENMASK(23, 16) +#define MT_TXS6_F0_NOISE_1 GENMASK(15, 8) +#define MT_TXS6_F0_NOISE_0 GENMASK(7, 0) +#define MT_TXS6_F1_MPDU_FAIL_COUNT GENMASK(31, 24) +#define MT_TXS6_F1_MPDU_FAIL_BYTES GENMASK(23, 0) + +#define MT_TXS7_F0_RCPI_3 GENMASK(31, 24) +#define MT_TXS7_F0_RCPI_2 GENMASK(23, 16) +#define MT_TXS7_F0_RCPI_1 GENMASK(15, 8) +#define MT_TXS7_F0_RCPI_0 GENMASK(7, 0) +#define MT_TXS7_F1_MPDU_RETRY_COUNT GENMASK(31, 24) +#define MT_TXS7_F1_MPDU_RETRY_BYTES GENMASK(23, 0) + struct mt7915_dfs_pulse { u32 max_width; /* us */ int max_pwr; /* dbm */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 9ec414de317e..76e8aa604e8b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -2440,7 +2440,7 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct sk_buff *rskb, cont->csa_ofs = cpu_to_le16(offs->cntdwn_counter_offs[0] - 4); buf = (u8 *)tlv + sizeof(*cont); - mt7915_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL, + mt7915_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, NULL, true); memcpy(buf + MT_TXD_SIZE, skb->data, skb->len); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 0342729145e7..c4bf8edeb1dd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -395,7 +395,7 @@ void mt7915_mac_reset_counters(struct mt7915_phy *phy); void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy); void mt7915_mac_enable_nf(struct mt7915_dev *dev, bool ext_phy); void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, - struct sk_buff *skb, struct mt76_wcid *wcid, + struct sk_buff *skb, struct mt76_wcid *wcid, int pid, struct ieee80211_key_conf *key, bool beacon); void mt7915_mac_set_timing(struct mt7915_phy *phy); int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, From 54b8fdebe4f45aafb61a0c73872a50d53791b091 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 29 Apr 2021 18:32:56 +0200 Subject: [PATCH 012/170] mt76: move mt76_rates in mt76 module Move mt76_rates array in mt76 module and remove duplicated code since it is shared by all drivers Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 16 +++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 15 ++++++++ .../net/wireless/mediatek/mt76/mt7603/init.c | 32 ++--------------- .../net/wireless/mediatek/mt76/mt7615/init.c | 33 ++--------------- .../wireless/mediatek/mt76/mt7615/pci_init.c | 4 +-- .../wireless/mediatek/mt76/mt7615/usb_sdio.c | 4 +-- .../net/wireless/mediatek/mt76/mt76x02_util.c | 16 +++------ .../net/wireless/mediatek/mt76/mt7915/init.c | 36 +++---------------- .../net/wireless/mediatek/mt76/mt7921/init.c | 32 ++--------------- 9 files changed, 50 insertions(+), 138 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 03fe62837557..447bc9a3abb0 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -83,6 +83,22 @@ static const struct ieee80211_tpt_blink mt76_tpt_blink[] = { { .throughput = 300 * 1024, .blink_time = 50 }, }; +struct ieee80211_rate mt76_rates[] = { + CCK_RATE(0, 10), + CCK_RATE(1, 20), + CCK_RATE(2, 55), + CCK_RATE(3, 110), + OFDM_RATE(11, 60), + OFDM_RATE(15, 90), + OFDM_RATE(10, 120), + OFDM_RATE(14, 180), + OFDM_RATE(9, 240), + OFDM_RATE(13, 360), + OFDM_RATE(8, 480), + OFDM_RATE(12, 540), +}; +EXPORT_SYMBOL_GPL(mt76_rates); + static int mt76_led_init(struct mt76_dev *dev) { struct device_node *np = dev->dev->of_node; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index d3859eda2a4f..ebacd55cb0cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -738,6 +738,21 @@ enum mt76_phy_type { MT_PHY_TYPE_HE_MU, }; +#define CCK_RATE(_idx, _rate) { \ + .bitrate = _rate, \ + .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ + .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ + .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + _idx), \ +} + +#define OFDM_RATE(_idx, _rate) { \ + .bitrate = _rate, \ + .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ + .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ +} + +extern struct ieee80211_rate mt76_rates[12]; + #define __mt76_rr(dev, ...) (dev)->bus->rr((dev), __VA_ARGS__) #define __mt76_wr(dev, ...) (dev)->bus->wr((dev), __VA_ARGS__) #define __mt76_rmw(dev, ...) (dev)->bus->rmw((dev), __VA_ARGS__) diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c index e1b2cfa56074..031d39a48a55 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c @@ -304,34 +304,6 @@ mt7603_init_hardware(struct mt7603_dev *dev) return 0; } -#define CCK_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ - .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ - .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + _idx), \ -} - -#define OFDM_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ - .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ -} - -static struct ieee80211_rate mt7603_rates[] = { - CCK_RATE(0, 10), - CCK_RATE(1, 20), - CCK_RATE(2, 55), - CCK_RATE(3, 110), - OFDM_RATE(11, 60), - OFDM_RATE(15, 90), - OFDM_RATE(10, 120), - OFDM_RATE(14, 180), - OFDM_RATE(9, 240), - OFDM_RATE(13, 360), - OFDM_RATE(8, 480), - OFDM_RATE(12, 540), -}; - static const struct ieee80211_iface_limit if_limits[] = { { .max = 1, @@ -569,8 +541,8 @@ int mt7603_register_device(struct mt7603_dev *dev) wiphy->reg_notifier = mt7603_regd_notifier; - ret = mt76_register_device(&dev->mt76, true, mt7603_rates, - ARRAY_SIZE(mt7603_rates)); + ret = mt76_register_device(&dev->mt76, true, mt76_rates, + ARRAY_SIZE(mt76_rates)); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index d20f05a7717d..ecc3ca9eb658 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -174,35 +174,6 @@ bool mt7615_wait_for_mcu_init(struct mt7615_dev *dev) } EXPORT_SYMBOL_GPL(mt7615_wait_for_mcu_init); -#define CCK_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ - .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ - .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + (_idx)), \ -} - -#define OFDM_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ - .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ -} - -struct ieee80211_rate mt7615_rates[] = { - CCK_RATE(0, 10), - CCK_RATE(1, 20), - CCK_RATE(2, 55), - CCK_RATE(3, 110), - OFDM_RATE(11, 60), - OFDM_RATE(15, 90), - OFDM_RATE(10, 120), - OFDM_RATE(14, 180), - OFDM_RATE(9, 240), - OFDM_RATE(13, 360), - OFDM_RATE(8, 480), - OFDM_RATE(12, 540), -}; -EXPORT_SYMBOL_GPL(mt7615_rates); - static const struct ieee80211_iface_limit if_limits[] = { { .max = 1, @@ -472,8 +443,8 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) for (i = 0; i <= MT_TXQ_PSD ; i++) mphy->q_tx[i] = dev->mphy.q_tx[i]; - ret = mt76_register_phy(mphy, true, mt7615_rates, - ARRAY_SIZE(mt7615_rates)); + ret = mt76_register_phy(mphy, true, mt76_rates, + ARRAY_SIZE(mt76_rates)); if (ret) ieee80211_free_hw(mphy->hw); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c index ec8ec1a2033f..273fda08bfa2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c @@ -147,8 +147,8 @@ int mt7615_register_device(struct mt7615_dev *dev) if (ret) return ret; - ret = mt76_register_device(&dev->mt76, true, mt7615_rates, - ARRAY_SIZE(mt7615_rates)); + ret = mt76_register_device(&dev->mt76, true, mt76_rates, + ARRAY_SIZE(mt76_rates)); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c index f8d3673c2cae..b2b02614f8e9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c @@ -323,8 +323,8 @@ int mt7663_usb_sdio_register_device(struct mt7615_dev *dev) hw->max_tx_fragments = 1; } - err = mt76_register_device(&dev->mt76, true, mt7615_rates, - ARRAY_SIZE(mt7615_rates)); + err = mt76_register_device(&dev->mt76, true, mt76_rates, + ARRAY_SIZE(mt76_rates)); if (err < 0) return err; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 02db5d66735d..ccdbab341271 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -7,24 +7,18 @@ #include #include "mt76x02.h" -#define CCK_RATE(_idx, _rate) { \ +#define MT76x02_CCK_RATE(_idx, _rate) { \ .bitrate = _rate, \ .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + (_idx)), \ } -#define OFDM_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ - .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ -} - struct ieee80211_rate mt76x02_rates[] = { - CCK_RATE(0, 10), - CCK_RATE(1, 20), - CCK_RATE(2, 55), - CCK_RATE(3, 110), + MT76x02_CCK_RATE(0, 10), + MT76x02_CCK_RATE(1, 20), + MT76x02_CCK_RATE(2, 55), + MT76x02_CCK_RATE(3, 110), OFDM_RATE(0, 60), OFDM_RATE(1, 90), OFDM_RATE(2, 120), diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index a8fd822cc46e..c103175d9954 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -7,34 +7,6 @@ #include "mcu.h" #include "eeprom.h" -#define CCK_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ - .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ - .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + (_idx)), \ -} - -#define OFDM_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ - .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ -} - -static struct ieee80211_rate mt7915_rates[] = { - CCK_RATE(0, 10), - CCK_RATE(1, 20), - CCK_RATE(2, 55), - CCK_RATE(3, 110), - OFDM_RATE(11, 60), - OFDM_RATE(15, 90), - OFDM_RATE(10, 120), - OFDM_RATE(14, 180), - OFDM_RATE(9, 240), - OFDM_RATE(13, 360), - OFDM_RATE(8, 480), - OFDM_RATE(12, 540), -}; - static const struct ieee80211_iface_limit if_limits[] = { { .max = 1, @@ -281,8 +253,8 @@ static int mt7915_register_ext_phy(struct mt7915_dev *dev) if (ret) goto error; - ret = mt76_register_phy(mphy, true, mt7915_rates, - ARRAY_SIZE(mt7915_rates)); + ret = mt76_register_phy(mphy, true, mt76_rates, + ARRAY_SIZE(mt76_rates)); if (ret) goto error; @@ -731,8 +703,8 @@ int mt7915_register_device(struct mt7915_dev *dev) dev->mt76.test_ops = &mt7915_testmode_ops; #endif - ret = mt76_register_device(&dev->mt76, true, mt7915_rates, - ARRAY_SIZE(mt7915_rates)); + ret = mt76_register_device(&dev->mt76, true, mt76_rates, + ARRAY_SIZE(mt76_rates)); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 1763ea0614ce..703f36bedc17 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -7,34 +7,6 @@ #include "mcu.h" #include "eeprom.h" -#define CCK_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ - .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ - .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + (_idx)), \ -} - -#define OFDM_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ - .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ -} - -static struct ieee80211_rate mt7921_rates[] = { - CCK_RATE(0, 10), - CCK_RATE(1, 20), - CCK_RATE(2, 55), - CCK_RATE(3, 110), - OFDM_RATE(11, 60), - OFDM_RATE(15, 90), - OFDM_RATE(10, 120), - OFDM_RATE(14, 180), - OFDM_RATE(9, 240), - OFDM_RATE(13, 360), - OFDM_RATE(8, 480), - OFDM_RATE(12, 540), -}; - static const struct ieee80211_iface_limit if_limits[] = { { .max = MT7921_MAX_INTERFACES, @@ -260,8 +232,8 @@ int mt7921_register_device(struct mt7921_dev *dev) mt76_set_stream_caps(&dev->mphy, true); mt7921_set_stream_he_caps(&dev->phy); - ret = mt76_register_device(&dev->mt76, true, mt7921_rates, - ARRAY_SIZE(mt7921_rates)); + ret = mt76_register_device(&dev->mt76, true, mt76_rates, + ARRAY_SIZE(mt76_rates)); if (ret) return ret; From 64cf5ad3c2fa841e4b416343a7ea69c63d60fa4e Mon Sep 17 00:00:00 2001 From: Evelyn Tsai Date: Mon, 3 May 2021 16:04:37 +0800 Subject: [PATCH 013/170] mt76: mt7915: fix tssi indication field of DBDC NICs Correct the bitfield which indicates TSSI on/off for MT7915D NIC. Signed-off-by: Evelyn Tsai Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h index 033fb592bdf0..7896e983209a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h @@ -99,12 +99,15 @@ static inline bool mt7915_tssi_enabled(struct mt7915_dev *dev, enum nl80211_band band) { u8 *eep = dev->mt76.eeprom.data; + u8 val = eep[MT_EE_WIFI_CONF + 7]; - /* TODO: DBDC */ - if (band == NL80211_BAND_5GHZ) - return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF7_TSSI0_5G; + if (band == NL80211_BAND_2GHZ) + return val & MT_EE_WIFI_CONF7_TSSI0_2G; + + if (dev->dbdc_support) + return val & MT_EE_WIFI_CONF7_TSSI1_5G; else - return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF7_TSSI0_2G; + return val & MT_EE_WIFI_CONF7_TSSI0_5G; } extern const u8 mt7915_sku_group_len[MAX_SKU_RATE_GROUP_NUM]; From 861fad474ec7638aeca46a508da4ea81612374b9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 3 May 2021 17:53:59 +0300 Subject: [PATCH 014/170] mt76: mt7915: fix a signedness bug in mt7915_mcu_apply_tx_dpd() "idx" needs to be signed for the error handling to work. Fixes: 495184ac91bb ("mt76: mt7915: add support for applying pre-calibration data") Signed-off-by: Dan Carpenter Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 76e8aa604e8b..ce7c55fda6cf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -3448,8 +3448,9 @@ int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; struct cfg80211_chan_def *chandef = &phy->mt76->chandef; - u16 total = 2, idx, center_freq = chandef->center_freq1; + u16 total = 2, center_freq = chandef->center_freq1; u8 *cal = dev->cal, *eep = dev->mt76.eeprom.data; + int idx; if (!(eep[MT_EE_DO_PRE_CAL] & MT_EE_WIFI_CAL_DPD)) return 0; From 5b0b5c6a1c2195942ac48ec8bbf567789f903353 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 May 2021 20:13:32 +0200 Subject: [PATCH 015/170] mt76: mt7921: enable rx hw de-amsdu Enable hw rx-amsdu de-aggregation support available in 7921 devices. This is a preliminary patch to enable rx checksum offload. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 16 +++++++++++++++- drivers/net/wireless/mediatek/mt76/mt7921/mac.h | 3 +++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 703f36bedc17..73741e148240 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -125,8 +125,8 @@ void mt7921_mac_init(struct mt7921_dev *dev) int i; mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 1536); - /* disable hardware de-agg */ - mt76_clear(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN); + /* enable hardware de-agg */ + mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN); mt76_clear(dev, MT_MDP_DCR0, MT_MDP_DCR0_RX_HDR_TRANS_EN); for (i = 0; i < MT7921_WTBL_SIZE; i++) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index decf2d5f0ce3..7e57d230e63a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -319,8 +319,9 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) u32 rxd1 = le32_to_cpu(rxd[1]); u32 rxd2 = le32_to_cpu(rxd[2]); u32 rxd3 = le32_to_cpu(rxd[3]); + u32 rxd4 = le32_to_cpu(rxd[4]); bool unicast, insert_ccmp_hdr = false; - u8 remove_pad; + u8 remove_pad, amsdu_info; int i, idx; u8 chfreq; @@ -332,6 +333,9 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) if (!test_bit(MT76_STATE_RUNNING, &mphy->state)) return -EINVAL; + if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR) + return -EINVAL; + chfreq = FIELD_GET(MT_RXD3_NORMAL_CH_FREQ, rxd3); unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M; idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1); @@ -540,6 +544,16 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) skb_pull(skb, (u8 *)rxd - skb->data + 2 * remove_pad); + amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4); + status->amsdu = !!amsdu_info; + if (status->amsdu) { + status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME; + status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME; + memmove(skb->data + 2, skb->data, + ieee80211_get_hdrlen_from_skb(skb)); + skb_pull(skb, 2); + } + if (insert_ccmp_hdr) { u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h index 109c8849d106..435c138c27d1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h @@ -88,6 +88,9 @@ enum rx_pkt_type { /* RXD DW4 */ #define MT_RXD4_NORMAL_PAYLOAD_FORMAT GENMASK(1, 0) +#define MT_RXD4_FIRST_AMSDU_FRAME GENMASK(1, 0) +#define MT_RXD4_MID_AMSDU_FRAME BIT(1) +#define MT_RXD4_LAST_AMSDU_FRAME BIT(0) #define MT_RXD4_NORMAL_PATTERN_DROP BIT(9) #define MT_RXD4_NORMAL_CLS BIT(10) #define MT_RXD4_NORMAL_OFLD GENMASK(12, 11) From 868fe07ee612f81a493504190cdfcc9d344c9dc3 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 May 2021 20:13:33 +0200 Subject: [PATCH 016/170] mt76: connac: add missing configuration in mt76_connac_mcu_wtbl_hdr_trans_tlv Add missing configuration parameters in mt76_connac_mcu_wtbl_hdr_trans_tlv routine Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 8 ++++---- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 11 +++++++++++ drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index aa42af9ebfd6..32a2cb76b583 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1037,8 +1037,8 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif, if (sta) mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, wskb, sta, NULL, wtbl_hdr); - mt76_connac_mcu_wtbl_hdr_trans_tlv(wskb, &msta->wcid, NULL, - wtbl_hdr); + mt76_connac_mcu_wtbl_hdr_trans_tlv(wskb, vif, &msta->wcid, + NULL, wtbl_hdr); } cmd = enable ? MCU_EXT_CMD_WTBL_UPDATE : MCU_EXT_CMD_STA_REC_UPDATE; @@ -1167,8 +1167,8 @@ int mt7615_mcu_sta_update_hdr_trans(struct mt7615_dev *dev, if (IS_ERR(wtbl_hdr)) return PTR_ERR(wtbl_hdr); - mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, &msta->wcid, NULL, wtbl_hdr); - + mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, &msta->wcid, NULL, + wtbl_hdr); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_WTBL_UPDATE, true); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 619561606f96..443e5109c1d9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -393,6 +393,7 @@ mt76_connac_mcu_sta_uapsd(struct sk_buff *skb, struct ieee80211_vif *vif, } void mt76_connac_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb, + struct ieee80211_vif *vif, struct mt76_wcid *wcid, void *sta_wtbl, void *wtbl_tlv) { @@ -404,6 +405,16 @@ void mt76_connac_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb, wtbl_tlv, sta_wtbl); htr = (struct wtbl_hdr_trans *)tlv; htr->no_rx_trans = !test_bit(MT_WCID_FLAG_HDR_TRANS, &wcid->flags); + + if (vif->type == NL80211_IFTYPE_STATION) + htr->to_ds = true; + else + htr->from_ds = true; + + if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) { + htr->to_ds = true; + htr->from_ds = true; + } } EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_hdr_trans_tlv); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index a1096861d04a..f0493924fa89 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -969,6 +969,7 @@ void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_sta *sta, void *sta_wtbl, void *wtbl_tlv); void mt76_connac_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb, + struct ieee80211_vif *vif, struct mt76_wcid *wcid, void *sta_wtbl, void *wtbl_tlv); void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, From 24299fc869f7caded8ae30a33f205ab37be729d4 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 May 2021 20:13:34 +0200 Subject: [PATCH 017/170] mt76: mt7921: enable rx header traslation offload As already done for mt7615 and mt7915, enable rx header translation offload for mt7921 in order to reduce cpu load in the rx path. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.c | 29 +++++++++++ .../wireless/mediatek/mt76/mt76_connac_mcu.h | 3 ++ .../net/wireless/mediatek/mt76/mt7921/init.c | 4 +- .../net/wireless/mediatek/mt76/mt7921/mac.c | 52 +++++++++++++------ .../net/wireless/mediatek/mt76/mt7921/mac.h | 11 ++++ .../net/wireless/mediatek/mt76/mt7921/main.c | 18 +++++++ 6 files changed, 101 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 443e5109c1d9..7b8f8e6f431d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -418,6 +418,33 @@ void mt76_connac_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb, } EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_hdr_trans_tlv); +int mt76_connac_mcu_sta_update_hdr_trans(struct mt76_dev *dev, + struct ieee80211_vif *vif, + struct mt76_wcid *wcid, int cmd) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct wtbl_req_hdr *wtbl_hdr; + struct tlv *sta_wtbl; + struct sk_buff *skb; + + skb = mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, + sizeof(struct tlv)); + + wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(dev, wcid, WTBL_SET, + sta_wtbl, &skb); + if (IS_ERR(wtbl_hdr)) + return PTR_ERR(wtbl_hdr); + + mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, wcid, sta_wtbl, wtbl_hdr); + + return mt76_mcu_skb_send_msg(dev, skb, cmd, true); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_update_hdr_trans); + void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_vif *vif, @@ -870,6 +897,8 @@ int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy, mt76_connac_mcu_wtbl_generic_tlv(dev, skb, info->vif, info->sta, sta_wtbl, wtbl_hdr); + mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, info->vif, info->wcid, + sta_wtbl, wtbl_hdr); if (info->sta) mt76_connac_mcu_wtbl_ht_tlv(dev, skb, info->sta, sta_wtbl, wtbl_hdr); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index f0493924fa89..01fc9f2c2f4a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -972,6 +972,9 @@ void mt76_connac_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct mt76_wcid *wcid, void *sta_wtbl, void *wtbl_tlv); +int mt76_connac_mcu_sta_update_hdr_trans(struct mt76_dev *dev, + struct ieee80211_vif *vif, + struct mt76_wcid *wcid, int cmd); void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, struct ieee80211_sta *sta, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 73741e148240..d5ad92a440c3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -78,6 +78,7 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); ieee80211_hw_set(hw, HAS_RATE_CONTROL); ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD); + ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); ieee80211_hw_set(hw, WANT_MONITOR_VIF); ieee80211_hw_set(hw, SUPPORTS_PS); ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); @@ -127,7 +128,8 @@ void mt7921_mac_init(struct mt7921_dev *dev) mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 1536); /* enable hardware de-agg */ mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN); - mt76_clear(dev, MT_MDP_DCR0, MT_MDP_DCR0_RX_HDR_TRANS_EN); + /* enable hardware rx header translation */ + mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_RX_HDR_TRANS_EN); for (i = 0; i < MT7921_WTBL_SIZE; i++) mt7921_mac_wtbl_update(dev, i, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 7e57d230e63a..74974f689462 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -309,6 +309,8 @@ mt7921_mac_assoc_rssi(struct mt7921_dev *dev, struct sk_buff *skb) int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; + bool hdr_trans, unicast, insert_ccmp_hdr = false; + u8 chfreq, qos_ctl = 0, remove_pad, amsdu_info; struct mt76_phy *mphy = &dev->mt76.phy; struct mt7921_phy *phy = &dev->phy; struct ieee80211_supported_band *sband; @@ -320,10 +322,9 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) u32 rxd2 = le32_to_cpu(rxd[2]); u32 rxd3 = le32_to_cpu(rxd[3]); u32 rxd4 = le32_to_cpu(rxd[4]); - bool unicast, insert_ccmp_hdr = false; - u8 remove_pad, amsdu_info; + u16 seq_ctrl = 0; + __le16 fc = 0; int i, idx; - u8 chfreq; memset(status, 0, sizeof(*status)); @@ -339,6 +340,7 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) chfreq = FIELD_GET(MT_RXD3_NORMAL_CH_FREQ, rxd3); unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M; idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1); + hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS; status->wcid = mt7921_rx_get_wcid(dev, idx, unicast); if (status->wcid) { @@ -381,6 +383,13 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) rxd += 6; if (rxd1 & MT_RXD1_NORMAL_GROUP_4) { + u32 v0 = le32_to_cpu(rxd[0]); + u32 v2 = le32_to_cpu(rxd[2]); + + fc = cpu_to_le16(FIELD_GET(MT_RXD6_FRAME_CONTROL, v0)); + seq_ctrl = FIELD_GET(MT_RXD8_SEQ_CTRL, v2); + qos_ctl = FIELD_GET(MT_RXD8_QOS_CTL, v2); + rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; @@ -549,15 +558,30 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) if (status->amsdu) { status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME; status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME; - memmove(skb->data + 2, skb->data, - ieee80211_get_hdrlen_from_skb(skb)); - skb_pull(skb, 2); + if (!hdr_trans) { + memmove(skb->data + 2, skb->data, + ieee80211_get_hdrlen_from_skb(skb)); + skb_pull(skb, 2); + } } - if (insert_ccmp_hdr) { - u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1); + if (!hdr_trans) { + if (insert_ccmp_hdr) { + u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1); - mt76_insert_ccmp_hdr(skb, key_id); + mt76_insert_ccmp_hdr(skb, key_id); + } + + hdr = mt76_skb_get_hdr(skb); + fc = hdr->frame_control; + if (ieee80211_is_data_qos(fc)) { + seq_ctrl = le16_to_cpu(hdr->seq_ctrl); + qos_ctl = *ieee80211_get_qos_ctl(hdr); + } + } else { + status->flag &= ~(RX_FLAG_RADIOTAP_HE | + RX_FLAG_RADIOTAP_HE_MU); + status->flag |= RX_FLAG_8023; } mt7921_mac_assoc_rssi(dev, skb); @@ -565,14 +589,12 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) if (rxv && status->flag & RX_FLAG_RADIOTAP_HE) mt7921_mac_decode_he_radiotap(skb, status, rxv, mode); - hdr = mt76_skb_get_hdr(skb); - if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control)) + if (!status->wcid || !ieee80211_is_data_qos(fc)) return 0; - status->aggr = unicast && - !ieee80211_is_qos_nullfunc(hdr->frame_control); - status->qos_ctl = *ieee80211_get_qos_ctl(hdr); - status->seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + status->aggr = unicast && !ieee80211_is_qos_nullfunc(fc); + status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl); + status->qos_ctl = qos_ctl; return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h index 435c138c27d1..3af67fac213d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h @@ -100,6 +100,17 @@ enum rx_pkt_type { #define MT_RXD3_NORMAL_PF_MODE BIT(29) #define MT_RXD3_NORMAL_PF_STS GENMASK(31, 30) +/* RXD GROUP4 */ +#define MT_RXD6_FRAME_CONTROL GENMASK(15, 0) +#define MT_RXD6_TA_LO GENMASK(31, 16) + +#define MT_RXD7_TA_HI GENMASK(31, 0) + +#define MT_RXD8_SEQ_CTRL GENMASK(15, 0) +#define MT_RXD8_QOS_CTL GENMASK(31, 16) + +#define MT_RXD9_HT_CONTROL GENMASK(31, 0) + /* P-RXV DW0 */ #define MT_PRXV_TX_RATE GENMASK(6, 0) #define MT_PRXV_TX_DCM BIT(4) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 97a0ef331ac3..8016f8377c8f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -1163,6 +1163,23 @@ static void mt7921_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, HZ / 2); } +static void mt7921_sta_set_decap_offload(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + bool enabled) +{ + struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; + struct mt7921_dev *dev = mt7921_hw_dev(hw); + + if (enabled) + set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); + else + clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); + + mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76, vif, &msta->wcid, + MCU_UNI_CMD_STA_REC_UPDATE); +} + const struct ieee80211_ops mt7921_ops = { .tx = mt7921_tx, .start = mt7921_start, @@ -1177,6 +1194,7 @@ const struct ieee80211_ops mt7921_ops = { .sta_remove = mt7921_sta_remove, .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, .set_key = mt7921_set_key, + .sta_set_decap_offload = mt7921_sta_set_decap_offload, .ampdu_action = mt7921_ampdu_action, .set_rts_threshold = mt7921_set_rts_threshold, .wake_tx_queue = mt76_wake_tx_queue, From 0e75732764e86a7741d7807b4408cd02cbaf1e0c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 6 May 2021 20:13:35 +0200 Subject: [PATCH 018/170] mt76: mt7921: enable rx csum offload As already done for mt7615 and mt7915, enable hw rx checksum offload. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 1 + drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index d5ad92a440c3..b899b82bbf04 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -50,6 +50,7 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) hw->queues = 4; hw->max_rx_aggregation_subframes = 64; hw->max_tx_aggregation_subframes = 128; + hw->netdev_features = NETIF_F_RXCSUM; hw->radiotap_timestamp.units_pos = IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 74974f689462..44b8918db95b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -308,22 +308,23 @@ mt7921_mac_assoc_rssi(struct mt7921_dev *dev, struct sk_buff *skb) int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) { + u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM; struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; bool hdr_trans, unicast, insert_ccmp_hdr = false; u8 chfreq, qos_ctl = 0, remove_pad, amsdu_info; + __le32 *rxv = NULL, *rxd = (__le32 *)skb->data; struct mt76_phy *mphy = &dev->mt76.phy; struct mt7921_phy *phy = &dev->phy; struct ieee80211_supported_band *sband; struct ieee80211_hdr *hdr; - __le32 *rxd = (__le32 *)skb->data; - __le32 *rxv = NULL; - u32 mode = 0; + u32 rxd0 = le32_to_cpu(rxd[0]); u32 rxd1 = le32_to_cpu(rxd[1]); u32 rxd2 = le32_to_cpu(rxd[2]); u32 rxd3 = le32_to_cpu(rxd[3]); u32 rxd4 = le32_to_cpu(rxd[4]); u16 seq_ctrl = 0; __le16 fc = 0; + u32 mode = 0; int i, idx; memset(status, 0, sizeof(*status)); @@ -363,6 +364,9 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) if (!sband->channels) return -EINVAL; + if ((rxd0 & csum_mask) == csum_mask) + skb->ip_summed = CHECKSUM_UNNECESSARY; + if (rxd1 & MT_RXD1_NORMAL_FCS_ERR) status->flag |= RX_FLAG_FAILED_FCS_CRC; From a441a77a736cd20e2f6529be4d610e5956bac6fa Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 27 Apr 2021 07:14:26 +0800 Subject: [PATCH 019/170] mt76: mt7915: cleanup mt7915_mcu_sta_rate_ctrl_tlv() Remove obsoleted codes. This is the preparation for .set_bitrate_mask(). Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/mcu.c | 74 +++++-------------- .../net/wireless/mediatek/mt76/mt7915/mcu.h | 2 +- 2 files changed, 21 insertions(+), 55 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index ce7c55fda6cf..b22dfdc39f1e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -147,10 +147,10 @@ mt7915_get_he_phy_cap(struct mt7915_phy *phy, struct ieee80211_vif *vif) } static u8 -mt7915_get_phy_mode(struct mt76_phy *mphy, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +mt7915_get_phy_mode(struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - enum nl80211_band band = mphy->chandef.chan->band; + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + enum nl80211_band band = mvif->phy->mt76->chandef.chan->band; struct ieee80211_sta_ht_cap *ht_cap; struct ieee80211_sta_vht_cap *vht_cap; const struct ieee80211_sta_he_cap *he_cap; @@ -163,7 +163,7 @@ mt7915_get_phy_mode(struct mt76_phy *mphy, struct ieee80211_vif *vif, } else { struct ieee80211_supported_band *sband; - sband = mphy->hw->wiphy->bands[band]; + sband = mvif->phy->mt76->hw->wiphy->bands[band]; ht_cap = &sband->ht_cap; vht_cap = &sband->vht_cap; @@ -741,7 +741,7 @@ mt7915_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN); bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); bss->dtim_period = vif->bss_conf.dtim_period; - bss->phy_mode = mt7915_get_phy_mode(phy->mt76, vif, NULL); + bss->phy_mode = mt7915_get_phy_mode(vif, NULL); } else { memcpy(bss->bssid, phy->mt76->macaddr, ETH_ALEN); } @@ -2087,47 +2087,39 @@ static void mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; - struct mt76_phy *mphy = &dev->mphy; - enum nl80211_band band; + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef; + enum nl80211_band band = chandef->chan->band; struct sta_rec_ra *ra; struct tlv *tlv; - u32 supp_rate, n_rates, cap = sta->wme ? STA_CAP_WMM : 0; - u8 i, nss = sta->rx_nss, mcs = 0; + u32 supp_rate = sta->supp_rates[band]; + u32 cap = sta->wme ? STA_CAP_WMM : 0; + u8 i, nss = sta->rx_nss; tlv = mt7915_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra)); ra = (struct sta_rec_ra *)tlv; - if (msta->wcid.ext_phy && dev->mt76.phy2) - mphy = dev->mt76.phy2; - - band = mphy->chandef.chan->band; - supp_rate = sta->supp_rates[band]; - n_rates = hweight32(supp_rate); - ra->valid = true; ra->auto_rate = true; - ra->phy_mode = mt7915_get_phy_mode(mphy, vif, sta); - ra->channel = mphy->chandef.chan->hw_value; + ra->phy_mode = mt7915_get_phy_mode(vif, sta); + ra->channel = chandef->chan->hw_value; ra->bw = sta->bandwidth; - ra->rate_len = n_rates; ra->phy.bw = sta->bandwidth; - if (n_rates) { + if (supp_rate) { + ra->rate_len = hweight32(supp_rate); + if (band == NL80211_BAND_2GHZ) { ra->supp_mode = MODE_CCK; ra->supp_cck_rate = supp_rate & GENMASK(3, 0); - ra->phy.type = MT_PHY_TYPE_CCK; - if (n_rates > 4) { + if (ra->rate_len > 4) { ra->supp_mode |= MODE_OFDM; ra->supp_ofdm_rate = supp_rate >> 4; - ra->phy.type = MT_PHY_TYPE_OFDM; } } else { ra->supp_mode = MODE_OFDM; ra->supp_ofdm_rate = supp_rate; - ra->phy.type = MT_PHY_TYPE_OFDM; } } @@ -2137,7 +2129,6 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs; ra->supp_mode |= MODE_HT; - mcs = hweight32(le32_to_cpu(ra->supp_ht_mcs)) - 1; ra->af = sta->ht_cap.ampdu_factor; ra->ht_gf = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD); @@ -2157,7 +2148,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, if (sta->vht_cap.vht_supported) { u16 mcs_map = le16_to_cpu(sta->vht_cap.vht_mcs.rx_mcs_map); u16 vht_mcs; - u8 af, mcs_prev; + u8 af; af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, sta->vht_cap.cap); @@ -2176,7 +2167,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, cap |= STA_CAP_VHT_LDPC; ra->supp_mode |= MODE_VHT; - for (mcs = 0, i = 0; i < nss; i++, mcs_map >>= 2) { + for (i = 0; i < nss; i++, mcs_map >>= 2) { switch (mcs_map & 0x3) { case IEEE80211_VHT_MCS_SUPPORT_0_9: vht_mcs = GENMASK(9, 0); @@ -2193,10 +2184,6 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, ra->supp_vht_mcs[i] = cpu_to_le16(vht_mcs); - mcs_prev = hweight16(vht_mcs) - 1; - if (mcs_prev > mcs) - mcs = mcs_prev; - /* only support 2ss on 160MHz */ if (i > 1 && (ra->bw == CMD_CBW_160MHZ || ra->bw == CMD_CBW_8080MHZ)) @@ -2209,28 +2196,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, cap |= STA_CAP_HE; } - ra->sta_status = cpu_to_le32(cap); - - switch (BIT(fls(ra->supp_mode) - 1)) { - case MODE_VHT: - ra->phy.type = MT_PHY_TYPE_VHT; - ra->phy.mcs = mcs; - ra->phy.nss = nss; - ra->phy.stbc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC); - ra->phy.ldpc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); - ra->phy.sgi = - !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80); - break; - case MODE_HT: - ra->phy.type = MT_PHY_TYPE_HT; - ra->phy.mcs = mcs; - ra->phy.ldpc = sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING; - ra->phy.stbc = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC); - ra->phy.sgi = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20); - break; - default: - break; - } + ra->sta_cap = cpu_to_le32(cap); } int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 42582a66e42d..f95920d58a40 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -919,7 +919,7 @@ struct sta_rec_ra { u8 op_vht_rx_nss; u8 op_vht_rx_nss_type; - __le32 sta_status; + __le32 sta_cap; struct ra_phy phy; } __packed; From 76be6c076c0774844670df818233c488538bae02 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 27 Apr 2021 07:14:27 +0800 Subject: [PATCH 020/170] mt76: mt7915: add .set_bitrate_mask() callback Add runtime configuration for bitrate mask. This update firmware rate control to add a boundary on top of table to limit the rate selection for each peer, so when user set bitrates vht-mcs-5 1:9, which actually means nss = 1 mcs = 0~9. This only applies to data frames as for other mgmt, mcast, bcast still use legacy rates as it is. Note that driver does not support GI configuration. Example: iw dev wlan0 set bitrates vht-mcs-5 1:9 he-mcs-5 2:7 iw dev wlan0 set bitrates legacy-5 6 he-mcs-5 2:0-11 Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/mac.c | 4 +- .../net/wireless/mediatek/mt76/mt7915/main.c | 64 +++++- .../net/wireless/mediatek/mt76/mt7915/mcu.c | 185 ++++++++++++++---- .../wireless/mediatek/mt76/mt7915/mt7915.h | 3 + 4 files changed, 213 insertions(+), 43 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index f8bb043f9be7..642a11e72bef 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1804,8 +1804,10 @@ void mt7915_mac_sta_rc_work(struct work_struct *work) if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED | IEEE80211_RC_NSS_CHANGED | - IEEE80211_RC_BW_CHANGED)) + IEEE80211_RC_BW_CHANGED)) { + mt7915_mcu_add_he(dev, vif, sta); mt7915_mcu_add_rate_ctrl(dev, vif, sta); + } if (changed & IEEE80211_RC_SMPS_CHANGED) mt7915_mcu_add_smps(dev, vif, sta); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index e5bd687546b6..64f9ebe4424a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -172,6 +172,22 @@ static int get_omac_idx(enum nl80211_iftype type, u64 mask) return -1; } +static void mt7915_init_bitrate_mask(struct ieee80211_vif *vif) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + int i; + + for (i = 0; i < ARRAY_SIZE(mvif->bitrate_mask.control); i++) { + mvif->bitrate_mask.control[i].legacy = GENMASK(31, 0); + memset(mvif->bitrate_mask.control[i].ht_mcs, GENMASK(7, 0), + sizeof(mvif->bitrate_mask.control[i].ht_mcs)); + memset(mvif->bitrate_mask.control[i].vht_mcs, GENMASK(15, 0), + sizeof(mvif->bitrate_mask.control[i].vht_mcs)); + memset(mvif->bitrate_mask.control[i].he_mcs, GENMASK(15, 0), + sizeof(mvif->bitrate_mask.control[i].he_mcs)); + } +} + static int mt7915_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -241,6 +257,8 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, vif->offload_flags = 0; vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR; + mt7915_init_bitrate_mask(vif); + out: mutex_unlock(&dev->mt76.mutex); @@ -911,17 +929,15 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw, sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); } -static void -mt7915_sta_rc_update(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - u32 changed) +static void mt7915_sta_rc_work(void *data, struct ieee80211_sta *sta) { - struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt7915_dev *dev = msta->vif->phy->dev; + struct ieee80211_hw *hw = msta->vif->phy->mt76->hw; + u32 *changed = data; spin_lock_bh(&dev->sta_poll_lock); - msta->stats.changed |= changed; + msta->stats.changed |= *changed; if (list_empty(&msta->rc_list)) list_add_tail(&msta->rc_list, &dev->sta_rc_list); spin_unlock_bh(&dev->sta_poll_lock); @@ -929,6 +945,39 @@ mt7915_sta_rc_update(struct ieee80211_hw *hw, ieee80211_queue_work(hw, &dev->rc_work); } +static void mt7915_sta_rc_update(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + u32 changed) +{ + mt7915_sta_rc_work(&changed, sta); +} + +static int +mt7915_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + enum nl80211_band band = mvif->phy->mt76->chandef.chan->band; + u32 changed; + + if (mask->control[band].gi == NL80211_TXRATE_FORCE_LGI) + return -EINVAL; + + changed = IEEE80211_RC_SUPP_RATES_CHANGED; + mvif->bitrate_mask = *mask; + + /* Update firmware rate control to add a boundary on top of table + * to limit the rate selection for each peer, so when set bitrates + * vht-mcs-5 1:9, which actually means nss = 1 mcs = 0~9. This only + * applies to data frames as for the other mgmt, mcast, bcast still + * use legacy rates as it is. + */ + ieee80211_iterate_stations_atomic(hw, mt7915_sta_rc_work, &changed); + + return 0; +} + static void mt7915_sta_set_4addr(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -990,6 +1039,7 @@ const struct ieee80211_ops mt7915_ops = { .get_survey = mt76_get_survey, .get_antenna = mt76_get_antenna, .set_antenna = mt7915_set_antenna, + .set_bitrate_mask = mt7915_set_bitrate_mask, .set_coverage_class = mt7915_set_coverage_class, .sta_statistics = mt7915_sta_statistics, .sta_set_4addr = mt7915_sta_set_4addr, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index b22dfdc39f1e..e5302ff4c9dd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -209,6 +209,112 @@ mt7915_mcu_get_sta_nss(u16 mcs_map) return nss - 1; } +static void +mt7915_mcu_set_sta_he_mcs(struct ieee80211_sta *sta, __le16 *he_mcs, + const u16 *mask) +{ + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct cfg80211_chan_def *chandef = &msta->vif->phy->mt76->chandef; + int nss, max_nss = sta->rx_nss > 3 ? 4 : sta->rx_nss; + u16 mcs_map; + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_80P80: + mcs_map = le16_to_cpu(sta->he_cap.he_mcs_nss_supp.rx_mcs_80p80); + break; + case NL80211_CHAN_WIDTH_160: + mcs_map = le16_to_cpu(sta->he_cap.he_mcs_nss_supp.rx_mcs_160); + break; + default: + mcs_map = le16_to_cpu(sta->he_cap.he_mcs_nss_supp.rx_mcs_80); + break; + } + + for (nss = 0; nss < max_nss; nss++) { + int mcs; + + switch ((mcs_map >> (2 * nss)) & 0x3) { + case IEEE80211_HE_MCS_SUPPORT_0_11: + mcs = GENMASK(11, 0); + break; + case IEEE80211_HE_MCS_SUPPORT_0_9: + mcs = GENMASK(9, 0); + break; + case IEEE80211_HE_MCS_SUPPORT_0_7: + mcs = GENMASK(7, 0); + break; + default: + mcs = 0; + } + + mcs = mcs ? fls(mcs & mask[nss]) - 1 : -1; + + switch (mcs) { + case 0 ... 7: + mcs = IEEE80211_HE_MCS_SUPPORT_0_7; + break; + case 8 ... 9: + mcs = IEEE80211_HE_MCS_SUPPORT_0_9; + break; + case 10 ... 11: + mcs = IEEE80211_HE_MCS_SUPPORT_0_11; + break; + default: + mcs = IEEE80211_HE_MCS_NOT_SUPPORTED; + break; + } + mcs_map &= ~(0x3 << (nss * 2)); + mcs_map |= mcs << (nss * 2); + + /* only support 2ss on 160MHz */ + if (nss > 1 && (sta->bandwidth == IEEE80211_STA_RX_BW_160)) + break; + } + + *he_mcs = cpu_to_le16(mcs_map); +} + +static void +mt7915_mcu_set_sta_vht_mcs(struct ieee80211_sta *sta, __le16 *vht_mcs, + const u16 *mask) +{ + u16 mcs_map = le16_to_cpu(sta->vht_cap.vht_mcs.rx_mcs_map); + int nss, max_nss = sta->rx_nss > 3 ? 4 : sta->rx_nss; + u16 mcs; + + for (nss = 0; nss < max_nss; nss++, mcs_map >>= 2) { + switch (mcs_map & 0x3) { + case IEEE80211_VHT_MCS_SUPPORT_0_9: + mcs = GENMASK(9, 0); + break; + case IEEE80211_VHT_MCS_SUPPORT_0_8: + mcs = GENMASK(8, 0); + break; + case IEEE80211_VHT_MCS_SUPPORT_0_7: + mcs = GENMASK(7, 0); + break; + default: + mcs = 0; + } + + vht_mcs[nss] = cpu_to_le16(mcs & mask[nss]); + + /* only support 2ss on 160MHz */ + if (nss > 1 && (sta->bandwidth == IEEE80211_STA_RX_BW_160)) + break; + } +} + +static void +mt7915_mcu_set_sta_ht_mcs(struct ieee80211_sta *sta, u8 *ht_mcs, + const u8 *mask) +{ + int nss, max_nss = sta->rx_nss > 3 ? 4 : sta->rx_nss; + + for (nss = 0; nss < max_nss; nss++) + ht_mcs[nss] = sta->ht_cap.mcs.rx_mask[nss] & mask[nss]; +} + static int mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd, struct sk_buff *skb, int seq) @@ -1344,8 +1450,11 @@ mt7915_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, static void mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) { + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; + enum nl80211_band band = msta->vif->phy->mt76->chandef.chan->band; + const u16 *mcs_mask = msta->vif->bitrate_mask.control[band].he_mcs; struct sta_rec_he *he; struct tlv *tlv; u32 cap = 0; @@ -1436,15 +1545,18 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) case IEEE80211_STA_RX_BW_160: if (elem->phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) - he->max_nss_mcs[CMD_HE_MCS_BW8080] = - he_cap->he_mcs_nss_supp.rx_mcs_80p80; + mt7915_mcu_set_sta_he_mcs(sta, + &he->max_nss_mcs[CMD_HE_MCS_BW8080], + mcs_mask); - he->max_nss_mcs[CMD_HE_MCS_BW160] = - he_cap->he_mcs_nss_supp.rx_mcs_160; + mt7915_mcu_set_sta_he_mcs(sta, + &he->max_nss_mcs[CMD_HE_MCS_BW160], + mcs_mask); fallthrough; default: - he->max_nss_mcs[CMD_HE_MCS_BW80] = - he_cap->he_mcs_nss_supp.rx_mcs_80; + mt7915_mcu_set_sta_he_mcs(sta, + &he->max_nss_mcs[CMD_HE_MCS_BW80], + mcs_mask); break; } @@ -2089,12 +2201,12 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef; + struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask; enum nl80211_band band = chandef->chan->band; struct sta_rec_ra *ra; struct tlv *tlv; u32 supp_rate = sta->supp_rates[band]; u32 cap = sta->wme ? STA_CAP_WMM : 0; - u8 i, nss = sta->rx_nss; tlv = mt7915_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra)); ra = (struct sta_rec_ra *)tlv; @@ -2107,6 +2219,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, ra->phy.bw = sta->bandwidth; if (supp_rate) { + supp_rate &= mask->control[band].legacy; ra->rate_len = hweight32(supp_rate); if (band == NL80211_BAND_2GHZ) { @@ -2124,10 +2237,8 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, } if (sta->ht_cap.ht_supported) { - for (i = 0; i < nss; i++) - ra->ht_mcs[i] = sta->ht_cap.mcs.rx_mask[i]; + const u8 *mcs_mask = mask->control[band].ht_mcs; - ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs; ra->supp_mode |= MODE_HT; ra->af = sta->ht_cap.ampdu_factor; ra->ht_gf = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD); @@ -2143,13 +2254,16 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, cap |= STA_CAP_RX_STBC; if (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING) cap |= STA_CAP_LDPC; + + mt7915_mcu_set_sta_ht_mcs(sta, ra->ht_mcs, mcs_mask); + ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs; } if (sta->vht_cap.vht_supported) { - u16 mcs_map = le16_to_cpu(sta->vht_cap.vht_mcs.rx_mcs_map); - u16 vht_mcs; + const u16 *mcs_mask = mask->control[band].vht_mcs; u8 af; + ra->supp_mode |= MODE_VHT; af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, sta->vht_cap.cap); ra->af = max_t(u8, ra->af, af); @@ -2166,29 +2280,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, if (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC) cap |= STA_CAP_VHT_LDPC; - ra->supp_mode |= MODE_VHT; - for (i = 0; i < nss; i++, mcs_map >>= 2) { - switch (mcs_map & 0x3) { - case IEEE80211_VHT_MCS_SUPPORT_0_9: - vht_mcs = GENMASK(9, 0); - break; - case IEEE80211_VHT_MCS_SUPPORT_0_8: - vht_mcs = GENMASK(8, 0); - break; - case IEEE80211_VHT_MCS_SUPPORT_0_7: - vht_mcs = GENMASK(7, 0); - break; - default: - vht_mcs = 0; - } - - ra->supp_vht_mcs[i] = cpu_to_le16(vht_mcs); - - /* only support 2ss on 160MHz */ - if (i > 1 && (ra->bw == CMD_CBW_160MHZ || - ra->bw == CMD_CBW_8080MHZ)) - break; - } + mt7915_mcu_set_sta_vht_mcs(sta, ra->supp_vht_mcs, mcs_mask); } if (sta->he_cap.has_he) { @@ -2217,6 +2309,29 @@ int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, MCU_EXT_CMD(STA_REC_UPDATE), true); } +int mt7915_mcu_add_he(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct sk_buff *skb; + int len; + + if (!sta->he_cap.has_he) + return 0; + + len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_he); + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt7915_mcu_sta_he_tlv(skb, sta); + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD(STA_REC_UPDATE), true); +} + int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index c4bf8edeb1dd..47341876da09 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -100,6 +100,7 @@ struct mt7915_vif { struct mt7915_phy *phy; struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; + struct cfg80211_bitrate_mask bitrate_mask; }; struct mib_stats { @@ -323,6 +324,8 @@ int mt7915_mcu_add_obss_spr(struct mt7915_dev *dev, struct ieee80211_vif *vif, bool enable); int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); +int mt7915_mcu_add_he(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); int mt7915_set_channel(struct mt7915_phy *phy); From d7400a2f3e295b8cee692c7a66e10f60015a3c37 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 27 Apr 2021 12:05:00 +0200 Subject: [PATCH 021/170] mt76: fix possible NULL pointer dereference in mt76_tx Even if this is not a real issue since mt76_tx is never run with wcid set to NULL, fix a theoretical NULL pointer dereference in mt76_tx routine Fixes: db9f11d3433f7 ("mt76: store wcid tx rate info in one u32 reduce locking") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 70a830132a37..5cc3e4d75c4f 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -306,7 +306,7 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta, skb_set_queue_mapping(skb, qid); } - if (!(wcid->tx_info & MT_WCID_TX_INFO_SET)) + if (wcid && !(wcid->tx_info & MT_WCID_TX_INFO_SET)) ieee80211_get_tx_rates(info->control.vif, sta, skb, info->control.rates, 1); From 8d3cdc1bbb1d355f0ebef973175ae5fd74286feb Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 27 Apr 2021 12:07:14 +0200 Subject: [PATCH 022/170] mt76: mt7615: fix NULL pointer dereference in tx_prepare_skb() Fix theoretical NULL pointer dereference in mt7615_tx_prepare_skb and mt7663_usb_sdio_tx_prepare_skb routines. This issue has been identified by code analysis. Fixes: 6aa4ed7927f11 ("mt76: mt7615: implement DMA support for MT7622") Fixes: 4bb586bc33b98 ("mt76: mt7663u: sync probe sampling with rate configuration") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c | 5 +++-- drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c index d7cbef752f9f..cc278d8cb888 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c @@ -131,20 +131,21 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, struct mt76_tx_info *tx_info) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); - struct mt7615_sta *msta = container_of(wcid, struct mt7615_sta, wcid); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); struct ieee80211_key_conf *key = info->control.hw_key; int pid, id; u8 *txwi = (u8 *)txwi_ptr; struct mt76_txwi_cache *t; + struct mt7615_sta *msta; void *txp; + msta = wcid ? container_of(wcid, struct mt7615_sta, wcid) : NULL; if (!wcid) wcid = &dev->mt76.global_wcid; pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); - if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) { + if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && msta) { struct mt7615_phy *phy = &dev->phy; if ((info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY) && mdev->phy2) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c index b2b02614f8e9..75a05f8dd7e7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c @@ -191,14 +191,15 @@ int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, struct ieee80211_sta *sta, struct mt76_tx_info *tx_info) { - struct mt7615_sta *msta = container_of(wcid, struct mt7615_sta, wcid); struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); struct sk_buff *skb = tx_info->skb; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct mt7615_sta *msta; int pad; + msta = wcid ? container_of(wcid, struct mt7615_sta, wcid) : NULL; if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && - !msta->rate_probe) { + msta && !msta->rate_probe) { /* request to configure sampling rate */ spin_lock_bh(&dev->mt76.lock); mt7615_mac_set_rates(&dev->phy, msta, &info->control.rates[0], From 47cbf73cf924ce2202332f61e705f4ed9bd6a74e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 7 May 2021 12:26:11 +0200 Subject: [PATCH 023/170] mt76: mt76x0: use dev_debug instead of dev_err for hw_rf_ctrl BIT(0) in MT_EE_NIC_CONF_1 is use to notify the driver if the radio RF switch is controlled through a gpio. Use dev_debug instead of dev_err to log this info. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index dd66fd12a2e6..cea24213186c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -68,7 +68,7 @@ static void mt76x0_set_chip_cap(struct mt76x02_dev *dev) nic_conf1 &= 0xff00; if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL) - dev_err(dev->mt76.dev, + dev_dbg(dev->mt76.dev, "driver does not support HW RF ctrl\n"); if (!mt76x02_field_valid(nic_conf0 >> 8)) From 2f83054342dcce87e2f47b60af9aa7cfbcf4b80e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 10 May 2021 09:13:03 +0200 Subject: [PATCH 024/170] mt76: mt7615: free irq if mt7615_mmio_probe fails As already done for mt7915 and mt7921, free registered irq line if mt7615_mmio_probe routine fails Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mmio.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c index 202ea235415e..71719c787511 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c @@ -229,7 +229,7 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, GFP_KERNEL); if (!bus_ops) { ret = -ENOMEM; - goto error; + goto err_free_dev; } bus_ops->rr = mt7615_rr; @@ -242,17 +242,20 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, ret = devm_request_irq(mdev->dev, irq, mt7615_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) - goto error; + goto err_free_dev; if (is_mt7663(mdev)) mt76_wr(dev, MT_PCIE_IRQ_ENABLE, 1); ret = mt7615_register_device(dev); if (ret) - goto error; + goto err_free_irq; return 0; -error: + +err_free_irq: + devm_free_irq(pdev, irq, dev); +err_free_dev: mt76_free_device(&dev->mt76); return ret; From 54c31b9e6507cd8183a27fa862cc3a407a332076 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 10 May 2021 10:13:07 +0200 Subject: [PATCH 025/170] mt76: mt7663: enable hw rx header translation As already done for mt7615 and mt7915, enable rx header translation offload for mt7663 in order to reduce cpu load in the rx path. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7615/main.c | 2 +- .../net/wireless/mediatek/mt76/mt7615/mcu.c | 66 +++++++++++++------ .../wireless/mediatek/mt76/mt7615/mt7615.h | 7 +- 3 files changed, 52 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 39733b351ac4..faae60775b16 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -1162,7 +1162,7 @@ static void mt7615_sta_set_decap_offload(struct ieee80211_hw *hw, else clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); - mt7615_mcu_sta_update_hdr_trans(dev, vif, sta); + mt7615_mcu_set_sta_decap_offload(dev, vif, sta); } #ifdef CONFIG_PM diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 32a2cb76b583..32090e01b4d2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1058,6 +1058,26 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif, return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true); } +static int +mt7615_mcu_wtbl_update_hdr_trans(struct mt7615_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; + struct wtbl_req_hdr *wtbl_hdr; + struct sk_buff *skb = NULL; + + wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid, + WTBL_SET, NULL, &skb); + if (IS_ERR(wtbl_hdr)) + return PTR_ERR(wtbl_hdr); + + mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, &msta->wcid, NULL, + wtbl_hdr); + return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_WTBL_UPDATE, + true); +} + static const struct mt7615_mcu_ops wtbl_update_ops = { .add_beacon_offload = mt7615_mcu_add_beacon_offload, .set_pm_state = mt7615_mcu_ctrl_pm_state, @@ -1068,6 +1088,7 @@ static const struct mt7615_mcu_ops wtbl_update_ops = { .sta_add = mt7615_mcu_wtbl_sta_add, .set_drv_ctrl = mt7615_mcu_drv_pmctrl, .set_fw_ctrl = mt7615_mcu_fw_pmctrl, + .set_sta_decap_offload = mt7615_mcu_wtbl_update_hdr_trans, }; static int @@ -1142,6 +1163,18 @@ mt7615_mcu_add_sta(struct mt7615_phy *phy, struct ieee80211_vif *vif, MCU_EXT_CMD_STA_REC_UPDATE); } +static int +mt7615_mcu_sta_update_hdr_trans(struct mt7615_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; + + return mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76, + vif, &msta->wcid, + MCU_EXT_CMD_STA_REC_UPDATE); +} + static const struct mt7615_mcu_ops sta_update_ops = { .add_beacon_offload = mt7615_mcu_add_beacon_offload, .set_pm_state = mt7615_mcu_ctrl_pm_state, @@ -1152,27 +1185,9 @@ static const struct mt7615_mcu_ops sta_update_ops = { .sta_add = mt7615_mcu_add_sta, .set_drv_ctrl = mt7615_mcu_drv_pmctrl, .set_fw_ctrl = mt7615_mcu_fw_pmctrl, + .set_sta_decap_offload = mt7615_mcu_sta_update_hdr_trans, }; -int mt7615_mcu_sta_update_hdr_trans(struct mt7615_dev *dev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; - struct wtbl_req_hdr *wtbl_hdr; - struct sk_buff *skb = NULL; - - wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid, - WTBL_SET, NULL, &skb); - if (IS_ERR(wtbl_hdr)) - return PTR_ERR(wtbl_hdr); - - mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, &msta->wcid, NULL, - wtbl_hdr); - return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_WTBL_UPDATE, - true); -} - static int mt7615_mcu_uni_ctrl_pm_state(struct mt7615_dev *dev, int band, int state) { @@ -1338,6 +1353,18 @@ mt7615_mcu_uni_rx_ba(struct mt7615_dev *dev, MCU_UNI_CMD_STA_REC_UPDATE, true); } +static int +mt7615_mcu_sta_uni_update_hdr_trans(struct mt7615_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; + + return mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76, + vif, &msta->wcid, + MCU_UNI_CMD_STA_REC_UPDATE); +} + static const struct mt7615_mcu_ops uni_update_ops = { .add_beacon_offload = mt7615_mcu_uni_add_beacon_offload, .set_pm_state = mt7615_mcu_uni_ctrl_pm_state, @@ -1348,6 +1375,7 @@ static const struct mt7615_mcu_ops uni_update_ops = { .sta_add = mt7615_mcu_uni_add_sta, .set_drv_ctrl = mt7615_mcu_lp_drv_pmctrl, .set_fw_ctrl = mt7615_mcu_fw_pmctrl, + .set_sta_decap_offload = mt7615_mcu_sta_uni_update_hdr_trans, }; int mt7615_mcu_restart(struct mt76_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 989f05ed4377..2ba86bd96a31 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -202,6 +202,7 @@ struct mt7615_phy { #define mt7615_mcu_set_pm(dev, ...) (dev)->mcu_ops->set_pm_state((dev), __VA_ARGS__) #define mt7615_mcu_set_drv_ctrl(dev) (dev)->mcu_ops->set_drv_ctrl((dev)) #define mt7615_mcu_set_fw_ctrl(dev) (dev)->mcu_ops->set_fw_ctrl((dev)) +#define mt7615_mcu_set_sta_decap_offload(dev, ...) (dev)->mcu_ops->set_sta_decap_offload((dev), __VA_ARGS__) struct mt7615_mcu_ops { int (*add_tx_ba)(struct mt7615_dev *dev, struct ieee80211_ampdu_params *params, @@ -221,6 +222,9 @@ struct mt7615_mcu_ops { int (*set_pm_state)(struct mt7615_dev *dev, int band, int state); int (*set_drv_ctrl)(struct mt7615_dev *dev); int (*set_fw_ctrl)(struct mt7615_dev *dev); + int (*set_sta_decap_offload)(struct mt7615_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta); }; struct mt7615_dev { @@ -518,9 +522,6 @@ void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, void mt7615_mac_work(struct work_struct *work); void mt7615_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *txwi); -int mt7615_mcu_sta_update_hdr_trans(struct mt7615_dev *dev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); int mt7615_mcu_set_rx_hdr_trans_blacklist(struct mt7615_dev *dev); int mt7615_mcu_set_fcc5_lpn(struct mt7615_dev *dev, int val); int mt7615_mcu_set_pulse_th(struct mt7615_dev *dev, From 20eb83c749609199443972cf80fb6004fc36afc6 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Mon, 10 May 2021 23:14:49 +0800 Subject: [PATCH 026/170] mt76: mt7921: fix mt7921_wfsys_reset sequence WiFi subsytem reset should control MT_WFSYS_SW_RST_B and then poll the same register until the bit WFSYS_SW_INIT_DONE bit is set. Fixes: 0c1ce9884607 ("mt76: mt7921: add wifi reset support") Reviewed-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/dma.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c index 71e664ee7652..bd9143dc865f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c @@ -313,9 +313,9 @@ static int mt7921_dma_reset(struct mt7921_dev *dev, bool force) int mt7921_wfsys_reset(struct mt7921_dev *dev) { - mt76_set(dev, 0x70002600, BIT(0)); - msleep(200); - mt76_clear(dev, 0x70002600, BIT(0)); + mt76_clear(dev, MT_WFSYS_SW_RST_B, WFSYS_SW_RST_B); + msleep(50); + mt76_set(dev, MT_WFSYS_SW_RST_B, WFSYS_SW_RST_B); if (!__mt76_poll_msec(&dev->mt76, MT_WFSYS_SW_RST_B, WFSYS_SW_INIT_DONE, WFSYS_SW_INIT_DONE, 500)) From 2c80c02a682aefc073df2cfbb48c77c74579cb4a Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Mon, 10 May 2021 23:14:50 +0800 Subject: [PATCH 027/170] mt76: mt7921: Don't alter Rx path classifier Keep Rx path classifier the mt7921 firmware prefers to allow frames pass through MCU. Fixes: 5c14a5f944b9 ("mt76: mt7921: introduce mt7921e support") Reviewed-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7921/init.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index b899b82bbf04..9a28da5abb11 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -90,30 +90,12 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) static void mt7921_mac_init_band(struct mt7921_dev *dev, u8 band) { - u32 mask, set; - mt76_rmw_field(dev, MT_TMAC_CTCR0(band), MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f); mt76_set(dev, MT_TMAC_CTCR0(band), MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN | MT_TMAC_CTCR0_INS_DDLMT_EN); - mask = MT_MDP_RCFR0_MCU_RX_MGMT | - MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR | - MT_MDP_RCFR0_MCU_RX_CTL_BAR; - set = FIELD_PREP(MT_MDP_RCFR0_MCU_RX_MGMT, MT_MDP_TO_HIF) | - FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR, MT_MDP_TO_HIF) | - FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_BAR, MT_MDP_TO_HIF); - mt76_rmw(dev, MT_MDP_BNRCFR0(band), mask, set); - - mask = MT_MDP_RCFR1_MCU_RX_BYPASS | - MT_MDP_RCFR1_RX_DROPPED_UCAST | - MT_MDP_RCFR1_RX_DROPPED_MCAST; - set = FIELD_PREP(MT_MDP_RCFR1_MCU_RX_BYPASS, MT_MDP_TO_HIF) | - FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_UCAST, MT_MDP_TO_HIF) | - FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_MCAST, MT_MDP_TO_HIF); - mt76_rmw(dev, MT_MDP_BNRCFR1(band), mask, set); - mt76_set(dev, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); From 4bfa291251623486711693a69d9eaa539478d340 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Mon, 10 May 2021 23:14:51 +0800 Subject: [PATCH 028/170] mt76: connac: fw_own rely on all packet memory all being free If the device is MMIO-based, we must ensure all TxD/TxP on the host memory all being consumed by the device prior to safely switching to fw_own state. Fixes: ec7bd7b4a9c0 ("mt76: connac: check wake refcount in mcu_fw_pmctrl") Reviewed-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 6c889b90fd12..337c5ece7ec3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -127,8 +127,12 @@ mt76_connac_pm_unref(struct mt76_connac_pm *pm) static inline bool mt76_connac_skip_fw_pmctrl(struct mt76_phy *phy, struct mt76_connac_pm *pm) { + struct mt76_dev *dev = phy->dev; bool ret; + if (dev->token_count) + return true; + spin_lock_bh(&pm->wake.lock); ret = pm->wake.count || test_and_set_bit(MT76_STATE_PM, &phy->state); spin_unlock_bh(&pm->wake.lock); From 7bf0a71e839822bb6ba04a6e163ad334314e2659 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Thu, 20 May 2021 11:46:37 +0800 Subject: [PATCH 029/170] mt76: mt7921: fix reset under the deep sleep is enabled To fix possibly the race to access register between the WiFi reset and the other context that is caused by explicitly cancelling ps_work and wake_work to break PM_STATE consistency. Deep sleep would cause the hardware into the inactive state, so we forcely put device drv_own state before we start to reset. The patch also ignore the reset request when the procedure is in progress to avoid the consecutive WiFi resets. localhost ~ # [ 2932.073966] SError Interrupt on CPU7, code 0xbe000011 [ 2932.073967] CPU: 7 PID: 8761 Comm: kworker/u16:2 Not tainted 5.4.112 #30 [ 2932.073968] Hardware name: MediaTek Asurada rev1 board (DT) [ 2932.073968] Workqueue: phy0 ieee80211_reconfig_filter [mac80211] [ 2932.073969] pstate: 80400089 (Nzcv daIf +PAN -UAO) [ 2932.073969] pc : el1_irq+0x78/0x180 [ 2932.073970] lr : mt76_mmio_rmw+0x30/0x5c [mt76] [ 2932.073970] sp : ffffffc01142bad0 [ 2932.073970] x29: ffffffc01142bc00 x28: ffffff8f96fb1e00 [ 2932.073971] x27: ffffffd2cdc12138 x26: ffffffd2cdaeb018 [ 2932.073972] x25: 0000000000000000 x24: ffffff8fa8e14c08 [ 2932.073973] x23: 0000000080c00009 x22: ffffffd2a5603918 [ 2932.073974] x21: ffffffc01142bc10 x20: 0000007fffffffff [ 2932.073975] x19: 0000000000000000 x18: 0000000000000400 [ 2932.073975] x17: 0000000000000400 x16: ffffffd2cd2b87dc [ 2932.073976] x15: 0000000000000000 x14: 0000000000000000 [ 2932.073977] x13: 0000000000000001 x12: 0000000000000001 [ 2932.073978] x11: 0000000000000001 x10: 000000000010e000 [ 2932.073978] x9 : 0000000000000000 x8 : ffffffc013921404 [ 2932.073979] x7 : 000000b2b5593519 x6 : 0000000000300000 [ 2932.073980] x5 : 0000000000000000 x4 : ffffffc01142bbc8 [ 2932.073980] x3 : 00000000000001f0 x2 : 0000000000000000 [ 2932.073981] x1 : 0000000000021404 x0 : ffffff8fa8e12300 [ 2932.073982] Kernel panic - not syncing: Asynchronous SError Interrupt [ 2932.073983] CPU: 7 PID: 8761 Comm: kworker/u16:2 Not tainted 5.4.112 #30 [ 2932.073983] Hardware name: MediaTek Asurada rev1 board (DT) [ 2932.073984] Workqueue: phy0 ieee80211_reconfig_filter [mac80211] [ 2932.073984] Call trace: [ 2932.073985] dump_backtrace+0x0/0x14c [ 2932.073985] show_stack+0x20/0x2c [ 2932.073985] dump_stack+0xa0/0xf8 [ 2932.073986] panic+0x154/0x360 [ 2932.073986] test_taint+0x0/0x44 [ 2932.073986] arm64_serror_panic+0x78/0x84 [ 2932.073987] do_serror+0x0/0x118 [ 2932.073987] do_serror+0xa4/0x118 [ 2932.073987] el1_error+0x84/0xf8 [ 2932.073988] el1_irq+0x78/0x180 [ 2932.073988] mt76_mmio_rr+0x30/0xf0 [mt76] [ 2932.073988] mt76_mmio_rmw+0x30/0x5c [mt76] [ 2932.073989] mt7921_rmw+0x4c/0x5c [mt7921e] [ 2932.073989] mt7921_configure_filter+0x138/0x160 [mt7921e] [ 2932.073990] ieee80211_configure_filter+0x2f0/0x3e0 [mac80211] [ 2932.073990] ieee80211_reconfig_filter+0x1c/0x28 [mac80211] [ 2932.073990] process_one_work+0x208/0x3c8 [ 2932.073991] worker_thread+0x23c/0x3e8 [ 2932.073991] kthread+0x140/0x17c [ 2932.073992] ret_from_fork+0x10/0x18 [ 2932.074071] SMP: stopping secondary CPUs [ 2932.074071] Kernel Offset: 0x12bc800000 from 0xffffffc010000000 [ 2932.074072] PHYS_OFFSET: 0xfffffff180000000 [ 2932.074072] CPU features: 0x080026,2a80aa18 [ 2932.074072] Memory Limit: none Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7921/mac.c | 21 +++++++++-------- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 23 ++++++++++++++----- .../wireless/mediatek/mt76/mt7921/mt7921.h | 1 + 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 44b8918db95b..31741da14099 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1281,9 +1281,10 @@ mt7921_mac_reset(struct mt7921_dev *dev) mt76_worker_enable(&dev->mt76.tx_worker); clear_bit(MT76_MCU_RESET, &dev->mphy.state); - clear_bit(MT76_STATE_PM, &dev->mphy.state); - mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0); + mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, + MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL | + MT_INT_MCU_CMD); mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); err = mt7921_run_firmware(dev); @@ -1301,22 +1302,23 @@ mt7921_mac_reset(struct mt7921_dev *dev) /* system error recovery */ void mt7921_mac_reset_work(struct work_struct *work) { - struct ieee80211_hw *hw; - struct mt7921_dev *dev; + struct mt7921_dev *dev = container_of(work, struct mt7921_dev, + reset_work); + struct ieee80211_hw *hw = mt76_hw(dev); + struct mt76_connac_pm *pm = &dev->pm; int i; - dev = container_of(work, struct mt7921_dev, reset_work); - hw = mt76_hw(dev); - dev_err(dev->mt76.dev, "chip reset\n"); ieee80211_stop_queues(hw); cancel_delayed_work_sync(&dev->mphy.mac_work); - cancel_delayed_work_sync(&dev->pm.ps_work); - cancel_work_sync(&dev->pm.wake_work); + cancel_delayed_work_sync(&pm->ps_work); + cancel_work_sync(&pm->wake_work); mutex_lock(&dev->mt76.mutex); for (i = 0; i < 10; i++) { + __mt7921_mcu_drv_pmctrl(dev); + if (!mt7921_mac_reset(dev)) break; } @@ -1337,6 +1339,7 @@ void mt7921_mac_reset_work(struct work_struct *work) ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7921_vif_connect_iter, NULL); + mt76_connac_power_save_sched(&dev->mt76.phy, pm); } void mt7921_reset(struct mt76_dev *mdev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 67dc4b4cc094..ef3e454862ad 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -1288,17 +1288,12 @@ int mt7921_mcu_sta_add(struct mt7921_dev *dev, struct ieee80211_sta *sta, return mt76_connac_mcu_add_sta_cmd(&dev->mphy, &info); } -int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) +int __mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_connac_pm *pm = &dev->pm; int i, err = 0; - mutex_lock(&pm->mutex); - - if (!test_bit(MT76_STATE_PM, &mphy->state)) - goto out; - for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) { mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_CLR_OWN); if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL, @@ -1318,6 +1313,22 @@ int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) pm->stats.last_wake_event = jiffies; pm->stats.doze_time += pm->stats.last_wake_event - pm->stats.last_doze_event; +out: + return err; +} + +int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) +{ + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt76_connac_pm *pm = &dev->pm; + int err = 0; + + mutex_lock(&pm->mutex); + + if (!test_bit(MT76_STATE_PM, &mphy->state)) + goto out; + + err = __mt7921_mcu_drv_pmctrl(dev); out: mutex_unlock(&pm->mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 59862ea4951c..03bcb210c357 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -368,6 +368,7 @@ int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, bool enable); int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, bool enable); +int __mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev); int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev); int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev); void mt7921_pm_wake_work(struct work_struct *work); From 193e5f22eeb2a9661bff8bc0d8519e6ded48c807 Mon Sep 17 00:00:00 2001 From: YN Chen Date: Mon, 10 May 2021 23:14:54 +0800 Subject: [PATCH 030/170] mt76: connac: fix WoW with disconnetion and bitmap pattern Update MCU command usage to fix WoW configuration with disconnection and bitmap pattern and to avoid magic number. Fixes: ffa1bf97425b ("mt76: mt7921: introduce PM support") Reviewed-by: Lorenzo Bianconi Signed-off-by: YN Chen Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 11 +++++++---- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h | 8 ++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 7b8f8e6f431d..54612a479215 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1979,7 +1979,7 @@ mt76_connac_mcu_set_wow_pattern(struct mt76_dev *dev, ptlv->index = index; memcpy(ptlv->pattern, pattern->pattern, pattern->pattern_len); - memcpy(ptlv->mask, pattern->mask, pattern->pattern_len / 8); + memcpy(ptlv->mask, pattern->mask, DIV_ROUND_UP(pattern->pattern_len, 8)); return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD_SUSPEND, true); } @@ -2014,14 +2014,17 @@ mt76_connac_mcu_set_wow_ctrl(struct mt76_phy *phy, struct ieee80211_vif *vif, }; if (wowlan->magic_pkt) - req.wow_ctrl_tlv.trigger |= BIT(0); + req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_MAGIC; if (wowlan->disconnect) - req.wow_ctrl_tlv.trigger |= BIT(2); + req.wow_ctrl_tlv.trigger |= (UNI_WOW_DETECT_TYPE_DISCONNECT | + UNI_WOW_DETECT_TYPE_BCN_LOST); if (wowlan->nd_config) { mt76_connac_mcu_sched_scan_req(phy, vif, wowlan->nd_config); - req.wow_ctrl_tlv.trigger |= BIT(5); + req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_SCH_SCAN_HIT; mt76_connac_mcu_sched_scan_enable(phy, vif, suspend); } + if (wowlan->n_patterns) + req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_BITMAP; if (mt76_is_mmio(dev)) req.wow_ctrl_tlv.wakeup_hif = WOW_PCIE; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 01fc9f2c2f4a..676b1c6bc959 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -590,6 +590,14 @@ enum { UNI_OFFLOAD_OFFLOAD_BMC_RPY_DETECT, }; +#define UNI_WOW_DETECT_TYPE_MAGIC BIT(0) +#define UNI_WOW_DETECT_TYPE_ANY BIT(1) +#define UNI_WOW_DETECT_TYPE_DISCONNECT BIT(2) +#define UNI_WOW_DETECT_TYPE_GTK_REKEY_FAIL BIT(3) +#define UNI_WOW_DETECT_TYPE_BCN_LOST BIT(4) +#define UNI_WOW_DETECT_TYPE_SCH_SCAN_HIT BIT(5) +#define UNI_WOW_DETECT_TYPE_BITMAP BIT(6) + enum { UNI_SUSPEND_MODE_SETTING, UNI_SUSPEND_WOW_CTRL, From edb5aebc1c3db312e74e1dcf75b8626ee5300596 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Mon, 10 May 2021 23:14:55 +0800 Subject: [PATCH 031/170] mt76: mt7921: consider the invalid value for to_rssi It is possible the RCPI from the certain antenna is an invalid value, especially packets are receiving while the system is frequently entering deep sleep mode, so consider calculating RSSI with the reasonable upper bound to avoid report the wrong value to the mac80211 layer. Fixes: 163f4d22c118 ("mt76: mt7921: add MAC support") Reviewed-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 31741da14099..96a6c0aabe06 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -461,16 +461,19 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v1); status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v1); status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v1); - status->signal = status->chain_signal[0]; - - for (i = 1; i < hweight8(mphy->antenna_mask); i++) { - if (!(status->chains & BIT(i))) + status->signal = -128; + for (i = 0; i < hweight8(mphy->antenna_mask); i++) { + if (!(status->chains & BIT(i)) || + status->chain_signal[i] >= 0) continue; status->signal = max(status->signal, status->chain_signal[i]); } + if (status->signal == -128) + status->flag |= RX_FLAG_NO_SIGNAL_VAL; + stbc = FIELD_GET(MT_PRXV_STBC, v0); gi = FIELD_GET(MT_PRXV_SGI, v0); cck = false; From 10de032a31683585292cd10b598d896d7bcf276f Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Mon, 10 May 2021 23:14:57 +0800 Subject: [PATCH 032/170] mt76: mt7921: add back connection monitor support Hw beacon cmd to the mt7921 firmware doesn't only filter out the beacon, but also performs its own connection monitoring, including periodic keep-alives to the AP and probing the AP on beacon loss. Will indicate the host with the event when the firmware detects the connection is lost. Fixes: 1d8efc741df8 ("mt76: mt7921: introduce Runtime PM support") Reviewed-by: Lorenzo Bianconi Signed-off-by: Deren Wu Signed-off-by: YN Chen Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7921/init.c | 4 +++ .../net/wireless/mediatek/mt76/mt7921/mcu.c | 32 +++++++++++++------ 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 9a28da5abb11..a3517ed76813 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -45,6 +45,7 @@ static void mt7921_init_wiphy(struct ieee80211_hw *hw) { struct mt7921_phy *phy = mt7921_hw_phy(hw); + struct mt7921_dev *dev = phy->dev; struct wiphy *wiphy = hw->wiphy; hw->queues = 4; @@ -84,6 +85,9 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) ieee80211_hw_set(hw, SUPPORTS_PS); ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); + if (dev->pm.enable) + ieee80211_hw_set(hw, CONNECTION_MONITOR); + hw->max_tx_fragments = 4; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index ef3e454862ad..06209d58ce27 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -450,22 +450,33 @@ mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb) } static void -mt7921_mcu_beacon_loss_event(struct mt7921_dev *dev, struct sk_buff *skb) +mt7921_mcu_connection_loss_iter(void *priv, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_connac_beacon_loss_event *event = priv; + + if (mvif->idx != event->bss_idx) + return; + + if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER)) + return; + + ieee80211_connection_loss(vif); +} + +static void +mt7921_mcu_connection_loss_event(struct mt7921_dev *dev, struct sk_buff *skb) { struct mt76_connac_beacon_loss_event *event; - struct mt76_phy *mphy; - u8 band_idx = 0; /* DBDC support */ + struct mt76_phy *mphy = &dev->mt76.phy; skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); event = (struct mt76_connac_beacon_loss_event *)skb->data; - if (band_idx && dev->mt76.phy2) - mphy = dev->mt76.phy2; - else - mphy = &dev->mt76.phy; ieee80211_iterate_active_interfaces_atomic(mphy->hw, IEEE80211_IFACE_ITER_RESUME_ALL, - mt76_connac_mcu_beacon_loss_iter, event); + mt7921_mcu_connection_loss_iter, event); } static void @@ -530,7 +541,7 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) switch (rxd->eid) { case MCU_EVENT_BSS_BEACON_LOSS: - mt7921_mcu_beacon_loss_event(dev, skb); + mt7921_mcu_connection_loss_event(dev, skb); break; case MCU_EVENT_SCHED_SCAN_DONE: case MCU_EVENT_SCAN_DONE: @@ -1379,6 +1390,7 @@ mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct mt7921_phy *phy = priv; struct mt7921_dev *dev = phy->dev; + struct ieee80211_hw *hw = mt76_hw(dev); int ret; if (dev->pm.enable) @@ -1391,9 +1403,11 @@ mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) if (dev->pm.enable) { vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + ieee80211_hw_set(hw, CONNECTION_MONITOR); mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); } else { vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; + __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags); mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); } } From 33fe9c639c13de03ce04a1dc2c904d66d1cd02eb Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 24 Apr 2021 06:02:04 +0800 Subject: [PATCH 033/170] mt76: mt7915: add thermal sensor device support This provides userspace with a unified interface, hwmon sysfs, to monitor temperature in the hardware and can be adapted to system monitoring tools. For reading temperature, cat /sys/class/ieee80211/phy*/hwmon*/temp1_input Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7915/debugfs.c | 14 ----- .../net/wireless/mediatek/mt76/mt7915/init.c | 51 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7915/mcu.c | 7 +-- .../wireless/mediatek/mt76/mt7915/mt7915.h | 2 +- 4 files changed, 56 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 6a8ddeeecbe9..f1e8b076d54c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -224,18 +224,6 @@ mt7915_tx_stats_show(struct seq_file *file, void *data) DEFINE_SHOW_ATTRIBUTE(mt7915_tx_stats); -static int mt7915_read_temperature(struct seq_file *s, void *data) -{ - struct mt7915_dev *dev = dev_get_drvdata(s->private); - int temp; - - /* cpu */ - temp = mt7915_mcu_get_temperature(dev, 0); - seq_printf(s, "Temperature: %d\n", temp); - - return 0; -} - static int mt7915_queues_acq(struct seq_file *s, void *data) { @@ -390,8 +378,6 @@ int mt7915_init_debugfs(struct mt7915_dev *dev) debugfs_create_file("radar_trigger", 0200, dir, dev, &fops_radar_trigger); debugfs_create_file("ser_trigger", 0200, dir, dev, &fops_ser_trigger); - debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir, - mt7915_read_temperature); debugfs_create_devm_seqfile(dev->mt76.dev, "txpower_sku", dir, mt7915_read_rate_txpower); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index c103175d9954..ff7c38b87ed1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -2,6 +2,8 @@ /* Copyright (C) 2020 MediaTek Inc. */ #include +#include +#include #include "mt7915.h" #include "mac.h" #include "mcu.h" @@ -39,6 +41,47 @@ static const struct ieee80211_iface_combination if_comb[] = { } }; +static ssize_t mt7915_thermal_show_temp(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct mt7915_phy *phy = dev_get_drvdata(dev); + int temperature; + + temperature = mt7915_mcu_get_temperature(phy); + if (temperature < 0) + return temperature; + + /* display in millidegree celcius */ + return sprintf(buf, "%u\n", temperature * 1000); +} + +static SENSOR_DEVICE_ATTR(temp1_input, 0444, mt7915_thermal_show_temp, + NULL, 0); + +static struct attribute *mt7915_hwmon_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(mt7915_hwmon); + +static int mt7915_thermal_init(struct mt7915_phy *phy) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + struct device *hwmon; + + if (!IS_REACHABLE(CONFIG_HWMON)) + return 0; + + hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, + wiphy_name(wiphy), phy, + mt7915_hwmon_groups); + if (IS_ERR(hwmon)) + return PTR_ERR(hwmon); + + return 0; +} + static void mt7915_init_txpower(struct mt7915_dev *dev, struct ieee80211_supported_band *sband) @@ -258,6 +301,10 @@ static int mt7915_register_ext_phy(struct mt7915_dev *dev) if (ret) goto error; + ret = mt7915_thermal_init(phy); + if (ret) + goto error; + return 0; error: @@ -708,6 +755,10 @@ int mt7915_register_device(struct mt7915_dev *dev) if (ret) return ret; + ret = mt7915_thermal_init(&dev->phy); + if (ret) + return ret; + ieee80211_queue_work(mt76_hw(dev), &dev->init_work); ret = mt7915_register_ext_phy(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index e5302ff4c9dd..f40a2090837f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -3559,16 +3559,17 @@ int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy) return 0; } -int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index) +int mt7915_mcu_get_temperature(struct mt7915_phy *phy) { + struct mt7915_dev *dev = phy->dev; struct { u8 ctrl_id; u8 action; - u8 band; + u8 dbdc_idx; u8 rsv[5]; } req = { .ctrl_id = THERMAL_SENSOR_TEMP_QUERY, - .action = index, + .dbdc_idx = phy != &dev->phy, }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 47341876da09..3ff549577574 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -356,7 +356,7 @@ int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index, const struct mt7915_dfs_pattern *pattern); int mt7915_mcu_apply_group_cal(struct mt7915_dev *dev); int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy); -int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index); +int mt7915_mcu_get_temperature(struct mt7915_phy *phy); int mt7915_mcu_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx); int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct rate_info *rate); From 34b877d972bec8cbf397a57393317672cf92996f Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 24 Apr 2021 06:02:05 +0800 Subject: [PATCH 034/170] mt76: mt7915: add thermal cooling device support Thermal cooling device support is added to control the temperature by throttling the data transmission for the given duration. Throttling is done by adjusting Tx period by given percentage of time. The thermal device allows user to configure duty cycle. Throttling can be disabled by setting the duty cycle to 0. The cooling device can be found under /sys/class/thermal/cooling_deviceX/. Corresponding soft link to this device can be found under phy folder To set duty cycle as 80%, echo 80 > /sys/class/ieee80211/phy*/cooling_device/cur_state Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/init.c | 73 +++++++++++++++++ .../net/wireless/mediatek/mt76/mt7915/mcu.c | 80 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7915/mcu.h | 35 ++++++++ .../wireless/mediatek/mt76/mt7915/mt7915.h | 6 ++ 4 files changed, 194 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index ff7c38b87ed1..39f3639aa096 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "mt7915.h" #include "mac.h" #include "mcu.h" @@ -65,11 +66,81 @@ static struct attribute *mt7915_hwmon_attrs[] = { }; ATTRIBUTE_GROUPS(mt7915_hwmon); +static int +mt7915_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + *state = MT7915_THERMAL_THROTTLE_MAX; + + return 0; +} + +static int +mt7915_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct mt7915_phy *phy = cdev->devdata; + + *state = phy->throttle_state; + + return 0; +} + +static int +mt7915_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct mt7915_phy *phy = cdev->devdata; + int ret; + + if (state > MT7915_THERMAL_THROTTLE_MAX) + return -EINVAL; + + if (state == phy->throttle_state) + return 0; + + ret = mt7915_mcu_set_thermal_throttling(phy, state); + if (ret) + return ret; + + phy->throttle_state = state; + + return 0; +} + +static const struct thermal_cooling_device_ops mt7915_thermal_ops = { + .get_max_state = mt7915_thermal_get_max_throttle_state, + .get_cur_state = mt7915_thermal_get_cur_throttle_state, + .set_cur_state = mt7915_thermal_set_cur_throttle_state, +}; + +static void mt7915_unregister_thermal(struct mt7915_phy *phy) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + + if (!phy->cdev) + return; + + sysfs_remove_link(&wiphy->dev.kobj, "cooling_device"); + thermal_cooling_device_unregister(phy->cdev); +} + static int mt7915_thermal_init(struct mt7915_phy *phy) { struct wiphy *wiphy = phy->mt76->hw->wiphy; + struct thermal_cooling_device *cdev; struct device *hwmon; + cdev = thermal_cooling_device_register(wiphy_name(wiphy), phy, + &mt7915_thermal_ops); + if (!IS_ERR(cdev)) { + if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj, + "cooling_device") < 0) + thermal_cooling_device_unregister(cdev); + else + phy->cdev = cdev; + } + if (!IS_REACHABLE(CONFIG_HWMON)) return 0; @@ -709,6 +780,7 @@ static void mt7915_unregister_ext_phy(struct mt7915_dev *dev) if (!phy) return; + mt7915_unregister_thermal(phy); mt76_unregister_phy(mphy); ieee80211_free_hw(mphy->hw); } @@ -771,6 +843,7 @@ int mt7915_register_device(struct mt7915_dev *dev) void mt7915_unregister_device(struct mt7915_dev *dev) { mt7915_unregister_ext_phy(dev); + mt7915_unregister_thermal(&dev->phy); mt76_unregister_device(&dev->mt76); mt7915_mcu_exit(dev); mt7915_tx_token_put(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index f40a2090837f..05ba45d0b3e1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -455,6 +455,24 @@ mt7915_mcu_rx_csa_notify(struct mt7915_dev *dev, struct sk_buff *skb) mt7915_mcu_csa_finish, mphy->hw); } +static void +mt7915_mcu_rx_thermal_notify(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt7915_mcu_thermal_notify *t; + struct mt7915_phy *phy; + + t = (struct mt7915_mcu_thermal_notify *)skb->data; + if (t->ctrl.ctrl_id != THERMAL_PROTECT_ENABLE) + return; + + if (t->ctrl.band_idx && dev->mt76.phy2) + mphy = dev->mt76.phy2; + + phy = (struct mt7915_phy *)mphy->priv; + phy->throttle_state = t->ctrl.duty.duty_cycle; +} + static void mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb) { @@ -645,6 +663,9 @@ mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb) struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; switch (rxd->ext_eid) { + case MCU_EXT_EVENT_THERMAL_PROTECT: + mt7915_mcu_rx_thermal_notify(dev, skb); + break; case MCU_EXT_EVENT_RDD_REPORT: mt7915_mcu_rx_radar_detected(dev, skb); break; @@ -3576,6 +3597,65 @@ int mt7915_mcu_get_temperature(struct mt7915_phy *phy) sizeof(req), true); } +int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state) +{ + struct mt7915_dev *dev = phy->dev; + struct { + struct mt7915_mcu_thermal_ctrl ctrl; + + __le32 trigger_temp; + __le32 restore_temp; + __le16 sustain_time; + u8 rsv[2]; + } __packed req = { + .ctrl = { + .band_idx = phy != &dev->phy, + }, + }; + int level; + +#define TRIGGER_TEMPERATURE 122 +#define RESTORE_TEMPERATURE 116 +#define SUSTAIN_PERIOD 10 + + if (!state) { + req.ctrl.ctrl_id = THERMAL_PROTECT_DISABLE; + goto out; + } + + /* set duty cycle and level */ + for (level = 0; level < 4; level++) { + int ret; + + req.ctrl.ctrl_id = THERMAL_PROTECT_DUTY_CONFIG; + req.ctrl.duty.duty_level = level; + req.ctrl.duty.duty_cycle = state; + state = state * 4 / 5; + + ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT), + &req, sizeof(req.ctrl), false); + if (ret) + return ret; + } + + /* currently use fixed values for throttling, and would be better + * to implement thermal zone for dynamic trip in the long run. + */ + + /* set high-temperature trigger threshold */ + req.ctrl.ctrl_id = THERMAL_PROTECT_ENABLE; + req.trigger_temp = cpu_to_le32(TRIGGER_TEMPERATURE); + req.restore_temp = cpu_to_le32(RESTORE_TEMPERATURE); + req.sustain_time = cpu_to_le16(SUSTAIN_PERIOD); + +out: + req.ctrl.type.protect_type = 1; + req.ctrl.type.trigger_type = 1; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT), + &req, sizeof(req), false); +} + int mt7915_mcu_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx) { struct { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index f95920d58a40..7e3432384633 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -68,6 +68,29 @@ struct mt7915_mcu_rxd { u8 s2d_index; }; +struct mt7915_mcu_thermal_ctrl { + u8 ctrl_id; + u8 band_idx; + union { + struct { + u8 protect_type; /* 1: duty admit, 2: radio off */ + u8 trigger_type; /* 0: low, 1: high */ + } __packed type; + struct { + u8 duty_level; /* level 0~3 */ + u8 duty_cycle; + } __packed duty; + }; +} __packed; + +struct mt7915_mcu_thermal_notify { + struct mt7915_mcu_rxd rxd; + + struct mt7915_mcu_thermal_ctrl ctrl; + __le32 temperature; + u8 rsv[8]; +} __packed; + struct mt7915_mcu_csa_notify { struct mt7915_mcu_rxd rxd; @@ -262,6 +285,7 @@ enum { MCU_EXT_CMD_FW_LOG_2_HOST = 0x13, MCU_EXT_CMD_TXBF_ACTION = 0x1e, MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21, + MCU_EXT_CMD_THERMAL_PROT = 0x23, MCU_EXT_CMD_STA_REC_UPDATE = 0x25, MCU_EXT_CMD_BSS_INFO_UPDATE = 0x26, MCU_EXT_CMD_EDCA_UPDATE = 0x27, @@ -1066,6 +1090,17 @@ enum { THERMAL_SENSOR_TASK_CTRL, }; +enum { + THERMAL_PROTECT_PARAMETER_CTRL, + THERMAL_PROTECT_BASIC_INFO, + THERMAL_PROTECT_ENABLE, + THERMAL_PROTECT_DISABLE, + THERMAL_PROTECT_DUTY_CONFIG, + THERMAL_PROTECT_MECH_INFO, + THERMAL_PROTECT_DUTY_INFO, + THERMAL_PROTECT_STATE_ACT, +}; + enum { MT_EBF = BIT(0), /* explicit beamforming */ MT_IBF = BIT(1) /* implicit beamforming */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 3ff549577574..f3ffa907bf87 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -38,6 +38,8 @@ #define MT7915_5G_RATE_DEFAULT 0x4b /* OFDM 6M */ #define MT7915_2G_RATE_DEFAULT 0x0 /* CCK 1M */ +#define MT7915_THERMAL_THROTTLE_MAX 100 + struct mt7915_vif; struct mt7915_sta; struct mt7915_dfs_pulse; @@ -127,6 +129,9 @@ struct mt7915_phy { struct ieee80211_vif *monitor_vif; + struct thermal_cooling_device *cdev; + u8 throttle_state; + u32 rxfilter; u64 omac_mask; @@ -357,6 +362,7 @@ int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index, int mt7915_mcu_apply_group_cal(struct mt7915_dev *dev); int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy); int mt7915_mcu_get_temperature(struct mt7915_phy *phy); +int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state); int mt7915_mcu_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx); int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct rate_info *rate); From 109e505ad944dc207aaa9ee134b0994be09d291d Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 24 Apr 2021 06:02:06 +0800 Subject: [PATCH 035/170] mt76: mt7615: add thermal sensor device support Similar to mt7915, switching to use standard hwmon sysfs. For reading temperature, cat /sys/class/ieee80211/phy*/hwmon*/temp1_input Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7615/debugfs.c | 20 -------- .../net/wireless/mediatek/mt76/mt7615/init.c | 50 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7615/mcu.c | 6 +-- .../wireless/mediatek/mt76/mt7615/mt7615.h | 3 +- .../wireless/mediatek/mt76/mt7615/pci_init.c | 4 ++ 5 files changed, 58 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index 676bb22726d6..8cb4426e757c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -319,24 +319,6 @@ mt7615_radio_read(struct seq_file *s, void *data) return 0; } -static int mt7615_read_temperature(struct seq_file *s, void *data) -{ - struct mt7615_dev *dev = dev_get_drvdata(s->private); - int temp; - - if (!mt7615_wait_for_mcu_init(dev)) - return 0; - - /* cpu */ - mt7615_mutex_acquire(dev); - temp = mt7615_mcu_get_temperature(dev, 0); - mt7615_mutex_release(dev); - - seq_printf(s, "Temperature: %d\n", temp); - - return 0; -} - static int mt7615_queues_acq(struct seq_file *s, void *data) { @@ -566,8 +548,6 @@ int mt7615_init_debugfs(struct mt7615_dev *dev) debugfs_create_file("reset_test", 0200, dir, dev, &fops_reset_test); - debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir, - mt7615_read_temperature); debugfs_create_file("ext_mac_addr", 0600, dir, dev, &fops_ext_mac_addr); debugfs_create_u32("rf_wfidx", 0600, dir, &dev->debugfs_rf_wf); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index ecc3ca9eb658..4aa7877a6383 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -8,11 +8,61 @@ */ #include +#include +#include #include "mt7615.h" #include "mac.h" #include "mcu.h" #include "eeprom.h" +static ssize_t mt7615_thermal_show_temp(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct mt7615_dev *mdev = dev_get_drvdata(dev); + int temperature; + + if (!mt7615_wait_for_mcu_init(mdev)) + return 0; + + mt7615_mutex_acquire(mdev); + temperature = mt7615_mcu_get_temperature(mdev); + mt7615_mutex_release(mdev); + + if (temperature < 0) + return temperature; + + /* display in millidegree celcius */ + return sprintf(buf, "%u\n", temperature * 1000); +} + +static SENSOR_DEVICE_ATTR(temp1_input, 0444, mt7615_thermal_show_temp, + NULL, 0); + +static struct attribute *mt7615_hwmon_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(mt7615_hwmon); + +int mt7615_thermal_init(struct mt7615_dev *dev) +{ + struct wiphy *wiphy = mt76_hw(dev)->wiphy; + struct device *hwmon; + + if (!IS_REACHABLE(CONFIG_HWMON)) + return 0; + + hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, + wiphy_name(wiphy), dev, + mt7615_hwmon_groups); + if (IS_ERR(hwmon)) + return PTR_ERR(hwmon); + + return 0; +} +EXPORT_SYMBOL_GPL(mt7615_thermal_init); + static void mt7615_phy_init(struct mt7615_dev *dev) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 32090e01b4d2..a59bd7af81be 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2350,14 +2350,12 @@ int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd) return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); } -int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index) +int mt7615_mcu_get_temperature(struct mt7615_dev *dev) { struct { u8 action; u8 rsv[3]; - } req = { - .action = index, - }; + } req = {}; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_GET_TEMP, &req, sizeof(req), true); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 2ba86bd96a31..8f03dddba8cf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -360,6 +360,7 @@ static inline int mt7622_wmac_init(struct mt7615_dev *dev) } #endif +int mt7615_thermal_init(struct mt7615_dev *dev); int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, int irq, const u32 *map); u32 mt7615_reg_map(struct mt7615_dev *dev, u32 addr); @@ -498,7 +499,7 @@ u32 mt7615_rf_rr(struct mt7615_dev *dev, u32 wf, u32 reg); int mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val); int mt7615_mcu_set_dbdc(struct mt7615_dev *dev); int mt7615_mcu_set_eeprom(struct mt7615_dev *dev); -int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index); +int mt7615_mcu_get_temperature(struct mt7615_dev *dev); int mt7615_mcu_set_tx_power(struct mt7615_phy *phy); void mt7615_mcu_exit(struct mt7615_dev *dev); void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c index 273fda08bfa2..261cff78de40 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c @@ -152,6 +152,10 @@ int mt7615_register_device(struct mt7615_dev *dev) if (ret) return ret; + ret = mt7615_thermal_init(dev); + if (ret) + return ret; + ieee80211_queue_work(mt76_hw(dev), &dev->mcu_work); mt7615_init_txpower(dev, &dev->mphy.sband_2g.sband); mt7615_init_txpower(dev, &dev->mphy.sband_5g.sband); From f011c3691a7efe66b1ef76bbf7821973b8490a15 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Thu, 20 May 2021 11:46:36 +0800 Subject: [PATCH 036/170] mt76: connac: update BA win size in Rx direction Update BA size used data transimission in the Rx direction to improve Rx throughput. Reviewed-by: Lorenzo Bianconi Signed-off-by: Deren Wu Signed-off-by: Leon Yen Signed-off-by: YN Chen Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 54612a479215..dd4a28b75e4e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -935,8 +935,10 @@ void mt76_connac_mcu_wtbl_ba_tlv(struct mt76_dev *dev, struct sk_buff *skb, ba->rst_ba_sb = 1; } - if (is_mt7921(dev)) + if (is_mt7921(dev)) { + ba->ba_winsize = enable ? cpu_to_le16(params->buf_size) : 0; return; + } if (enable && tx) { u8 ba_range[] = { 4, 8, 12, 24, 36, 48, 54, 64 }; From f07ac384b4579f294bb1e0380ed501156219ed71 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Thu, 20 May 2021 11:46:38 +0800 Subject: [PATCH 037/170] mt76: mt7921: avoid unnecessary consecutive WiFi resets Avoid unnecessary consecutive WiFi resets by dropping reset request when reset work is working. Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 5 ++++- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 96a6c0aabe06..ffc73fabb5b9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1312,6 +1312,7 @@ void mt7921_mac_reset_work(struct work_struct *work) int i; dev_err(dev->mt76.dev, "chip reset\n"); + dev->hw_full_reset = true; ieee80211_stop_queues(hw); cancel_delayed_work_sync(&dev->mphy.mac_work); @@ -1338,6 +1339,7 @@ void mt7921_mac_reset_work(struct work_struct *work) ieee80211_scan_completed(dev->mphy.hw, &info); } + dev->hw_full_reset = false; ieee80211_wake_queues(hw); ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL, @@ -1349,7 +1351,8 @@ void mt7921_reset(struct mt76_dev *mdev) { struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); - queue_work(dev->mt76.wq, &dev->reset_work); + if (!dev->hw_full_reset) + queue_work(dev->mt76.wq, &dev->reset_work); } static void diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 03bcb210c357..710ad242fd53 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -156,6 +156,7 @@ struct mt7921_dev { u16 chainmask; struct work_struct reset_work; + bool hw_full_reset; struct list_head sta_poll_list; spinlock_t sta_poll_lock; From f86625ae0e35924ed495cdf0ff2d3133cb6e3010 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Thu, 20 May 2021 11:46:39 +0800 Subject: [PATCH 038/170] mt76: mt7921: fix invalid register access in wake_work Make sure mt7921_pm_wake_work wouldn't be scheduled after the driver is in suspend mode to fix the following the kernel crash. [ 3515.390012] mt7921e 0000:01:00.0: calling pci_pm_suspend+0x0/0x22c @ 2869, parent: 0000:00:00.0 [ 3515.390015] mt7921e 0000:01:00.0: mt7921_pci_suspend + [ 3515.396395] anx7625 3-0058: anx7625_suspend+0x0/0x6c returned 0 after 0 usecs [ 3515.405965] mt7921e 0000:01:00.0: mt7921_pci_suspend - [ 3515.411336] usb 1-1.4: usb_dev_suspend+0x0/0x2c returned 0 after 1 usecs [ 3515.411513] SError Interrupt on CPU7, code 0xbe000011 -- SError [ 3515.411515] CPU: 7 PID: 2849 Comm: kworker/u16:27 Not tainted 5.4.114 #44 [ 3515.411516] Hardware name: MediaTek Asurada rev1 board (DT) [ 3515.411517] Workqueue: mt76 mt7921_pm_wake_work [mt7921e] [ 3515.411518] pstate: 80c00009 (Nzcv daif +PAN +UAO) [ 3515.411519] pc : mt76_mmio_rr+0x30/0xf0 [mt76] [ 3515.411520] lr : mt7921_rr+0x38/0x44 [mt7921e] [ 3515.411520] sp : ffffffc015813c50 [ 3515.411521] x29: ffffffc015813c50 x28: 0000000000000402 [ 3515.411522] x27: ffffffe5a2012138 x26: ffffffe5a1eea018 [ 3515.411524] x25: 00000000328be505 x24: 00000000000a0002 [ 3515.411525] x23: 0000000000000006 x22: ffffffbd29b7a300 [ 3515.411527] x21: ffffffbd29b7a300 x20: 00000000000e0010 [ 3515.411528] x19: 00000000eac08f43 x18: 0000000000000000 [ 3515.411529] x17: 0000000000000000 x16: ffffffe5a16b2914 [ 3515.411531] x15: 0000000000000010 x14: 0000000000000010 [ 3515.411532] x13: 00000000003dd3a2 x12: 0000000000010000 [ 3515.411533] x11: ffffffe597abec14 x10: 0000000000000010 [ 3515.411535] x9 : ffffffe597abeba8 x8 : ffffffc013ce0010 [ 3515.411536] x7 : 000000b2b5593519 x6 : 0000000000300000 [ 3515.411537] x5 : 0000000000000000 x4 : 0000000000000032 [ 3515.411539] x3 : 0000000000000000 x2 : 0000000000000004 [ 3515.411540] x1 : 00000000000e0010 x0 : ffffffbd29b7a300 [ 3515.411542] Kernel panic - not syncing: Asynchronous SError Interrupt [ 3515.411543] CPU: 7 PID: 2849 Comm: kworker/u16:27 Not tainted 5.4.114 #44 [ 3515.411544] Hardware name: MediaTek Asurada rev1 board (DT) [ 3515.411544] Workqueue: mt76 mt7921_pm_wake_work [mt7921e] [ 3515.411545] Call trace: [ 3515.411546] dump_backtrace+0x0/0x14c [ 3515.411546] show_stack+0x20/0x2c [ 3515.411547] dump_stack+0xa0/0xfc [ 3515.411548] panic+0x154/0x350 [ 3515.411548] panic+0x0/0x350 [ 3515.411549] arm64_serror_panic+0x78/0x84 [ 3515.411550] do_serror+0x0/0x118 [ 3515.411550] do_serror+0xa4/0x118 [ 3515.411551] el1_error+0x84/0xf8 [ 3515.411552] mt76_mmio_rr+0x30/0xf0 [mt76] [ 3515.411552] mt7921_rr+0x38/0x44 [mt7921e] [ 3515.411553] __mt76_poll_msec+0x5c/0x9c [mt76] [ 3515.411554] __mt7921_mcu_drv_pmctrl+0x50/0x94 [mt7921e] [ 3515.411555] mt7921_mcu_drv_pmctrl+0x38/0xb0 [mt7921e] [ 3515.411555] mt7921_pm_wake_work+0x34/0xd4 [mt7921e] [ 3515.411556] process_one_work+0x208/0x3c8 [ 3515.411557] worker_thread+0x23c/0x3e8 [ 3515.411557] kthread+0x144/0x178 [ 3515.411558] ret_from_fork+0x10/0x18 [ 3515.418831] SMP: stopping secondary CPUs [ 3515.418832] Kernel Offset: 0x2590c00000 from 0xffffffc010000000 [ 3515.418832] PHYS_OFFSET: 0xffffffc400000000 [ 3515.418833] CPU features: 0x080026,2a80aa18 [ 3515.418834] Memory Limit: none [DL] 00000000 00000000 010701 Fixes: 1d8efc741df80 ("mt76: mt7921: introduce Runtime PM support") Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac.h | 1 + .../wireless/mediatek/mt76/mt76_connac_mac.c | 6 +++++ .../net/wireless/mediatek/mt76/mt7921/pci.c | 25 +++++++++++++------ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 337c5ece7ec3..63c1d1a68a70 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -45,6 +45,7 @@ enum { struct mt76_connac_pm { bool enable; + bool suspended; spinlock_t txq_lock; struct { diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 6f180c92d413..5f2705fbd680 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -17,6 +17,9 @@ int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm) if (!test_bit(MT76_STATE_PM, &phy->state)) return 0; + if (pm->suspended) + return 0; + queue_work(dev->wq, &pm->wake_work); if (!wait_event_timeout(pm->wait, !test_bit(MT76_STATE_PM, &phy->state), @@ -40,6 +43,9 @@ void mt76_connac_power_save_sched(struct mt76_phy *phy, if (!pm->enable) return; + if (pm->suspended) + return; + pm->last_activity = jiffies; if (!test_bit(MT76_STATE_PM, &phy->state)) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index fa02d934f0bf..13263f50dc00 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -188,21 +188,26 @@ static int mt7921_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + struct mt76_connac_pm *pm = &dev->pm; bool hif_suspend; int i, err; - err = mt76_connac_pm_wake(&dev->mphy, &dev->pm); + pm->suspended = true; + cancel_delayed_work_sync(&pm->ps_work); + cancel_work_sync(&pm->wake_work); + + err = mt7921_mcu_drv_pmctrl(dev); if (err < 0) - return err; + goto restore_suspend; hif_suspend = !test_bit(MT76_STATE_SUSPEND, &dev->mphy.state); if (hif_suspend) { err = mt76_connac_mcu_set_hif_suspend(mdev, true); if (err) - return err; + goto restore_suspend; } - if (!dev->pm.enable) + if (!pm->enable) mt76_connac_mcu_set_deep_sleep(&dev->mt76, true); napi_disable(&mdev->tx_napi); @@ -231,27 +236,30 @@ static int mt7921_pci_suspend(struct pci_dev *pdev, pm_message_t state) err = mt7921_mcu_fw_pmctrl(dev); if (err) - goto restore; + goto restore_napi; pci_save_state(pdev); err = pci_set_power_state(pdev, pci_choose_state(pdev, state)); if (err) - goto restore; + goto restore_napi; return 0; -restore: +restore_napi: mt76_for_each_q_rx(mdev, i) { napi_enable(&mdev->napi[i]); } napi_enable(&mdev->tx_napi); - if (!dev->pm.enable) + if (!pm->enable) mt76_connac_mcu_set_deep_sleep(&dev->mt76, false); if (hif_suspend) mt76_connac_mcu_set_hif_suspend(mdev, false); +restore_suspend: + pm->suspended = false; + return err; } @@ -261,6 +269,7 @@ static int mt7921_pci_resume(struct pci_dev *pdev) struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); int i, err; + dev->pm.suspended = false; err = pci_set_power_state(pdev, PCI_D0); if (err) return err; From 213f87289ea01514acdbfeed9f65bcb5f12aef70 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Thu, 20 May 2021 11:46:40 +0800 Subject: [PATCH 039/170] mt76: mt7921: fix OMAC idx usage OMAC idx have to be same with BSS idx according to firmware usage. Fixes: e0f9fdda81bd ("mt76: mt7921: add ieee80211_ops") Reviewed-by: Lorenzo Bianconi Signed-off-by: Deren Wu Signed-off-by: YN Chen Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7921/main.c | 55 +------------------ 1 file changed, 1 insertion(+), 54 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 8016f8377c8f..175030ec221d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -223,54 +223,6 @@ static void mt7921_stop(struct ieee80211_hw *hw) mt7921_mutex_release(dev); } -static inline int get_free_idx(u32 mask, u8 start, u8 end) -{ - return ffs(~mask & GENMASK(end, start)); -} - -static int get_omac_idx(enum nl80211_iftype type, u64 mask) -{ - int i; - - switch (type) { - case NL80211_IFTYPE_STATION: - /* prefer hw bssid slot 1-3 */ - i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3); - if (i) - return i - 1; - - /* next, try to find a free repeater entry for the sta */ - i = get_free_idx(mask >> REPEATER_BSSID_START, 0, - REPEATER_BSSID_MAX - REPEATER_BSSID_START); - if (i) - return i + 32 - 1; - - i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); - if (i) - return i - 1; - - if (~mask & BIT(HW_BSSID_0)) - return HW_BSSID_0; - - break; - case NL80211_IFTYPE_MONITOR: - /* ap uses hw bssid 0 and ext bssid */ - if (~mask & BIT(HW_BSSID_0)) - return HW_BSSID_0; - - i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); - if (i) - return i - 1; - - break; - default: - WARN_ON(1); - break; - } - - return -1; -} - static int mt7921_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -292,12 +244,7 @@ static int mt7921_add_interface(struct ieee80211_hw *hw, goto out; } - idx = get_omac_idx(vif->type, phy->omac_mask); - if (idx < 0) { - ret = -ENOSPC; - goto out; - } - mvif->mt76.omac_idx = idx; + mvif->mt76.omac_idx = mvif->mt76.idx; mvif->phy = phy; mvif->mt76.band_idx = 0; mvif->mt76.wmm_idx = mvif->mt76.idx % MT7921_MAX_WMM_SETS; From a2d3442e3db1028f57efdeff26cd6e72a82cb648 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 20 May 2021 11:46:41 +0800 Subject: [PATCH 040/170] mt76: mt7921: enable runtime pm by default mt7921 is mainly used in CE/IoT market so enable runtime-pm by default Signed-off-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index a3517ed76813..c1a5bb5e5e02 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -185,7 +185,6 @@ int mt7921_register_device(struct mt7921_dev *dev) mutex_init(&dev->pm.mutex); init_waitqueue_head(&dev->pm.wait); spin_lock_init(&dev->pm.txq_lock); - set_bit(MT76_STATE_PM, &dev->mphy.state); INIT_LIST_HEAD(&dev->phy.stats_list); INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7921_mac_work); INIT_DELAYED_WORK(&dev->phy.scan_work, mt7921_scan_work); @@ -200,6 +199,7 @@ int mt7921_register_device(struct mt7921_dev *dev) dev->pm.idle_timeout = MT7921_PM_TIMEOUT; dev->pm.stats.last_wake_event = jiffies; dev->pm.stats.last_doze_event = jiffies; + dev->pm.enable = true; ret = mt7921_init_hardware(dev); if (ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 06209d58ce27..37d8cbd12ff9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -945,8 +945,6 @@ static int mt7921_load_firmware(struct mt7921_dev *dev) dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support; #endif /* CONFIG_PM */ - clear_bit(MT76_STATE_PM, &dev->mphy.state); - dev_err(dev->mt76.dev, "Firmware init done\n"); return 0; From b4b880b90cb3863ca98e4ad55107d159742a79ae Mon Sep 17 00:00:00 2001 From: YN Chen Date: Thu, 20 May 2021 11:46:35 +0800 Subject: [PATCH 041/170] mt76: connac: add bss color support for sta mode Add bss color support for sta mode Signed-off-by: Jayden.Kuo Signed-off-by: YN Chen Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 14 ++++++++++++++ .../net/wireless/mediatek/mt76/mt76_connac_mcu.h | 9 +++++++++ 2 files changed, 23 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index dd4a28b75e4e..9066c57b1e32 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1313,6 +1313,7 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy, u8 pad[3]; } __packed hdr; struct bss_info_uni_he he; + struct bss_info_uni_bss_color bss_color; } he_req = { .hdr = { .bss_idx = mvif->idx, @@ -1321,8 +1322,21 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy, .tag = cpu_to_le16(UNI_BSS_INFO_HE_BASIC), .len = cpu_to_le16(sizeof(struct bss_info_uni_he)), }, + .bss_color = { + .tag = cpu_to_le16(UNI_BSS_INFO_BSS_COLOR), + .len = cpu_to_le16(sizeof(struct bss_info_uni_bss_color)), + .enable = 0, + .bss_color = 0, + }, }; + if (enable) { + he_req.bss_color.enable = + vif->bss_conf.he_bss_color.enabled; + he_req.bss_color.bss_color = + vif->bss_conf.he_bss_color.color; + } + mt76_connac_mcu_uni_bss_he_tlv(phy, vif, (struct tlv *)&he_req.he); err = mt76_mcu_send_msg(mdev, MCU_UNI_CMD_BSS_INFO_UPDATE, diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 676b1c6bc959..13f7d6a57889 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -575,6 +575,7 @@ enum { enum { UNI_BSS_INFO_BASIC = 0, UNI_BSS_INFO_RLM = 2, + UNI_BSS_INFO_BSS_COLOR = 4, UNI_BSS_INFO_HE_BASIC = 5, UNI_BSS_INFO_BCN_CONTENT = 7, UNI_BSS_INFO_QBSS = 15, @@ -789,6 +790,14 @@ struct mt76_connac_sched_scan_done { __le16 pad; } __packed; +struct bss_info_uni_bss_color { + __le16 tag; + __le16 len; + u8 enable; + u8 bss_color; + u8 rsv[2]; +} __packed; + struct bss_info_uni_he { __le16 tag; __le16 len; From f5e3db30135f1157d2fac83f16e0347b1e38b9c5 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 23 May 2021 23:03:26 +0200 Subject: [PATCH 042/170] mt76: mt7921: return proper error value in mt7921_mac_init Return possible error values in mt7921_mac_init routine Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 8 +++----- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 5 ++++- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index c1a5bb5e5e02..99701cda0b9d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -108,7 +108,7 @@ mt7921_mac_init_band(struct mt7921_dev *dev, u8 band) mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN); } -void mt7921_mac_init(struct mt7921_dev *dev) +int mt7921_mac_init(struct mt7921_dev *dev) { int i; @@ -124,7 +124,7 @@ void mt7921_mac_init(struct mt7921_dev *dev) for (i = 0; i < 2; i++) mt7921_mac_init_band(dev, i); - mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, 0); + return mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, 0); } static int mt7921_init_hardware(struct mt7921_dev *dev) @@ -164,9 +164,7 @@ static int mt7921_init_hardware(struct mt7921_dev *dev) dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET; rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); - mt7921_mac_init(dev); - - return 0; + return mt7921_mac_init(dev); } int mt7921_register_device(struct mt7921_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index ffc73fabb5b9..1e52e92c5ad8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1298,7 +1298,10 @@ mt7921_mac_reset(struct mt7921_dev *dev) if (err) return err; - mt7921_mac_init(dev); + err = mt7921_mac_init(dev); + if (err) + return err; + return __mt7921_start(&dev->phy); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 710ad242fd53..1e65a8f6f211 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -319,7 +319,7 @@ static inline bool mt7921_dma_need_reinit(struct mt7921_dev *dev) return !mt76_get_field(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT); } -void mt7921_mac_init(struct mt7921_dev *dev); +int mt7921_mac_init(struct mt7921_dev *dev); bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask); void mt7921_mac_reset_counters(struct mt7921_phy *phy); void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, From d74c4b5667425c35d74906795a08e02e29df5b46 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 23 May 2021 23:08:05 +0200 Subject: [PATCH 043/170] mt76: mt7921: do not schedule hw reset if the device is not running Do not schedule hw full reset if the device is not fully initialized (e.g if the channel has not been configured yet). This patch fixes the kernel crash reported below [ 44.440266] mt7921e 0000:01:00.0: chip reset failed [ 44.527575] Unable to handle kernel paging request at virtual address ffffffc02f3e0000 [ 44.535771] Mem abort info: [ 44.538646] ESR = 0x96000006 [ 44.541792] EC = 0x25: DABT (current EL), IL = 32 bits [ 44.547268] SET = 0, FnV = 0 [ 44.550413] EA = 0, S1PTW = 0 [ 44.553648] Data abort info: [ 44.556613] ISV = 0, ISS = 0x00000006 [ 44.560563] CM = 0, WnR = 0 [ 44.563619] swapper pgtable: 4k pages, 39-bit VAs, pgdp=0000000000955000 [ 44.570530] [ffffffc02f3e0000] pgd=100000003ffff003, p4d=100000003ffff003, pud=100000003ffff003, pmd=0000000000000000 [ 44.581489] Internal error: Oops: 96000006 [#1] SMP [ 44.606406] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 5.13.0-rc1-espressobin-12875-g6dc7f82ebc26 #33 [ 44.617264] Hardware name: Globalscale Marvell ESPRESSOBin Board (DT) [ 44.623905] pstate: 600000c5 (nZCv daIF -PAN -UAO -TCO BTYPE=--) [ 44.630100] pc : __queue_work+0x1f0/0x500 [ 44.634249] lr : __queue_work+0x1e8/0x500 [ 44.638384] sp : ffffffc010003d70 [ 44.641798] x29: ffffffc010003d70 x28: 0000000000000000 x27: ffffff8003989200 [ 44.649166] x26: ffffffc010c08510 x25: 0000000000000002 x24: ffffffc010ad90b0 [ 44.656533] x23: ffffffc010c08508 x22: 0000000000000012 x21: 0000000000000000 [ 44.663899] x20: ffffff8006385238 x19: ffffffc02f3e0000 x18: 00000000000003c9 [ 44.671266] x17: 0000000000000000 x16: 0000000000000000 x15: 000009b1a8a3bf90 [ 44.678632] x14: 0098968000000000 x13: 0000000000000000 x12: 0000000000000325 [ 44.685998] x11: ffffff803fda1928 x10: 0000000000000001 x9 : ffffffc010003e98 [ 44.693365] x8 : 0000000000000032 x7 : fff8000000000000 x6 : 0000000000000035 [ 44.700732] x5 : 0000000000000000 x4 : 0000000000000000 x3 : ffffffc010adf700 [ 44.708098] x2 : ffffff8006385238 x1 : 000000007fffffff x0 : 0000000000000000 [ 44.715465] Call trace: [ 44.717982] __queue_work+0x1f0/0x500 [ 44.721760] delayed_work_timer_fn+0x18/0x20 [ 44.726167] call_timer_fn+0x2c/0x178 [ 44.729947] run_timer_softirq+0x488/0x5c8 [ 44.734172] _stext+0x11c/0x378 [ 44.737411] irq_exit+0x100/0x108 [ 44.740830] __handle_domain_irq+0x60/0xb0 [ 44.745059] gic_handle_irq+0x70/0x2b4 [ 44.748929] el1_irq+0xb8/0x13c [ 44.752167] arch_cpu_idle+0x14/0x30 [ 44.755858] default_idle_call+0x38/0x168 [ 44.759994] do_idle+0x1fc/0x210 [ 44.763325] cpu_startup_entry+0x20/0x58 [ 44.767372] rest_init+0xb8/0xc8 [ 44.770703] arch_call_rest_init+0xc/0x14 [ 44.774841] start_kernel+0x408/0x424 [ 44.778623] Code: aa1403e0 97fff54f aa0003f5 b5fff500 (f9400275) [ 44.784907] ---[ end trace be73c3142d8c36a9 ]--- [ 44.789668] Kernel panic - not syncing: Oops: Fatal exception in interrupt Fixes: 0c1ce9884607 ("mt76: mt7921: add wifi reset support") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 1e52e92c5ad8..4d1050ae9f39 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1354,6 +1354,9 @@ void mt7921_reset(struct mt76_dev *mdev) { struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + if (!test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) + return; + if (!dev->hw_full_reset) queue_work(dev->mt76.wq, &dev->reset_work); } From 01f7da40917923bf9d8fd8d5c9a6ed646004e47c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 23 May 2021 23:10:12 +0200 Subject: [PATCH 044/170] mt76: mt7921: reset wfsys during hw probe This patch fixes a mcu hang during device probe on Marvell ESPRESSObin after a hot reboot. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/dma.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c index bd9143dc865f..7fca7dc466b8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c @@ -402,6 +402,10 @@ int mt7921_dma_init(struct mt7921_dev *dev) if (ret) return ret; + ret = mt7921_wfsys_reset(dev); + if (ret) + return ret; + /* init tx queue */ ret = mt7921_init_tx_queues(&dev->phy, MT7921_TXQ_BAND0, MT7921_TX_RING_SIZE); From 160731341845171fd0e5ecd39fe0a43cc9d9af36 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 25 May 2021 16:45:14 +0800 Subject: [PATCH 045/170] mt76: mt7915: add .offset_tsf callback It's much more accurate than .get_tsf + .set_tsf, and switch to use mt76_rmw to operate tsf registers. Tested-by: Xing Song Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/main.c | 33 +++++++++++++++++-- .../net/wireless/mediatek/mt76/mt7915/regs.h | 2 ++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 64f9ebe4424a..2485f65766e7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -816,7 +816,8 @@ mt7915_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) n = mvif->omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->omac_idx; /* TSF software read */ - mt76_set(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE); + mt76_rmw(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE, + MT_LPON_TCR_SW_READ); tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(band)); tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(band)); @@ -845,7 +846,34 @@ mt7915_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt76_wr(dev, MT_LPON_UTTR0(band), tsf.t32[0]); mt76_wr(dev, MT_LPON_UTTR1(band), tsf.t32[1]); /* TSF software overwrite */ - mt76_set(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_WRITE); + mt76_rmw(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE, + MT_LPON_TCR_SW_WRITE); + + mutex_unlock(&dev->mt76.mutex); +} + +static void +mt7915_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + s64 timestamp) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + bool band = phy != &dev->phy; + union { + u64 t64; + u32 t32[2]; + } tsf = { .t64 = timestamp, }; + u16 n; + + mutex_lock(&dev->mt76.mutex); + + n = mvif->omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->omac_idx; + mt76_wr(dev, MT_LPON_UTTR0(band), tsf.t32[0]); + mt76_wr(dev, MT_LPON_UTTR1(band), tsf.t32[1]); + /* TSF software adjust*/ + mt76_rmw(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE, + MT_LPON_TCR_SW_ADJUST); mutex_unlock(&dev->mt76.mutex); } @@ -1036,6 +1064,7 @@ const struct ieee80211_ops mt7915_ops = { .get_stats = mt7915_get_stats, .get_tsf = mt7915_get_tsf, .set_tsf = mt7915_set_tsf, + .offset_tsf = mt7915_offset_tsf, .get_survey = mt76_get_survey, .get_antenna = mt76_get_antenna, .set_antenna = mt7915_set_antenna, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index efe0f2904c66..e36b30d84f07 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -124,6 +124,8 @@ #define MT_LPON_TCR(_band, n) MT_WF_LPON(_band, 0x0a8 + (n) * 4) #define MT_LPON_TCR_SW_MODE GENMASK(1, 0) #define MT_LPON_TCR_SW_WRITE BIT(0) +#define MT_LPON_TCR_SW_ADJUST BIT(1) +#define MT_LPON_TCR_SW_READ GENMASK(1, 0) /* MIB: band 0(0x24800), band 1(0xa4800) */ #define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800) From accbcea4f301e7db084b0a393de8100bdae26ce6 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 25 May 2021 17:22:24 +0800 Subject: [PATCH 046/170] mt76: mt7615: add .offset_tsf callback It's much more accurate than .get_tsf + .set_tsf and switch to use mt76_rmw to operate tsf registers. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7615/mac.c | 2 +- .../net/wireless/mediatek/mt76/mt7615/main.c | 32 +++++++++++++++++-- .../net/wireless/mediatek/mt76/mt7615/regs.h | 2 ++ .../wireless/mediatek/mt76/mt7615/usb_sdio.c | 2 +- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 7153f1da92d0..4daa0540e051 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1062,7 +1062,7 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, idx = idx > HW_BSSID_MAX ? HW_BSSID_0 : idx; addr = idx > 1 ? MT_LPON_TCR2(idx): MT_LPON_TCR0(idx); - mt76_set(dev, addr, MT_LPON_TCR_MODE); /* TSF read */ + mt76_rmw(dev, addr, MT_LPON_TCR_MODE, MT_LPON_TCR_READ); /* TSF read */ sta->rate_set_tsf = mt76_rr(dev, MT_LPON_UTTR0) & ~BIT(0); sta->rate_set_tsf |= rd.rateset; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index faae60775b16..c2a122ca2e83 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -881,7 +881,8 @@ mt7615_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mt7615_mutex_acquire(dev); - mt76_set(dev, reg, MT_LPON_TCR_MODE); /* TSF read */ + /* TSF read */ + mt76_rmw(dev, reg, MT_LPON_TCR_MODE, MT_LPON_TCR_READ); tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0); tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1); @@ -911,7 +912,33 @@ mt7615_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt76_wr(dev, MT_LPON_UTTR0, tsf.t32[0]); mt76_wr(dev, MT_LPON_UTTR1, tsf.t32[1]); /* TSF software overwrite */ - mt76_set(dev, reg, MT_LPON_TCR_WRITE); + mt76_rmw(dev, reg, MT_LPON_TCR_MODE, MT_LPON_TCR_WRITE); + + mt7615_mutex_release(dev); +} + +static void +mt7615_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + s64 timestamp) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt7615_dev *dev = mt7615_hw_dev(hw); + union { + u64 t64; + u32 t32[2]; + } tsf = { .t64 = timestamp, }; + u16 idx = mvif->mt76.omac_idx; + u32 reg; + + idx = idx > HW_BSSID_MAX ? HW_BSSID_0 : idx; + reg = idx > 1 ? MT_LPON_TCR2(idx): MT_LPON_TCR0(idx); + + mt7615_mutex_acquire(dev); + + mt76_wr(dev, MT_LPON_UTTR0, tsf.t32[0]); + mt76_wr(dev, MT_LPON_UTTR1, tsf.t32[1]); + /* TSF software adjust*/ + mt76_rmw(dev, reg, MT_LPON_TCR_MODE, MT_LPON_TCR_ADJUST); mt7615_mutex_release(dev); } @@ -1278,6 +1305,7 @@ const struct ieee80211_ops mt7615_ops = { .get_stats = mt7615_get_stats, .get_tsf = mt7615_get_tsf, .set_tsf = mt7615_set_tsf, + .offset_tsf = mt7615_offset_tsf, .get_survey = mt76_get_survey, .get_antenna = mt76_get_antenna, .set_antenna = mt7615_set_antenna, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 63c081bb04d0..6712ad9faeaa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -463,7 +463,9 @@ enum mt7615_reg_base { #define MT_LPON_TCR0(_n) MT_LPON(0x010 + ((_n) * 4)) #define MT_LPON_TCR2(_n) MT_LPON(0x0f8 + ((_n) - 2) * 4) #define MT_LPON_TCR_MODE GENMASK(1, 0) +#define MT_LPON_TCR_READ GENMASK(1, 0) #define MT_LPON_TCR_WRITE BIT(0) +#define MT_LPON_TCR_ADJUST BIT(1) #define MT_LPON_UTTR0 MT_LPON(0x018) #define MT_LPON_UTTR1 MT_LPON(0x01c) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c index 75a05f8dd7e7..996d48cca18a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c @@ -123,7 +123,7 @@ static int mt7663_usb_sdio_set_rates(struct mt7615_dev *dev, idx = idx > HW_BSSID_MAX ? HW_BSSID_0 : idx; addr = idx > 1 ? MT_LPON_TCR2(idx): MT_LPON_TCR0(idx); - mt76_set(dev, addr, MT_LPON_TCR_MODE); /* TSF read */ + mt76_rmw(dev, addr, MT_LPON_TCR_MODE, MT_LPON_TCR_READ); /* TSF read */ val = mt76_rr(dev, MT_LPON_UTTR0); sta->rate_set_tsf = (val & ~BIT(0)) | rate->rateset; From ae130bb8d4bd601f72ff7c93f049a498ecc58b87 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Tue, 25 May 2021 18:34:09 +0800 Subject: [PATCH 047/170] mt76: mt7915: use mt7915_mcu_get_txpower_sku() to get per-rate txpower Get per-rate txpower with mcu command. This is the preparation of co-driver for the next chipset, which has different tmac power registers but can share this same command. Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7915/debugfs.c | 49 ++++--------------- .../net/wireless/mediatek/mt76/mt7915/mcu.c | 34 ++++++++++++- .../wireless/mediatek/mt76/mt7915/mt7915.h | 3 ++ .../net/wireless/mediatek/mt76/mt7915/regs.h | 5 -- 4 files changed, 45 insertions(+), 46 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index f1e8b076d54c..3961d46e0df8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -295,54 +295,23 @@ mt7915_puts_rate_txpower(struct seq_file *s, struct mt7915_phy *phy) "RU26", "RU52", "RU106", "RU242/SU20", "RU484/SU40", "RU996/SU80", "RU2x996/SU160" }; - struct mt7915_dev *dev = dev_get_drvdata(s->private); - bool ext_phy = phy != &dev->phy; - u32 reg_base; - int i, idx = 0; + s8 txpower[MT7915_SKU_RATE_NUM], *buf; + int i; if (!phy) return; - reg_base = MT_TMAC_FP0R0(ext_phy); - seq_printf(s, "\nBand %d\n", ext_phy); + seq_printf(s, "\nBand %d\n", phy != &phy->dev->phy); - for (i = 0; i < ARRAY_SIZE(mt7915_sku_group_len); i++) { - u8 cnt, mcs_num = mt7915_sku_group_len[i]; - s8 txpower[12]; - int j; + mt7915_mcu_get_txpower_sku(phy, txpower, sizeof(txpower)); + for (i = 0, buf = txpower; i < ARRAY_SIZE(mt7915_sku_group_len); i++) { + u8 mcs_num = mt7915_sku_group_len[i]; - if (i == SKU_HT_BW20 || i == SKU_HT_BW40) { - mcs_num = 8; - } else if (i >= SKU_VHT_BW20 && i <= SKU_VHT_BW160) { + if (i >= SKU_VHT_BW20 && i <= SKU_VHT_BW160) mcs_num = 10; - } else if (i == SKU_HE_RU26) { - reg_base = MT_TMAC_FP0R18(ext_phy); - idx = 0; - } - for (j = 0, cnt = 0; j < DIV_ROUND_UP(mcs_num, 4); j++) { - u32 val; - - if (i == SKU_VHT_BW160 && idx == 60) { - reg_base = MT_TMAC_FP0R15(ext_phy); - idx = 0; - } - - val = mt76_rr(dev, reg_base + (idx / 4) * 4); - - if (idx && idx % 4) - val >>= (idx % 4) * 8; - - while (val > 0 && cnt < mcs_num) { - s8 pwr = FIELD_GET(MT_TMAC_FP_MASK, val); - - txpower[cnt++] = pwr; - val >>= 8; - idx++; - } - } - - mt76_seq_puts_array(s, sku_group_name[i], txpower, mcs_num); + mt76_seq_puts_array(s, sku_group_name[i], buf, mcs_num); + buf += mt7915_sku_group_len[i]; } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 05ba45d0b3e1..3418ecb0a98f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -3676,7 +3676,6 @@ int mt7915_mcu_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx) int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy) { -#define MT7915_SKU_RATE_NUM 161 struct mt7915_dev *dev = phy->dev; struct mt76_phy *mphy = phy->mt76; struct ieee80211_hw *hw = mphy->hw; @@ -3726,6 +3725,39 @@ int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy) sizeof(req), true); } +int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len) +{ +#define RATE_POWER_INFO 2 + struct mt7915_dev *dev = phy->dev; + struct { + u8 format_id; + u8 category; + u8 band; + u8 _rsv; + } __packed req = { + .format_id = 7, + .category = RATE_POWER_INFO, + .band = phy != &dev->phy, + }; + s8 res[MT7915_SKU_RATE_NUM][2]; + struct sk_buff *skb; + int ret, i; + + ret = mt76_mcu_send_and_get_msg(&dev->mt76, + MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), + &req, sizeof(req), true, &skb); + if (ret) + return ret; + + memcpy(res, skb->data + 4, sizeof(res)); + for (i = 0; i < len; i++) + txpower[i] = res[i][req.band]; + + dev_kfree_skb(skb); + + return 0; +} + int mt7915_mcu_set_test_param(struct mt7915_dev *dev, u8 param, bool test_mode, u8 en) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index f3ffa907bf87..bd6c555814a8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -40,6 +40,8 @@ #define MT7915_THERMAL_THROTTLE_MAX 100 +#define MT7915_SKU_RATE_NUM 161 + struct mt7915_vif; struct mt7915_sta; struct mt7915_dfs_pulse; @@ -351,6 +353,7 @@ int mt7915_mcu_set_rts_thresh(struct mt7915_phy *phy, u32 val); int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter); int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable); int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy); +int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len); int mt7915_mcu_set_txbf_type(struct mt7915_dev *dev); int mt7915_mcu_set_txbf_module(struct mt7915_dev *dev); int mt7915_mcu_set_txbf_sounding(struct mt7915_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index e36b30d84f07..8b080cb8f10f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -82,11 +82,6 @@ #define MT_TMAC_CTCR0_INS_DDLMT_EN BIT(17) #define MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN BIT(18) -#define MT_TMAC_FP0R0(_band) MT_WF_TMAC(_band, 0x020) -#define MT_TMAC_FP0R15(_band) MT_WF_TMAC(_band, 0x080) -#define MT_TMAC_FP0R18(_band) MT_WF_TMAC(_band, 0x270) -#define MT_TMAC_FP_MASK GENMASK(7, 0) - #define MT_TMAC_TFCR0(_band) MT_WF_TMAC(_band, 0x1e0) #define MT_WF_DMA_BASE(_band) ((_band) ? 0xa1e00 : 0x21e00) From ffce39bfb6073ff6f74a1332e6563b2d18392a5b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 27 May 2021 13:01:24 +0200 Subject: [PATCH 048/170] mt76: mt7615: remove useless if condition in mt7615_add_interface() Get rid of unnecessary if condition in mt7615_add_interface routine Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index c2a122ca2e83..7c9a55c57578 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -240,8 +240,6 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, } ret = mt7615_mcu_add_dev_info(phy, vif, true); - if (ret) - goto out; out: mt7615_mutex_release(dev); From fe2c3b1fc64ea0c7a5b2ca2f671b4572ff99baf8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 27 May 2021 13:35:28 +0200 Subject: [PATCH 049/170] mt76: testmode: fix memory leak in mt76_testmode_alloc_skb Free all pending frames in case of failure in mt76_testmode_alloc_skb routine Fixes: 2601dda8faa76 ("mt76: testmode: add support to send larger packet") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/testmode.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/testmode.c b/drivers/net/wireless/mediatek/mt76/testmode.c index 001d0ba5f73e..f40387a866ee 100644 --- a/drivers/net/wireless/mediatek/mt76/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/testmode.c @@ -158,8 +158,11 @@ int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len) frag_len = MT_TXP_MAX_LEN; frag = alloc_skb(frag_len, GFP_KERNEL); - if (!frag) + if (!frag) { + mt76_testmode_free_skb(phy); + dev_kfree_skb(head); return -ENOMEM; + } __skb_put_zero(frag, frag_len); head->len += frag->len; From d705ae86852d7676214c0a71479b52f528bdd0d1 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 27 May 2021 13:35:29 +0200 Subject: [PATCH 050/170] mt76: testmode: remove unnecessary function calls in mt76_testmode_free_skb Get rid of unnecessary function calls in mt76_testmode_free_skb routine since they are already managed by dev_kfree_skb Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/testmode.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/testmode.c b/drivers/net/wireless/mediatek/mt76/testmode.c index f40387a866ee..c516469278a4 100644 --- a/drivers/net/wireless/mediatek/mt76/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/testmode.c @@ -88,17 +88,8 @@ static void mt76_testmode_free_skb(struct mt76_phy *phy) { struct mt76_testmode_data *td = &phy->test; - struct sk_buff *skb = td->tx_skb; - if (!skb) - return; - - if (skb_has_frag_list(skb)) { - kfree_skb_list(skb_shinfo(skb)->frag_list); - skb_shinfo(skb)->frag_list = NULL; - } - - dev_kfree_skb(skb); + dev_kfree_skb(td->tx_skb); td->tx_skb = NULL; } From 223cea6d3c974acd393bfac2d168b2945a6cf1e5 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 27 May 2021 13:35:30 +0200 Subject: [PATCH 051/170] mt76: testmode: remove undefined behaviour in mt76_testmode_alloc_skb Get rid of an undefined behaviour in mt76_testmode_alloc_skb routine allocating skb frames Fixes: 2601dda8faa76 ("mt76: testmode: add support to send larger packet") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/testmode.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/testmode.c b/drivers/net/wireless/mediatek/mt76/testmode.c index c516469278a4..c6a85a0cfc89 100644 --- a/drivers/net/wireless/mediatek/mt76/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/testmode.c @@ -159,12 +159,8 @@ int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len) head->len += frag->len; head->data_len += frag->len; - if (*frag_tail) { - (*frag_tail)->next = frag; - frag_tail = &frag; - } else { - *frag_tail = frag; - } + *frag_tail = frag; + frag_tail = &(*frag_tail)->next; } mt76_testmode_free_skb(phy); From 3253f8fddd954aba9ac88ce3c34551dcca505b21 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Thu, 22 Apr 2021 06:20:03 +0800 Subject: [PATCH 052/170] mt76: mt7615: fix potential overflow on large shift Fix the following static checker warning: error: undefined (user controlled) shift '(((1))) << (c->omac_idx)' Fixes: 402a695b1ae6 ("mt76: mt7615: fix CSA notification for DBDC") Reported-by: Dan Carpenter Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index a59bd7af81be..fc9cd8da2a11 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -411,6 +411,9 @@ mt7615_mcu_rx_csa_notify(struct mt7615_dev *dev, struct sk_buff *skb) c = (struct mt7615_mcu_csa_notify *)skb->data; + if (c->omac_idx > EXT_BSSID_MAX) + return; + if (ext_phy && ext_phy->omac_mask & BIT_ULL(c->omac_idx)) mphy = dev->mt76.phy2; From 3cce2b98e0241ff238e25eca1dbb480534a7695a Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Fri, 28 May 2021 19:38:09 +0800 Subject: [PATCH 053/170] mt76: mt7921: introduce mac tx done handling Instead of read tx status from mac table, add new mechanisam to hanele tx done event for data frame, every 250ms This event indicate the real tx status of this pkt in mac layer and would help mac80211 correct status more frequently Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7921/mac.c | 69 +++++++++++-------- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 47 +++++++++++++ .../net/wireless/mediatek/mt76/mt7921/mcu.h | 28 ++++++++ .../wireless/mediatek/mt76/mt7921/mt7921.h | 2 + 4 files changed, 117 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 4d1050ae9f39..99bf20d48e4c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -13,6 +13,36 @@ #define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\ IEEE80211_RADIOTAP_HE_##f) +static u8 +mt7921_next_pid(struct mt7921_dev *dev, struct mt76_wcid *wcid) +{ + wcid->packet_id = (wcid->packet_id + 1) & MT_PACKET_ID_MASK; + if (wcid->packet_id == MT_PACKET_ID_NO_ACK || + wcid->packet_id == MT_PACKET_ID_NO_SKB) + wcid->packet_id = MT_PACKET_ID_FIRST; + return wcid->packet_id; +} + +static unsigned long +mt7921_next_txs_set(struct mt7921_dev *dev, struct mt76_wcid *wcid, + u32 timeout) +{ + struct mt7921_sta *msta; + + msta = container_of(wcid, struct mt7921_sta, wcid); + msta->next_txs_ts = jiffies + msecs_to_jiffies(timeout); + return msta->next_txs_ts; +} + +static bool +mt7921_next_txs_timeout(struct mt7921_dev *dev, struct mt76_wcid *wcid) +{ + struct mt7921_sta *msta; + + msta = container_of(wcid, struct mt7921_sta, wcid); + return time_is_before_jiffies(msta->next_txs_ts); +} + static struct mt76_wcid *mt7921_rx_get_wcid(struct mt7921_dev *dev, u16 idx, bool unicast) { @@ -726,7 +756,7 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; struct mt76_phy *mphy = &dev->mphy; - u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; + u8 pid, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; u16 tx_count = 15; u32 val; @@ -795,6 +825,15 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, txwi[6] |= cpu_to_le32(val); txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); } + + if ((FIELD_GET(MT_TXD2_FRAME_TYPE, txwi[2]) & + (IEEE80211_FTYPE_DATA >> 2)) && + mt7921_next_txs_timeout(dev, wcid)) { + mt7921_next_txs_set(dev, wcid, 250); + pid = mt7921_next_pid(dev, wcid); + val = MT_TXD5_TX_STATUS_MCU | FIELD_PREP(MT_TXD5_PID, pid); + txwi[5] |= cpu_to_le32(val); + } } static void @@ -1392,30 +1431,6 @@ mt7921_mac_update_mib_stats(struct mt7921_phy *phy) } } -static void -mt7921_mac_sta_stats_work(struct mt7921_phy *phy) -{ - struct mt7921_dev *dev = phy->dev; - struct mt7921_sta *msta; - LIST_HEAD(list); - - spin_lock_bh(&dev->sta_poll_lock); - list_splice_init(&phy->stats_list, &list); - - while (!list_empty(&list)) { - msta = list_first_entry(&list, struct mt7921_sta, stats_list); - list_del_init(&msta->stats_list); - spin_unlock_bh(&dev->sta_poll_lock); - - /* query wtbl info to report tx rate for further devices */ - mt7921_get_wtbl_info(dev, msta->wcid.idx); - - spin_lock_bh(&dev->sta_poll_lock); - } - - spin_unlock_bh(&dev->sta_poll_lock); -} - void mt7921_mac_work(struct work_struct *work) { struct mt7921_phy *phy; @@ -1433,10 +1448,6 @@ void mt7921_mac_work(struct work_struct *work) mt7921_mac_update_mib_stats(phy); } - if (++phy->sta_work_count == 4) { - phy->sta_work_count = 0; - mt7921_mac_sta_stats_work(phy); - } mt7921_mutex_release(phy->dev); ieee80211_queue_delayed_work(phy->mt76->hw, &mphy->mac_work, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 37d8cbd12ff9..7b366df4a8ea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -534,6 +534,49 @@ mt7921_mcu_low_power_event(struct mt7921_dev *dev, struct sk_buff *skb) trace_lp_event(dev, event->state); } +static void +mt7921_mcu_tx_done_event(struct mt7921_dev *dev, struct sk_buff *skb) +{ + struct mt7921_mcu_tx_done_event *event; + struct mt7921_sta *msta; + struct mt7921_phy *mphy = &dev->phy; + struct mt7921_mcu_peer_cap peer; + struct ieee80211_sta *sta; + LIST_HEAD(list); + + skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); + event = (struct mt7921_mcu_tx_done_event *)skb->data; + + spin_lock_bh(&dev->sta_poll_lock); + list_splice_init(&mphy->stats_list, &list); + + while (!list_empty(&list)) { + msta = list_first_entry(&list, struct mt7921_sta, stats_list); + list_del_init(&msta->stats_list); + + if (msta->wcid.idx != event->wlan_idx) + continue; + + spin_unlock_bh(&dev->sta_poll_lock); + + sta = wcid_to_sta(&msta->wcid); + + /* peer config based on IEEE SPEC */ + memset(&peer, 0x0, sizeof(peer)); + peer.bw = event->bw; + peer.g2 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20); + peer.g4 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40); + peer.g8 = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80); + peer.g16 = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160); + mt7921_mcu_tx_rate_parse(mphy->mt76, &peer, + &msta->stats.tx_rate, event->tx_rate); + + spin_lock_bh(&dev->sta_poll_lock); + break; + } + spin_unlock_bh(&dev->sta_poll_lock); +} + static void mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) { @@ -560,6 +603,9 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) case MCU_EVENT_LP_INFO: mt7921_mcu_low_power_event(dev, skb); break; + case MCU_EVENT_TX_DONE: + mt7921_mcu_tx_done_event(dev, skb); + break; default: break; } @@ -580,6 +626,7 @@ void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb) rxd->eid == MCU_EVENT_SCHED_SCAN_DONE || rxd->eid == MCU_EVENT_BSS_ABSENCE || rxd->eid == MCU_EVENT_SCAN_DONE || + rxd->eid == MCU_EVENT_TX_DONE || rxd->eid == MCU_EVENT_DBG_MSG || rxd->eid == MCU_EVENT_COREDUMP || rxd->eid == MCU_EVENT_LP_INFO || diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h index 49823d0a3d0a..22ebef4add00 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h @@ -81,6 +81,7 @@ enum { MCU_EVENT_REG_ACCESS = 0x05, MCU_EVENT_LP_INFO = 0x07, MCU_EVENT_SCAN_DONE = 0x0d, + MCU_EVENT_TX_DONE = 0x0f, MCU_EVENT_BSS_ABSENCE = 0x11, MCU_EVENT_BSS_BEACON_LOSS = 0x13, MCU_EVENT_CH_PRIVILEGE = 0x18, @@ -407,4 +408,31 @@ struct mt7921_txpwr_event { struct mt7921_txpwr txpwr; } __packed; +struct mt7921_mcu_tx_done_event { + u8 pid; + u8 status; + u16 seq; + + u8 wlan_idx; + u8 tx_cnt; + u16 tx_rate; + + u8 flag; + u8 tid; + u8 rsp_rate; + u8 mcs; + + u8 bw; + u8 tx_pwr; + u8 reason; + u8 rsv0[1]; + + u32 delay; + u32 timestamp; + u32 applied_flag; + + u8 txs[28]; + + u8 rsv1[32]; +} __packed; #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 1e65a8f6f211..a9b21fcc321c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -92,6 +92,8 @@ struct mt7921_sta { unsigned long ampdu_state; struct mt7921_sta_key_conf bip; + + unsigned long next_txs_ts; }; DECLARE_EWMA(rssi, 10, 8); From e3fd9934cf6e22c30e843d1902695b2379318be0 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Fri, 28 May 2021 01:05:33 +0800 Subject: [PATCH 054/170] mt76: mt7921: update statistic in active mode only wakeup chip every 250ms may cause huge power consumption try to update statistic counter only if in active status only, and it would lead fewer power cost Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 99bf20d48e4c..882bb74d0406 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1483,13 +1483,15 @@ void mt7921_pm_power_save_work(struct work_struct *work) { struct mt7921_dev *dev; unsigned long delta; + struct mt76_phy *mphy; dev = (struct mt7921_dev *)container_of(work, struct mt7921_dev, pm.ps_work.work); + mphy = dev->phy.mt76; delta = dev->pm.idle_timeout; - if (test_bit(MT76_HW_SCANNING, &dev->mphy.state) || - test_bit(MT76_HW_SCHED_SCANNING, &dev->mphy.state)) + if (test_bit(MT76_HW_SCANNING, &mphy->state) || + test_bit(MT76_HW_SCHED_SCANNING, &mphy->state)) goto out; if (time_is_after_jiffies(dev->pm.last_activity + delta)) { @@ -1497,8 +1499,10 @@ void mt7921_pm_power_save_work(struct work_struct *work) goto out; } - if (!mt7921_mcu_fw_pmctrl(dev)) + if (!mt7921_mcu_fw_pmctrl(dev)) { + cancel_delayed_work_sync(&mphy->mac_work); return; + } out: queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta); } From 8af414e8835be1a214ac16c37fc8686ef68218e6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 May 2021 13:02:24 +0200 Subject: [PATCH 055/170] mt76: allow hw driver code to overwrite wiphy interface_modes Move wiphy interface_modes configuration in mt76_alloc_device and mt76_alloc_phy in order to be overwritten by hw specific code since some drivers do not support all operating modes (mt7921 supports sta only in the current codebase) Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 33 ++++++++++++------- .../net/wireless/mediatek/mt76/mt7921/init.c | 2 ++ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 447bc9a3abb0..49da219d4e52 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -331,17 +331,6 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw) ieee80211_hw_set(hw, MFP_CAPABLE); ieee80211_hw_set(hw, AP_LINK_PS); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); - - wiphy->flags |= WIPHY_FLAG_IBSS_RSN; - wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP) | -#ifdef CONFIG_MAC80211_MESH - BIT(NL80211_IFTYPE_MESH_POINT) | -#endif - BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO) | - BIT(NL80211_IFTYPE_ADHOC); } struct mt76_phy * @@ -362,6 +351,17 @@ mt76_alloc_phy(struct mt76_dev *dev, unsigned int size, phy->hw = hw; phy->priv = hw->priv + phy_size; + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_ADHOC); + return phy; } EXPORT_SYMBOL_GPL(mt76_alloc_phy); @@ -444,6 +444,17 @@ mt76_alloc_device(struct device *pdev, unsigned int size, mutex_init(&dev->mcu.mutex); dev->tx_worker.fn = mt76_tx_worker; + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_ADHOC); + spin_lock_init(&dev->token_lock); idr_init(&dev->token); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 99701cda0b9d..9253706c24a0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -62,6 +62,8 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) hw->vif_data_size = sizeof(struct mt7921_vif); wiphy->iface_combinations = if_comb; + wiphy->flags &= ~WIPHY_FLAG_IBSS_RSN; + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN; wiphy->max_scan_ssids = 4; From 7f731405eeca869c51c8792544ef5b26c28c31c3 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 1 Jun 2021 22:26:31 +0200 Subject: [PATCH 056/170] mt76: mt7915: improve error recovery reliability - Remove no-op code for queue lock/unlock, which is no longer needed - Set a missing DMA flag - Wait for full completion of error recovery before restarting tx - Schedule IRQ tasklet to ensure that IRQ mask gets written Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/mac.c | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 642a11e72bef..ecd00dfa68ff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1608,14 +1608,18 @@ mt7915_dma_reset(struct mt7915_dev *dev) mt76_set(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); mt76_set(dev, MT_WFDMA1_GLO_CFG, - MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN); + MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN | + MT_WFDMA1_GLO_CFG_OMIT_TX_INFO | + MT_WFDMA1_GLO_CFG_OMIT_RX_INFO); if (dev->hif2) { mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, (MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN)); mt76_set(dev, MT_WFDMA1_GLO_CFG + hif1_ofs, (MT_WFDMA1_GLO_CFG_TX_DMA_EN | - MT_WFDMA1_GLO_CFG_RX_DMA_EN)); + MT_WFDMA1_GLO_CFG_RX_DMA_EN | + MT_WFDMA1_GLO_CFG_OMIT_TX_INFO | + MT_WFDMA1_GLO_CFG_OMIT_RX_INFO)); } } @@ -1659,11 +1663,6 @@ void mt7915_mac_reset_work(struct work_struct *work) set_bit(MT76_RESET, &phy2->mt76->state); cancel_delayed_work_sync(&phy2->mt76->mac_work); } - /* lock/unlock all queues to ensure that no tx is pending */ - mt76_txq_schedule_all(&dev->mphy); - if (ext_phy) - mt76_txq_schedule_all(ext_phy); - mt76_worker_disable(&dev->mt76.tx_worker); napi_disable(&dev->mt76.napi[0]); napi_disable(&dev->mt76.napi[1]); @@ -1689,10 +1688,6 @@ void mt7915_mac_reset_work(struct work_struct *work) if (phy2) clear_bit(MT76_RESET, &phy2->mt76->state); - mt76_worker_enable(&dev->mt76.tx_worker); - napi_enable(&dev->mt76.tx_napi); - napi_schedule(&dev->mt76.tx_napi); - napi_enable(&dev->mt76.napi[0]); napi_schedule(&dev->mt76.napi[0]); @@ -1701,14 +1696,20 @@ void mt7915_mac_reset_work(struct work_struct *work) napi_enable(&dev->mt76.napi[2]); napi_schedule(&dev->mt76.napi[2]); + tasklet_schedule(&dev->irq_tasklet); + + mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE); + mt7915_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); + + mt76_worker_enable(&dev->mt76.tx_worker); + + napi_enable(&dev->mt76.tx_napi); + napi_schedule(&dev->mt76.tx_napi); ieee80211_wake_queues(mt76_hw(dev)); if (ext_phy) ieee80211_wake_queues(ext_phy->hw); - mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE); - mt7915_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); - mutex_unlock(&dev->mt76.mutex); mt7915_update_beacons(dev); From 5ff4c4aab79b39810b30f5fd63117245d7554cb5 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 28 May 2021 19:11:42 +0200 Subject: [PATCH 057/170] mt76: mt7921: set MT76_RESET during mac reset Set MT76_RESET during mt7921_mac_reset in order to avoid packet transmissions. Move tx scheduling at the end of reset routine. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7921/mac.c | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 882bb74d0406..ed886f8633b1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1294,6 +1294,7 @@ mt7921_mac_reset(struct mt7921_dev *dev) mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0); mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); + set_bit(MT76_RESET, &dev->mphy.state); set_bit(MT76_MCU_RESET, &dev->mphy.state); wake_up(&dev->mt76.mcu.wait); skb_queue_purge(&dev->mt76.mcu.res_q); @@ -1309,19 +1310,13 @@ mt7921_mac_reset(struct mt7921_dev *dev) mt7921_tx_token_put(dev); idr_init(&dev->mt76.token); - err = mt7921_wpdma_reset(dev, true); - if (err) - return err; + mt7921_wpdma_reset(dev, true); mt76_for_each_q_rx(&dev->mt76, i) { napi_enable(&dev->mt76.napi[i]); napi_schedule(&dev->mt76.napi[i]); } - napi_enable(&dev->mt76.tx_napi); - napi_schedule(&dev->mt76.tx_napi); - mt76_worker_enable(&dev->mt76.tx_worker); - clear_bit(MT76_MCU_RESET, &dev->mphy.state); mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, @@ -1331,17 +1326,25 @@ mt7921_mac_reset(struct mt7921_dev *dev) err = mt7921_run_firmware(dev); if (err) - return err; + goto out; err = mt7921_mcu_set_eeprom(dev); if (err) - return err; + goto out; err = mt7921_mac_init(dev); if (err) - return err; + goto out; - return __mt7921_start(&dev->phy); + err = __mt7921_start(&dev->phy); +out: + clear_bit(MT76_RESET, &dev->mphy.state); + + napi_enable(&dev->mt76.tx_napi); + napi_schedule(&dev->mt76.tx_napi); + mt76_worker_enable(&dev->mt76.tx_worker); + + return err; } /* system error recovery */ From 6543002811960d882d722127b4b11e835af0db40 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 15 May 2021 12:17:29 +0800 Subject: [PATCH 058/170] mt76: mt7915: use mt7915_mcu_get_mib_info() to get survey data Firmware functions (SCS, MU ...) also require read-clear phy counters, hence firmware prepares a global task to read shared fields out to a shared pool to avoid concurrency. Switch to event format accordingly. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/init.c | 1 - .../net/wireless/mediatek/mt76/mt7915/mac.c | 38 +++------------ .../net/wireless/mediatek/mt76/mt7915/mcu.c | 46 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7915/mcu.h | 14 ++++++ .../wireless/mediatek/mt76/mt7915/mt7915.h | 2 + .../net/wireless/mediatek/mt76/mt7915/regs.h | 20 +------- 6 files changed, 69 insertions(+), 52 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 39f3639aa096..10c8d9244dc9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -287,7 +287,6 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band) FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_MCAST, MT_MDP_TO_HIF); mt76_rmw(dev, MT_MDP_BNRCFR1(band), mask, set); - mt76_set(dev, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 1536); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index ecd00dfa68ff..741899aaaed8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1374,14 +1374,10 @@ void mt7915_mac_reset_counters(struct mt7915_phy *phy) memset(&dev->mt76.aggr_stats[i], 0, sizeof(dev->mt76.aggr_stats) / 2); /* reset airtime counters */ - mt76_rr(dev, MT_MIB_SDR9(ext_phy)); - mt76_rr(dev, MT_MIB_SDR36(ext_phy)); - mt76_rr(dev, MT_MIB_SDR37(ext_phy)); - - mt76_set(dev, MT_WF_RMAC_MIB_TIME0(ext_phy), - MT_WF_RMAC_MIB_RXTIME_CLR); mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(ext_phy), MT_WF_RMAC_MIB_RXTIME_CLR); + + mt7915_mcu_get_chan_mib_info(phy, true); } void mt7915_mac_set_timing(struct mt7915_phy *phy) @@ -1478,20 +1474,11 @@ mt7915_phy_get_nf(struct mt7915_phy *phy, int idx) static void mt7915_phy_update_channel(struct mt76_phy *mphy, int idx) { - struct mt7915_dev *dev = container_of(mphy->dev, struct mt7915_dev, mt76); struct mt7915_phy *phy = (struct mt7915_phy *)mphy->priv; - struct mt76_channel_state *state; - u64 busy_time, tx_time, rx_time, obss_time; + struct mt76_channel_state *state = mphy->chan_state; int nf; - busy_time = mt76_get_field(dev, MT_MIB_SDR9(idx), - MT_MIB_SDR9_BUSY_MASK); - tx_time = mt76_get_field(dev, MT_MIB_SDR36(idx), - MT_MIB_SDR36_TXTIME_MASK); - rx_time = mt76_get_field(dev, MT_MIB_SDR37(idx), - MT_MIB_SDR37_RXTIME_MASK); - obss_time = mt76_get_field(dev, MT_WF_RMAC_MIB_AIRTIME14(idx), - MT_MIB_OBSSTIME_MASK); + mt7915_mcu_get_chan_mib_info(phy, false); nf = mt7915_phy_get_nf(phy, idx); if (!phy->noise) @@ -1499,27 +1486,14 @@ mt7915_phy_update_channel(struct mt76_phy *mphy, int idx) else if (nf) phy->noise += nf - (phy->noise >> 4); - state = mphy->chan_state; - state->cc_busy += busy_time; - state->cc_tx += tx_time; - state->cc_rx += rx_time + obss_time; - state->cc_bss_rx += rx_time; state->noise = -(phy->noise >> 4); } void mt7915_update_channel(struct mt76_dev *mdev) { - struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); - mt7915_phy_update_channel(&mdev->phy, 0); if (mdev->phy2) mt7915_phy_update_channel(mdev->phy2, 1); - - /* reset obss airtime */ - mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR); - if (mdev->phy2) - mt76_set(dev, MT_WF_RMAC_MIB_TIME0(1), - MT_WF_RMAC_MIB_RXTIME_CLR); } static bool @@ -1723,7 +1697,7 @@ void mt7915_mac_reset_work(struct work_struct *work) } static void -mt7915_mac_update_mib_stats(struct mt7915_phy *phy) +mt7915_mac_update_stats(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; struct mib_stats *mib = &phy->mib; @@ -1834,7 +1808,7 @@ void mt7915_mac_work(struct work_struct *work) if (++mphy->mac_work_count == 5) { mphy->mac_work_count = 0; - mt7915_mac_update_mib_stats(phy); + mt7915_mac_update_stats(phy); } if (++phy->sta_work_count == 10) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 3418ecb0a98f..59806ec96829 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -3580,6 +3580,52 @@ int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy) return 0; } +int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch) +{ + /* strict order */ + static const enum mt7915_chan_mib_offs offs[] = { + MIB_BUSY_TIME, MIB_TX_TIME, MIB_RX_TIME, MIB_OBSS_AIRTIME + }; + struct mt76_channel_state *state = phy->mt76->chan_state; + struct mt76_channel_state *state_ts = &phy->state_ts; + struct mt7915_dev *dev = phy->dev; + struct mt7915_mcu_mib *res, req[4]; + struct sk_buff *skb; + int i, ret; + + for (i = 0; i < 4; i++) { + req[i].band = cpu_to_le32(phy != &dev->phy); + req[i].offs = cpu_to_le32(offs[i]); + } + + ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(GET_MIB_INFO), + req, sizeof(req), true, &skb); + if (ret) + return ret; + + res = (struct mt7915_mcu_mib *)(skb->data + 20); + + if (chan_switch) + goto out; + +#define __res_u64(s) le64_to_cpu(res[s].data) + state->cc_busy += __res_u64(0) - state_ts->cc_busy; + state->cc_tx += __res_u64(1) - state_ts->cc_tx; + state->cc_bss_rx += __res_u64(2) - state_ts->cc_bss_rx; + state->cc_rx += __res_u64(2) + __res_u64(3) - state_ts->cc_rx; + +out: + state_ts->cc_busy = __res_u64(0); + state_ts->cc_tx = __res_u64(1); + state_ts->cc_bss_rx = __res_u64(2); + state_ts->cc_rx = __res_u64(2) + __res_u64(3); +#undef __res_u64 + + dev_kfree_skb(skb); + + return 0; +} + int mt7915_mcu_get_temperature(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 7e3432384633..70ab06d9f954 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -216,6 +216,19 @@ struct mt7915_mcu_phy_rx_info { #define MT_RA_RATE_DCM_EN BIT(4) #define MT_RA_RATE_BW GENMASK(14, 13) +struct mt7915_mcu_mib { + __le32 band; + __le32 offs; + __le64 data; +} __packed; + +enum mt7915_chan_mib_offs { + MIB_BUSY_TIME = 14, + MIB_TX_TIME = 81, + MIB_RX_TIME, + MIB_OBSS_AIRTIME = 86 +}; + struct edca { u8 queue; u8 set; @@ -301,6 +314,7 @@ enum { MCU_EXT_CMD_MUAR_UPDATE = 0x48, MCU_EXT_CMD_SET_RX_PATH = 0x4e, MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58, + MCU_EXT_CMD_GET_MIB_INFO = 0x5a, MCU_EXT_CMD_MWDS_SUPPORT = 0x80, MCU_EXT_CMD_SET_SER_TRIGGER = 0x81, MCU_EXT_CMD_SCS_CTRL = 0x82, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index bd6c555814a8..3cce464bc2c5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -149,6 +149,7 @@ struct mt7915_phy { u32 ampdu_ref; struct mib_stats mib; + struct mt76_channel_state state_ts; struct list_head stats_list; u8 sta_work_count; @@ -364,6 +365,7 @@ int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index, const struct mt7915_dfs_pattern *pattern); int mt7915_mcu_apply_group_cal(struct mt7915_dev *dev); int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy); +int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch); int mt7915_mcu_get_temperature(struct mt7915_phy *phy); int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state); int mt7915_mcu_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index 8b080cb8f10f..56c33eaa9d79 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -129,20 +129,9 @@ #define MT_MIB_SDR3(_band) MT_WF_MIB(_band, 0x014) #define MT_MIB_SDR3_FCS_ERR_MASK GENMASK(15, 0) -#define MT_MIB_SDR9(_band) MT_WF_MIB(_band, 0x02c) -#define MT_MIB_SDR9_BUSY_MASK GENMASK(23, 0) - -#define MT_MIB_SDR16(_band) MT_WF_MIB(_band, 0x048) -#define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0) - #define MT_MIB_SDR34(_band) MT_WF_MIB(_band, 0x090) #define MT_MIB_MU_BF_TX_CNT GENMASK(15, 0) -#define MT_MIB_SDR36(_band) MT_WF_MIB(_band, 0x098) -#define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0) -#define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x09c) -#define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0) - #define MT_MIB_DR8(_band) MT_WF_MIB(_band, 0x0c0) #define MT_MIB_DR9(_band) MT_WF_MIB(_band, 0x0c4) #define MT_MIB_DR11(_band) MT_WF_MIB(_band, 0x0cc) @@ -155,9 +144,6 @@ #define MT_MIB_BA_MISS_COUNT_MASK GENMASK(15, 0) #define MT_MIB_ACK_FAIL_COUNT_MASK GENMASK(31, 16) -#define MT_MIB_MB_SDR2(_band, n) MT_WF_MIB(_band, 0x108 + ((n) << 4)) -#define MT_MIB_FRAME_RETRIES_COUNT_MASK GENMASK(15, 0) - #define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0x0a8 + ((n) << 2)) #define MT_TX_AGG_CNT2(_band, n) MT_WF_MIB(_band, 0x164 + ((n) << 2)) #define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x4b8 + ((n) << 2)) @@ -255,14 +241,10 @@ #define MT_WF_RFCR1_DROP_CFEND BIT(7) #define MT_WF_RFCR1_DROP_CFACK BIT(8) -#define MT_WF_RMAC_MIB_TIME0(_band) MT_WF_RMAC(_band, 0x03c4) +#define MT_WF_RMAC_MIB_AIRTIME0(_band) MT_WF_RMAC(_band, 0x0380) #define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31) #define MT_WF_RMAC_MIB_RXTIME_EN BIT(30) -#define MT_WF_RMAC_MIB_AIRTIME14(_band) MT_WF_RMAC(_band, 0x03b8) -#define MT_MIB_OBSSTIME_MASK GENMASK(23, 0) -#define MT_WF_RMAC_MIB_AIRTIME0(_band) MT_WF_RMAC(_band, 0x0380) - /* WFDMA0 */ #define MT_WFDMA0_BASE 0xd4000 #define MT_WFDMA0(ofs) (MT_WFDMA0_BASE + (ofs)) From 83d229d28b10d5da9b71a06bee6395567bee732a Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Sat, 29 May 2021 19:11:50 +0800 Subject: [PATCH 059/170] mt76: mt7915: read all eeprom fields from fw in efuse mode If efuse mode is used, read all values from fw during eeprom init, which makes it more convinient to check if rf values in efuse are properly burned. Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7915/eeprom.c | 44 +++++++++---------- .../net/wireless/mediatek/mt76/mt7915/mcu.c | 5 ++- .../wireless/mediatek/mt76/mt7915/mt7915.h | 1 + 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c index 8ededf2e5279..ee3d64434821 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c @@ -4,22 +4,12 @@ #include "mt7915.h" #include "eeprom.h" -static u32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset) -{ - u8 *data = dev->mt76.eeprom.data; - - if (data[offset] == 0xff && !dev->flash_mode) - mt7915_mcu_get_eeprom(dev, offset); - - return data[offset]; -} - static int mt7915_eeprom_load_precal(struct mt7915_dev *dev) { struct mt76_dev *mdev = &dev->mt76; - u32 val; + u8 *eeprom = mdev->eeprom.data; + u32 val = eeprom[MT_EE_DO_PRE_CAL]; - val = mt7915_eeprom_read(dev, MT_EE_DO_PRE_CAL); if (val != (MT_EE_WIFI_CAL_DPD | MT_EE_WIFI_CAL_GROUP)) return 0; @@ -43,7 +33,13 @@ static int mt7915_eeprom_load(struct mt7915_dev *dev) dev->flash_mode = true; ret = mt7915_eeprom_load_precal(dev); } else { - memset(dev->mt76.eeprom.data, -1, MT7915_EEPROM_SIZE); + u32 block_num, i; + + block_num = DIV_ROUND_UP(MT7915_EEPROM_SIZE, + MT7915_EEPROM_BLOCK_SIZE); + for (i = 0; i < block_num; i++) + mt7915_mcu_get_eeprom(dev, + i * MT7915_EEPROM_BLOCK_SIZE); } return ret; @@ -52,10 +48,7 @@ static int mt7915_eeprom_load(struct mt7915_dev *dev) static int mt7915_check_eeprom(struct mt7915_dev *dev) { u8 *eeprom = dev->mt76.eeprom.data; - u16 val; - - mt7915_eeprom_read(dev, MT_EE_CHIP_ID); - val = get_unaligned_le16(eeprom); + u16 val = get_unaligned_le16(eeprom); switch (val) { case 0x7915: @@ -69,9 +62,10 @@ void mt7915_eeprom_parse_band_config(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; + u8 *eeprom = dev->mt76.eeprom.data; u32 val; - val = mt7915_eeprom_read(dev, MT_EE_WIFI_CONF + ext_phy); + val = eeprom[MT_EE_WIFI_CONF + ext_phy]; val = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val); if (val == MT_EE_BAND_SEL_DEFAULT && dev->dbdc_support) val = ext_phy ? MT_EE_BAND_SEL_5GHZ : MT_EE_BAND_SEL_2GHZ; @@ -143,6 +137,7 @@ int mt7915_eeprom_get_target_power(struct mt7915_dev *dev, struct ieee80211_channel *chan, u8 chain_idx) { + u8 *eeprom = dev->mt76.eeprom.data; int index, target_power; bool tssi_on; @@ -153,18 +148,18 @@ int mt7915_eeprom_get_target_power(struct mt7915_dev *dev, if (chan->band == NL80211_BAND_2GHZ) { index = MT_EE_TX0_POWER_2G + chain_idx * 3; - target_power = mt7915_eeprom_read(dev, index); + target_power = eeprom[index]; if (!tssi_on) - target_power += mt7915_eeprom_read(dev, index + 1); + target_power += eeprom[index + 1]; } else { int group = mt7915_get_channel_group(chan->hw_value); index = MT_EE_TX0_POWER_5G + chain_idx * 12; - target_power = mt7915_eeprom_read(dev, index + group); + target_power = eeprom[index + group]; if (!tssi_on) - target_power += mt7915_eeprom_read(dev, index + 8); + target_power += eeprom[index + 8]; } return target_power; @@ -172,13 +167,14 @@ int mt7915_eeprom_get_target_power(struct mt7915_dev *dev, s8 mt7915_eeprom_get_power_delta(struct mt7915_dev *dev, int band) { + u8 *eeprom = dev->mt76.eeprom.data; u32 val; s8 delta; if (band == NL80211_BAND_2GHZ) - val = mt7915_eeprom_read(dev, MT_EE_RATE_DELTA_2G); + val = eeprom[MT_EE_RATE_DELTA_2G]; else - val = mt7915_eeprom_read(dev, MT_EE_RATE_DELTA_5G); + val = eeprom[MT_EE_RATE_DELTA_5G]; if (!(val & MT_EE_RATE_DELTA_EN)) return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 59806ec96829..059da720d957 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -3417,7 +3417,8 @@ int mt7915_mcu_set_eeprom(struct mt7915_dev *dev) int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset) { struct mt7915_mcu_eeprom_info req = { - .addr = cpu_to_le32(round_down(offset, 16)), + .addr = cpu_to_le32(round_down(offset, + MT7915_EEPROM_BLOCK_SIZE)), }; struct mt7915_mcu_eeprom_info *res; struct sk_buff *skb; @@ -3431,7 +3432,7 @@ int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset) res = (struct mt7915_mcu_eeprom_info *)skb->data; buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr); - memcpy(buf, res->data, 16); + memcpy(buf, res->data, MT7915_EEPROM_BLOCK_SIZE); dev_kfree_skb(skb); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 3cce464bc2c5..a4b32e0d64e9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -31,6 +31,7 @@ #define MT7915_ROM_PATCH "mediatek/mt7915_rom_patch.bin" #define MT7915_EEPROM_SIZE 3584 +#define MT7915_EEPROM_BLOCK_SIZE 16 #define MT7915_TOKEN_SIZE 8192 #define MT7915_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ From a60951d4faa0ef2e475797dd217c2eaee32ed1c2 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 31 May 2021 08:33:18 +0200 Subject: [PATCH 060/170] mt76: mt7921: enable hw offloading for wep keys Enable wep key hw offloading for sta mode. This patch fixes WoW support for wep connections. Tested-by: Deren.Wu Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7921/main.c | 22 ++++++++++++++----- .../wireless/mediatek/mt76/mt7921/mt7921.h | 2 ++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 175030ec221d..a6cf4a0e286a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -376,6 +376,10 @@ static int mt7921_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; wcid_keyidx = &wcid->hw_key_idx2; break; + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + if (!mvif->wep_sta) + return -EOPNOTSUPP; case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP_256: @@ -383,8 +387,6 @@ static int mt7921_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, case WLAN_CIPHER_SUITE_GCMP_256: case WLAN_CIPHER_SUITE_SMS4: break; - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: default: return -EOPNOTSUPP; } @@ -402,6 +404,12 @@ static int mt7921_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, cmd == SET_KEY ? key : NULL); err = mt7921_mcu_add_key(dev, vif, msta, key, cmd); + if (err) + goto out; + + if (key->cipher == WLAN_CIPHER_SUITE_WEP104 || + key->cipher == WLAN_CIPHER_SUITE_WEP40) + err = mt7921_mcu_add_key(dev, vif, mvif->wep_sta, key, cmd); out: mt7921_mutex_release(dev); @@ -608,9 +616,12 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (ret) return ret; - if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) - mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, &mvif->sta.wcid, - true); + if (vif->type == NL80211_IFTYPE_STATION) { + mvif->wep_sta = msta; + if (!sta->tdls) + mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, + &mvif->sta.wcid, true); + } mt7921_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); @@ -640,6 +651,7 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (vif->type == NL80211_IFTYPE_STATION) { struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + mvif->wep_sta = NULL; ewma_rssi_init(&mvif->rssi); if (!sta->tdls) mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index a9b21fcc321c..30902231a4bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -102,6 +102,8 @@ struct mt7921_vif { struct mt76_vif mt76; /* must be first */ struct mt7921_sta sta; + struct mt7921_sta *wep_sta; + struct mt7921_phy *phy; struct ewma_rssi rssi; From 15539a5ba6fc1ee6c84e06b2f4977032ca5be202 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 31 May 2021 17:53:29 +0200 Subject: [PATCH 061/170] mt76: mt7921: remove mt7921_get_wtbl_info routine Since now the fw reports tx rate events without polling, mt7921_get_wtbl_info and related structures are no longer used. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 57 --------- .../net/wireless/mediatek/mt76/mt7921/mcu.h | 115 ------------------ .../wireless/mediatek/mt76/mt7921/mt7921.h | 1 - 3 files changed, 173 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 7b366df4a8ea..ffc83717fd0d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -398,43 +398,6 @@ mt7921_mcu_tx_rate_parse(struct mt76_phy *mphy, } } -static void -mt7921_mcu_tx_rate_report(struct mt7921_dev *dev, struct sk_buff *skb, - u16 wlan_idx) -{ - struct mt7921_mcu_wlan_info_event *wtbl_info; - struct mt76_phy *mphy = &dev->mphy; - struct mt7921_sta_stats *stats; - struct rate_info rate = {}; - struct mt7921_sta *msta; - struct mt76_wcid *wcid; - u8 idx; - - if (wlan_idx >= MT76_N_WCIDS) - return; - - wtbl_info = (struct mt7921_mcu_wlan_info_event *)skb->data; - idx = wtbl_info->rate_info.rate_idx; - if (idx >= ARRAY_SIZE(wtbl_info->rate_info.rate)) - return; - - rcu_read_lock(); - - wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); - if (!wcid) - goto out; - - msta = container_of(wcid, struct mt7921_sta, wcid); - stats = &msta->stats; - - /* current rate */ - mt7921_mcu_tx_rate_parse(mphy, &wtbl_info->peer_cap, &rate, - le16_to_cpu(wtbl_info->rate_info.rate[idx])); - stats->tx_rate = rate; -out: - rcu_read_unlock(); -} - static void mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb) { @@ -1192,26 +1155,6 @@ int mt7921_mcu_get_eeprom(struct mt7921_dev *dev, u32 offset) return 0; } -u32 mt7921_get_wtbl_info(struct mt7921_dev *dev, u32 wlan_idx) -{ - struct mt7921_mcu_wlan_info wtbl_info = { - .wlan_idx = cpu_to_le32(wlan_idx), - }; - struct sk_buff *skb; - int ret; - - ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CMD_GET_WTBL, - &wtbl_info, sizeof(wtbl_info), true, - &skb); - if (ret) - return ret; - - mt7921_mcu_tx_rate_report(dev, skb, wlan_idx); - dev_kfree_skb(skb); - - return 0; -} - int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif) { struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h index 22ebef4add00..89fed2f71161 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h @@ -255,86 +255,6 @@ struct mt7921_mcu_reg_event { __le32 val; } __packed; -struct mt7921_mcu_tx_config { - u8 peer_addr[ETH_ALEN]; - u8 sw; - u8 dis_rx_hdr_tran; - - u8 aad_om; - u8 pfmu_idx; - __le16 partial_aid; - - u8 ibf; - u8 ebf; - u8 is_ht; - u8 is_vht; - - u8 mesh; - u8 baf_en; - u8 cf_ack; - u8 rdg_ba; - - u8 rdg; - u8 pm; - u8 rts; - u8 smps; - - u8 txop_ps; - u8 not_update_ipsm; - u8 skip_tx; - u8 ldpc; - - u8 qos; - u8 from_ds; - u8 to_ds; - u8 dyn_bw; - - u8 amdsu_cross_lg; - u8 check_per; - u8 gid_63; - u8 he; - - u8 vht_ibf; - u8 vht_ebf; - u8 vht_ldpc; - u8 he_ldpc; -} __packed; - -struct mt7921_mcu_sec_config { - u8 wpi_flag; - u8 rv; - u8 ikv; - u8 rkv; - - u8 rcid; - u8 rca1; - u8 rca2; - u8 even_pn; - - u8 key_id; - u8 muar_idx; - u8 cipher_suit; - u8 rsv[1]; -} __packed; - -struct mt7921_mcu_key_config { - u8 key[32]; -} __packed; - -struct mt7921_mcu_rate_info { - u8 mpdu_fail; - u8 mpdu_tx; - u8 rate_idx; - u8 rsv[1]; - __le16 rate[8]; -} __packed; - -struct mt7921_mcu_ba_config { - u8 ba_en; - u8 rsv[3]; - __le32 ba_winsize; -} __packed; - struct mt7921_mcu_ant_id_config { u8 ant_id[4]; } __packed; @@ -358,41 +278,6 @@ struct mt7921_mcu_peer_cap { u8 rsv[1]; } __packed; -struct mt7921_mcu_rx_cnt { - u8 rx_rcpi[4]; - u8 rx_cc[4]; - u8 rx_cc_sel; - u8 ce_rmsd; - u8 rsv[2]; -} __packed; - -struct mt7921_mcu_tx_cnt { - __le16 rate1_cnt; - __le16 rate1_fail_cnt; - __le16 rate2_cnt; - __le16 rate3_cnt; - __le16 cur_bw_tx_cnt; - __le16 cur_bw_tx_fail_cnt; - __le16 other_bw_tx_cnt; - __le16 other_bw_tx_fail_cnt; -} __packed; - -struct mt7921_mcu_wlan_info_event { - struct mt7921_mcu_tx_config tx_config; - struct mt7921_mcu_sec_config sec_config; - struct mt7921_mcu_key_config key_config; - struct mt7921_mcu_rate_info rate_info; - struct mt7921_mcu_ba_config ba_config; - struct mt7921_mcu_peer_cap peer_cap; - struct mt7921_mcu_rx_cnt rx_cnt; - struct mt7921_mcu_tx_cnt tx_cnt; -} __packed; - -struct mt7921_mcu_wlan_info { - __le32 wlan_idx; - struct mt7921_mcu_wlan_info_event event; -} __packed; - struct mt7921_txpwr_req { u8 ver; u8 action; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 30902231a4bf..8aa8d2ecdffa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -367,7 +367,6 @@ int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev, struct ieee80211_ampdu_params *params, bool enable); void mt7921_scan_work(struct work_struct *work); -u32 mt7921_get_wtbl_info(struct mt7921_dev *dev, u32 wlan_idx); int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif); int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, bool enable); From 9f367c81de94a8171f7149f14a5f740f0009dd27 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Tue, 1 Jun 2021 01:01:22 +0800 Subject: [PATCH 062/170] mt76: mt7921: enable random mac address during sched_scan Enable src address randomization during scheduled scanning Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 14 ++++++++------ .../net/wireless/mediatek/mt76/mt76_connac_mcu.h | 4 +++- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 3 ++- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 9066c57b1e32..a5312d225d93 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1519,14 +1519,16 @@ int mt76_connac_mcu_sched_scan_req(struct mt76_phy *phy, req->version = 1; req->seq_num = mvif->scan_seq_num | ext_phy << 7; - if (is_mt7663(phy->dev) && - (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)) { - get_random_mask_addr(req->mt7663.random_mac, sreq->mac_addr, - sreq->mac_addr_mask); + if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { + u8 *addr = is_mt7663(phy->dev) ? req->mt7663.random_mac + : req->mt7921.random_mac; + req->scan_func = 1; - } else if (is_mt7921(phy->dev)) { - req->mt7921.bss_idx = mvif->idx; + get_random_mask_addr(addr, sreq->mac_addr, + sreq->mac_addr_mask); } + if (is_mt7921(phy->dev)) + req->mt7921.bss_idx = mvif->idx; req->ssids_num = sreq->n_ssids; for (i = 0; i < req->ssids_num; i++) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 13f7d6a57889..b574d444ddca 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -779,7 +779,9 @@ struct mt76_connac_sched_scan_req { } mt7663; struct { u8 bss_idx; - u8 pad2[63]; + u8 pad2[19]; + u8 random_mac[ETH_ALEN]; + u8 pad3[38]; } mt7921; }; } __packed; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 9253706c24a0..06fca78fe149 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -76,7 +76,8 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; wiphy->reg_notifier = mt7921_regd_notifier; - wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; + wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | + NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL); ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); From 798bffd8004fd10c084131b07519d0f6f0c2fac0 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Wed, 2 Jun 2021 09:50:17 +0800 Subject: [PATCH 063/170] mt76: mt7915: setup drr group for peers This is a prerequisite for MU functionality. Tested-by: Evelyn Tsai Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/mcu.c | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 059da720d957..e28396938ce9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -2353,6 +2353,32 @@ int mt7915_mcu_add_he(struct mt7915_dev *dev, struct ieee80211_vif *vif, MCU_EXT_CMD(STA_REC_UPDATE), true); } +static int +mt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ +#define MT_STA_BSS_GROUP 1 + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct { + __le32 action; + u8 wlan_idx_lo; + u8 status; + u8 wlan_idx_hi; + u8 rsv0[5]; + __le32 val; + u8 rsv1[8]; + } __packed req = { + .action = cpu_to_le32(MT_STA_BSS_GROUP), + .wlan_idx_lo = to_wcid_lo(msta->wcid.idx), + .wlan_idx_hi = to_wcid_hi(msta->wcid.idx), + .val = cpu_to_le32(mvif->idx % 16), + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_DRR_CTRL), &req, + sizeof(req), true); +} + int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { @@ -2362,6 +2388,10 @@ int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif, return 0; /* must keep the order */ + ret = mt7915_mcu_add_group(dev, vif, sta); + if (ret) + return ret; + ret = mt7915_mcu_add_txbf(dev, vif, sta, enable); if (ret) return ret; From e3343d0fef6a368cf5b5b34e99e4a4768ee51242 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Wed, 2 Jun 2021 11:04:03 +0800 Subject: [PATCH 064/170] mt76: mt7615: update radar parameters Patch radar parameters to match the SDK to avoid possible false alarms. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 17 ++++++++++------- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 4 ++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 4daa0540e051..f540b6188ba1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -20,7 +20,7 @@ #define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) static const struct mt7615_dfs_radar_spec etsi_radar_specs = { - .pulse_th = { 40, -10, -80, 800, 3360, 128, 5200 }, + .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, .radar_pattern = { [5] = { 1, 0, 6, 32, 28, 0, 17, 990, 5010, 1, 1 }, [6] = { 1, 0, 9, 32, 28, 0, 27, 615, 5010, 1, 1 }, @@ -34,7 +34,7 @@ static const struct mt7615_dfs_radar_spec etsi_radar_specs = { }; static const struct mt7615_dfs_radar_spec fcc_radar_specs = { - .pulse_th = { 40, -10, -80, 800, 3360, 128, 5200 }, + .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, .radar_pattern = { [0] = { 1, 0, 9, 32, 28, 0, 13, 508, 3076, 1, 1 }, [1] = { 1, 0, 12, 32, 28, 0, 17, 140, 240, 1, 1 }, @@ -45,7 +45,7 @@ static const struct mt7615_dfs_radar_spec fcc_radar_specs = { }; static const struct mt7615_dfs_radar_spec jp_radar_specs = { - .pulse_th = { 40, -10, -80, 800, 3360, 128, 5200 }, + .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, .radar_pattern = { [0] = { 1, 0, 8, 32, 28, 0, 13, 508, 3076, 1, 1 }, [1] = { 1, 0, 12, 32, 28, 0, 17, 140, 240, 1, 1 }, @@ -2047,14 +2047,12 @@ mt7615_dfs_init_radar_specs(struct mt7615_phy *phy) { const struct mt7615_dfs_radar_spec *radar_specs; struct mt7615_dev *dev = phy->dev; - int err, i; + int err, i, lpn = 500; switch (dev->mt76.region) { case NL80211_DFS_FCC: radar_specs = &fcc_radar_specs; - err = mt7615_mcu_set_fcc5_lpn(dev, 8); - if (err < 0) - return err; + lpn = 8; break; case NL80211_DFS_ETSI: radar_specs = &etsi_radar_specs; @@ -2066,6 +2064,11 @@ mt7615_dfs_init_radar_specs(struct mt7615_phy *phy) return -EINVAL; } + /* avoid FCC radar detection in non-FCC region */ + err = mt7615_mcu_set_fcc5_lpn(dev, lpn); + if (err < 0) + return err; + for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) { err = mt7615_mcu_set_radar_th(dev, i, &radar_specs->radar_pattern[i]); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index fc9cd8da2a11..cf4a4f2637d5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -430,6 +430,10 @@ mt7615_mcu_rx_radar_detected(struct mt7615_dev *dev, struct sk_buff *skb) r = (struct mt7615_mcu_rdd_report *)skb->data; + if (!dev->radar_pattern.n_pulses && !r->long_detected && + !r->constant_prf_detected && !r->staggered_prf_detected) + return; + if (r->band_idx && dev->mt76.phy2) mphy = dev->mt76.phy2; From ee8ba94f9cc9afab570fd71ad421292f6360983c Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Mon, 17 May 2021 12:45:58 +0800 Subject: [PATCH 065/170] mt76: mt7915: fix MT_EE_CAL_GROUP_SIZE Fix wrong offset for pre-calibration data. Fixes: 495184ac91bb ("mt76: mt7915: add support for applying pre-calibration data") Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h index 7896e983209a..a43389a41800 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h @@ -33,7 +33,7 @@ enum mt7915_eeprom_field { #define MT_EE_WIFI_CAL_GROUP BIT(0) #define MT_EE_WIFI_CAL_DPD GENMASK(2, 1) #define MT_EE_CAL_UNIT 1024 -#define MT_EE_CAL_GROUP_SIZE (44 * MT_EE_CAL_UNIT) +#define MT_EE_CAL_GROUP_SIZE (49 * MT_EE_CAL_UNIT + 16) #define MT_EE_CAL_DPD_SIZE (54 * MT_EE_CAL_UNIT) #define MT_EE_WIFI_CONF0_TX_PATH GENMASK(2, 0) From 435d68f9cffda3ea3c6f65897ddac4357bcb8fd8 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 6 Jun 2021 09:45:54 +0200 Subject: [PATCH 066/170] mt76: mt7921: enable VHT BFee capability Enables VHT beamformee functionality Signed-off-by: Leon Yen Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 06fca78fe149..2d682e59ab52 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -215,7 +215,11 @@ int mt7921_register_device(struct mt7921_dev *dev) IEEE80211_HT_CAP_MAX_AMSDU; dev->mphy.sband_5g.sband.vht_cap.cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 | - IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | + IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | + IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | + (3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT); + dev->mphy.hw->wiphy->available_antennas_rx = dev->mphy.chainmask; dev->mphy.hw->wiphy->available_antennas_tx = dev->mphy.chainmask; From 82453b1cbf9ef166364c12b5464251f16bac5f51 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 2 Jun 2021 18:00:14 +0200 Subject: [PATCH 067/170] mt76: connac: fix UC entry is being overwritten Fix UC entry is being overwritten by BC entry Tested-by: Deren Wu Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 8 +++++--- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 10 ++++++---- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 1 + 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index cf4a4f2637d5..ea1f23e99ca1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1148,12 +1148,14 @@ mt7615_mcu_sta_rx_ba(struct mt7615_dev *dev, static int __mt7615_mcu_add_sta(struct mt76_phy *phy, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enable, int cmd) + struct ieee80211_sta *sta, bool enable, int cmd, + bool offload_fw) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt76_sta_cmd_info info = { .sta = sta, .vif = vif, + .offload_fw = offload_fw, .enable = enable, .cmd = cmd, }; @@ -1167,7 +1169,7 @@ mt7615_mcu_add_sta(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { return __mt7615_mcu_add_sta(phy->mt76, vif, sta, enable, - MCU_EXT_CMD_STA_REC_UPDATE); + MCU_EXT_CMD_STA_REC_UPDATE, false); } static int @@ -1302,7 +1304,7 @@ mt7615_mcu_uni_add_sta(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { return __mt7615_mcu_add_sta(phy->mt76, vif, sta, enable, - MCU_UNI_CMD_STA_REC_UPDATE); + MCU_UNI_CMD_STA_REC_UPDATE, true); } static int diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index a5312d225d93..4b22625a1d4d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -879,10 +879,12 @@ int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy, if (IS_ERR(skb)) return PTR_ERR(skb); - mt76_connac_mcu_sta_basic_tlv(skb, info->vif, info->sta, info->enable); - if (info->enable && info->sta) - mt76_connac_mcu_sta_tlv(phy, skb, info->sta, info->vif, - info->rcpi); + if (info->sta || !info->offload_fw) + mt76_connac_mcu_sta_basic_tlv(skb, info->vif, info->sta, + info->enable); + if (info->sta && info->enable) + mt76_connac_mcu_sta_tlv(phy, skb, info->sta, + info->vif, info->rcpi); sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index b574d444ddca..f12c304958c0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -910,6 +910,7 @@ struct mt76_sta_cmd_info { struct ieee80211_vif *vif; + bool offload_fw; bool enable; int cmd; u8 rcpi; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index ffc83717fd0d..bd94d1244975 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -1277,6 +1277,7 @@ int mt7921_mcu_sta_add(struct mt7921_dev *dev, struct ieee80211_sta *sta, .vif = vif, .enable = enable, .cmd = MCU_UNI_CMD_STA_REC_UPDATE, + .offload_fw = true, .rcpi = to_rcpi(rssi), }; struct mt7921_sta *msta; From 6ab079e2aba283e3e356cc60dd3d0648adc15b1d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 2 Jun 2021 23:25:28 +0200 Subject: [PATCH 068/170] mt76: connac: add mt76_connac_power_save_sched in mt76_connac_pm_unref Schedule power_save work running mt76_connac_pm_unref in order to reduce power consumption Tested-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/dma.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76_connac.h | 8 ++++++-- drivers/net/wireless/mediatek/mt76/mt7921/dma.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 4 ++-- 6 files changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c index 8004ae5c16a9..b6184234cad2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c @@ -81,7 +81,7 @@ static int mt7615_poll_tx(struct napi_struct *napi, int budget) if (napi_complete(napi)) mt7615_irq_enable(dev, mt7615_tx_mcu_int_mask(dev)); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(&dev->mphy, &dev->pm); return 0; } @@ -99,7 +99,7 @@ static int mt7615_poll_rx(struct napi_struct *napi, int budget) return 0; } done = mt76_dma_rx_poll(napi, budget); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(&dev->mphy, &dev->pm); return done; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 7c9a55c57578..bd2f42ef5ad7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -693,7 +693,7 @@ static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw, msta->n_rates = i; if (mt76_connac_pm_ref(phy->mt76, &dev->pm)) { mt7615_mac_set_rates(phy, msta, NULL, msta->rates); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(phy->mt76, &dev->pm); } spin_unlock_bh(&dev->mt76.lock); } @@ -709,7 +709,7 @@ void mt7615_tx_worker(struct mt76_worker *w) } mt76_tx_worker_run(&dev->mt76); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(&dev->mphy, &dev->pm); } static void mt7615_tx(struct ieee80211_hw *hw, @@ -739,7 +739,7 @@ static void mt7615_tx(struct ieee80211_hw *hw, if (mt76_connac_pm_ref(mphy, &dev->pm)) { mt76_tx(mphy, control->sta, wcid, skb); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(mphy, &dev->pm); return; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c index 261cff78de40..a2465b49ecd0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c @@ -98,7 +98,7 @@ mt7615_led_set_config(struct led_classdev *led_cdev, addr = mt7615_reg_map(dev, MT_LED_CTRL); mt76_wr(dev, addr, val); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(&dev->mphy, &dev->pm); } static int diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 63c1d1a68a70..0dfa09902ffd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -117,11 +117,15 @@ out: } static inline void -mt76_connac_pm_unref(struct mt76_connac_pm *pm) +mt76_connac_pm_unref(struct mt76_phy *phy, struct mt76_connac_pm *pm) { spin_lock_bh(&pm->wake.lock); - pm->wake.count--; + pm->last_activity = jiffies; + if (--pm->wake.count == 0 && + test_bit(MT76_STATE_MCU_RUNNING, &phy->state)) + mt76_connac_power_save_sched(phy, pm); + spin_unlock_bh(&pm->wake.lock); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c index 7fca7dc466b8..5e745e9c2185 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c @@ -74,7 +74,7 @@ static int mt7921_poll_tx(struct napi_struct *napi, int budget) mt7921_tx_cleanup(dev); if (napi_complete(napi)) mt7921_irq_enable(dev, MT_INT_TX_DONE_ALL); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(&dev->mphy, &dev->pm); return 0; } @@ -92,7 +92,7 @@ static int mt7921_poll_rx(struct napi_struct *napi, int budget) return 0; } done = mt76_dma_rx_poll(napi, budget); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(&dev->mphy, &dev->pm); return done; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index a6cf4a0e286a..0cd519f6dc00 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -679,7 +679,7 @@ void mt7921_tx_worker(struct mt76_worker *w) } mt76_txq_schedule_all(&dev->mphy); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(&dev->mphy, &dev->pm); } static void mt7921_tx(struct ieee80211_hw *hw, @@ -709,7 +709,7 @@ static void mt7921_tx(struct ieee80211_hw *hw, if (mt76_connac_pm_ref(mphy, &dev->pm)) { mt76_tx(mphy, control->sta, wcid, skb); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(mphy, &dev->pm); return; } From 271fa685365842962f56651c9d1a33a0d0d3b30b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 5 Jun 2021 13:46:03 +0200 Subject: [PATCH 069/170] mt76: mt7921: wake the device before dumping power table Always wake the device up before dumping the single_sku power table otherwise the device can hang. Fixes: ea29acc97c555 ("mt76: mt7921: add dumping Tx power table") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c index 6ee423dd4027..6602903c0d02 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c @@ -184,7 +184,10 @@ mt7921_txpwr(struct seq_file *s, void *data) struct mt7921_txpwr txpwr; int ret; + mt7921_mutex_acquire(dev); ret = mt7921_get_txpwr_info(dev, &txpwr); + mt7921_mutex_release(dev); + if (ret) return ret; From 5bc52dee44f667507f6d54c70cd22bd2fa52e26b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 5 Jun 2021 15:12:48 +0200 Subject: [PATCH 070/170] mt76: mt7921: make mt7921_set_channel static Make mt7921_set_channel routine static since it is only used in main.c Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 0cd519f6dc00..5fc6cf7e5455 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -316,7 +316,7 @@ static void mt7921_remove_interface(struct ieee80211_hw *hw, spin_unlock_bh(&dev->sta_poll_lock); } -int mt7921_set_channel(struct mt7921_phy *phy) +static int mt7921_set_channel(struct mt7921_phy *phy) { struct mt7921_dev *dev = phy->dev; int ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 8aa8d2ecdffa..087067e7ea5b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -261,7 +261,6 @@ int mt7921_mcu_init(struct mt7921_dev *dev); int mt7921_mcu_add_key(struct mt7921_dev *dev, struct ieee80211_vif *vif, struct mt7921_sta *msta, struct ieee80211_key_conf *key, enum set_key_cmd cmd); -int mt7921_set_channel(struct mt7921_phy *phy); int mt7921_mcu_sta_add(struct mt7921_dev *dev, struct ieee80211_sta *sta, struct ieee80211_vif *vif, bool enable); int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd); From f7d2958ca4614a53b155b9ac37c400b216357394 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 6 Jun 2021 15:18:12 +0200 Subject: [PATCH 071/170] mt76: connac: add mt76_connac_mcu_get_nic_capability utility routine Introduce mt76_connac_mcu_get_nic_capability utility routine to poll device capabilities returned by mcu fw for CE devices (mt7663/mt7921). This is a preliminary patch to introduce 6GHz support. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + .../wireless/mediatek/mt76/mt76_connac_mcu.c | 54 +++++++++++++++++++ .../wireless/mediatek/mt76/mt76_connac_mcu.h | 24 +++++++++ .../net/wireless/mediatek/mt76/mt7921/mcu.c | 2 +- 4 files changed, 80 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index ebacd55cb0cd..338219024ba7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -320,6 +320,7 @@ enum { struct mt76_hw_cap { bool has_2ghz; bool has_5ghz; + bool has_6ghz; }; #define MT_DRV_TXWI_NO_FREE BIT(0) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 4b22625a1d4d..d7d7cede955b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1630,6 +1630,60 @@ void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb, } EXPORT_SYMBOL_GPL(mt76_connac_mcu_coredump_event); +int mt76_connac_mcu_get_nic_capability(struct mt76_phy *phy) +{ + struct mt76_connac_cap_hdr { + __le16 n_element; + u8 rsv[2]; + } __packed * hdr; + struct sk_buff *skb; + int ret, i; + + ret = mt76_mcu_send_and_get_msg(phy->dev, MCU_CMD_GET_NIC_CAPAB, NULL, + 0, true, &skb); + if (ret) + return ret; + + hdr = (struct mt76_connac_cap_hdr *)skb->data; + if (skb->len < sizeof(*hdr)) { + ret = -EINVAL; + goto out; + } + + skb_pull(skb, sizeof(*hdr)); + + for (i = 0; i < le16_to_cpu(hdr->n_element); i++) { + struct tlv_hdr { + __le32 type; + __le32 len; + } __packed * tlv = (struct tlv_hdr *)skb->data; + int len; + + if (skb->len < sizeof(*tlv)) + break; + + skb_pull(skb, sizeof(*tlv)); + + len = le32_to_cpu(tlv->len); + if (skb->len < len) + break; + + switch (le32_to_cpu(tlv->type)) { + case MT_NIC_CAP_6G: + phy->cap.has_6ghz = skb->data[0]; + break; + default: + break; + } + skb_pull(skb, len); + } +out: + dev_kfree_skb(skb); + + return ret; +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_get_nic_capability); + static void mt76_connac_mcu_build_sku(struct mt76_dev *dev, s8 *sku, struct mt76_power_limits *limits, diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index f12c304958c0..549e2ab95563 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -559,6 +559,7 @@ enum { MCU_CMD_SET_RATE_TX_POWER = MCU_CE_PREFIX | 0x5d, MCU_CMD_SCHED_SCAN_ENABLE = MCU_CE_PREFIX | 0x61, MCU_CMD_SCHED_SCAN_REQ = MCU_CE_PREFIX | 0x62, + MCU_CMD_GET_NIC_CAPAB = MCU_CE_PREFIX | 0x8a, MCU_CMD_REG_WRITE = MCU_CE_PREFIX | 0xc0, MCU_CMD_REG_READ = MCU_CE_PREFIX | MCU_QUERY_MASK | 0xc0, MCU_CMD_CHIP_CONFIG = MCU_CE_PREFIX | 0xca, @@ -591,6 +592,28 @@ enum { UNI_OFFLOAD_OFFLOAD_BMC_RPY_DETECT, }; +enum { + MT_NIC_CAP_TX_RESOURCE, + MT_NIC_CAP_TX_EFUSE_ADDR, + MT_NIC_CAP_COEX, + MT_NIC_CAP_SINGLE_SKU, + MT_NIC_CAP_CSUM_OFFLOAD, + MT_NIC_CAP_HW_VER, + MT_NIC_CAP_SW_VER, + MT_NIC_CAP_MAC_ADDR, + MT_NIC_CAP_PHY, + MT_NIC_CAP_MAC, + MT_NIC_CAP_FRAME_BUF, + MT_NIC_CAP_BEAM_FORM, + MT_NIC_CAP_LOCATION, + MT_NIC_CAP_MUMIMO, + MT_NIC_CAP_BUFFER_MODE_INFO, + MT_NIC_CAP_HW_ADIE_VERSION = 0x14, + MT_NIC_CAP_ANTSWP = 0x16, + MT_NIC_CAP_WFDMA_REALLOC, + MT_NIC_CAP_6G, +}; + #define UNI_WOW_DETECT_TYPE_MAGIC BIT(0) #define UNI_WOW_DETECT_TYPE_ANY BIT(1) #define UNI_WOW_DETECT_TYPE_DISCONNECT BIT(2) @@ -1032,6 +1055,7 @@ int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len, int mt76_connac_mcu_start_patch(struct mt76_dev *dev); int mt76_connac_mcu_patch_sem_ctrl(struct mt76_dev *dev, bool get); int mt76_connac_mcu_start_firmware(struct mt76_dev *dev, u32 addr, u32 option); +int mt76_connac_mcu_get_nic_capability(struct mt76_phy *phy); int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, struct ieee80211_scan_request *scan_req); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index bd94d1244975..ca481e37d22c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -988,7 +988,7 @@ int mt7921_run_firmware(struct mt7921_dev *dev) set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); mt7921_mcu_fw_log_2_host(dev, 1); - return 0; + return mt76_connac_mcu_get_nic_capability(&dev->mphy); } int mt7921_mcu_init(struct mt7921_dev *dev) From a0d65f627ba0fc7d93fddda3c11d3543dbe1c425 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Tue, 8 Jun 2021 14:55:57 +0800 Subject: [PATCH 072/170] mt76: testmode: move chip-specific stats dump before common stats Move chip-specific stats dumping part before common stats dumping to provide flexibility for per-chip driver to modify the value of common stats. Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/testmode.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/testmode.c b/drivers/net/wireless/mediatek/mt76/testmode.c index c6a85a0cfc89..f73ffbd6e622 100644 --- a/drivers/net/wireless/mediatek/mt76/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/testmode.c @@ -521,6 +521,14 @@ mt76_testmode_dump_stats(struct mt76_phy *phy, struct sk_buff *msg) u64 rx_fcs_error = 0; int i; + if (dev->test_ops->dump_stats) { + int ret; + + ret = dev->test_ops->dump_stats(phy, msg); + if (ret) + return ret; + } + for (i = 0; i < ARRAY_SIZE(td->rx_stats.packets); i++) { rx_packets += td->rx_stats.packets[i]; rx_fcs_error += td->rx_stats.fcs_error[i]; @@ -535,9 +543,6 @@ mt76_testmode_dump_stats(struct mt76_phy *phy, struct sk_buff *msg) MT76_TM_STATS_ATTR_PAD)) return -EMSGSIZE; - if (dev->test_ops->dump_stats) - return dev->test_ops->dump_stats(phy, msg); - return 0; } From 89043529c8b833d87391f1844e9d1cc1643393eb Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Tue, 8 Jun 2021 14:55:58 +0800 Subject: [PATCH 073/170] mt76: mt7915: fix rx fcs error count in testmode FCS error packets are filtered by default and won't be reported to driver, so that RX fcs error and PER in testmode always show zero. Fix this issue by reading fcs error count from hw counter. We did't fix this issue by disabling fcs error rx filter since it may let HW suffer some SER errors. Fixes: 5d8a83f09941 ("mt76: mt7915: implement testmode rx support") Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7915/testmode.c | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c index f9d81e36ef09..b220b334906b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c @@ -464,10 +464,17 @@ mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en) static void mt7915_tm_set_rx_frames(struct mt7915_phy *phy, bool en) { - if (en) + mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, false); + + if (en) { + struct mt7915_dev *dev = phy->dev; + mt7915_tm_update_channel(phy); - mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, en); + /* read-clear */ + mt76_rr(dev, MT_MIB_SDR3(phy != &dev->phy)); + mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, en); + } } static int @@ -690,7 +697,11 @@ static int mt7915_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg) { struct mt7915_phy *phy = mphy->priv; + struct mt7915_dev *dev = phy->dev; + bool ext_phy = phy != &dev->phy; + enum mt76_rxq_id q; void *rx, *rssi; + u16 fcs_err; int i; rx = nla_nest_start(msg, MT76_TM_STATS_ATTR_LAST_RX); @@ -735,6 +746,12 @@ mt7915_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg) nla_nest_end(msg, rx); + fcs_err = mt76_get_field(dev, MT_MIB_SDR3(ext_phy), + MT_MIB_SDR3_FCS_ERR_MASK); + q = ext_phy ? MT_RXQ_EXT : MT_RXQ_MAIN; + mphy->test.rx_stats.packets[q] += fcs_err; + mphy->test.rx_stats.fcs_error[q] += fcs_err; + return 0; } From abded041a07467c2f3dfe10afd9ea10572c63cc9 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 9 Jun 2021 14:15:32 +0800 Subject: [PATCH 074/170] mt76: connac: fix the maximum interval schedule scan can support Maximum interval (in seconds) for schedule scan plan supported by the offload firmware can be U16_MAX. Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76_connac.h | 3 ++- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 4aa7877a6383..2f1ac644e018 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -383,7 +383,7 @@ mt7615_init_wiphy(struct ieee80211_hw *hw) wiphy->reg_notifier = mt7615_regd_notifier; wiphy->max_sched_scan_plan_interval = - MT76_CONNAC_MAX_SCHED_SCAN_INTERVAL; + MT76_CONNAC_MAX_TIME_SCHED_SCAN_INTERVAL; wiphy->max_sched_scan_ie_len = IEEE80211_MAX_DATA_LEN; wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN; wiphy->max_sched_scan_ssids = MT76_CONNAC_MAX_SCHED_SCAN_SSID; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 0dfa09902ffd..9b3f8d22f17e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -7,7 +7,8 @@ #include "mt76.h" #define MT76_CONNAC_SCAN_IE_LEN 600 -#define MT76_CONNAC_MAX_SCHED_SCAN_INTERVAL 10 +#define MT76_CONNAC_MAX_NUM_SCHED_SCAN_INTERVAL 10 +#define MT76_CONNAC_MAX_TIME_SCHED_SCAN_INTERVAL U16_MAX #define MT76_CONNAC_MAX_SCHED_SCAN_SSID 10 #define MT76_CONNAC_MAX_SCAN_MATCH 16 diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 549e2ab95563..9f3c87902db8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -794,7 +794,7 @@ struct mt76_connac_sched_scan_req { u8 intervals_num; u8 scan_func; /* MT7663: BIT(0) eable random mac address */ struct mt76_connac_mcu_scan_channel channels[64]; - __le16 intervals[MT76_CONNAC_MAX_SCHED_SCAN_INTERVAL]; + __le16 intervals[MT76_CONNAC_MAX_NUM_SCHED_SCAN_INTERVAL]; union { struct { u8 random_mac[ETH_ALEN]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 2d682e59ab52..b399f3b8b5d7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -68,7 +68,7 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN; wiphy->max_scan_ssids = 4; wiphy->max_sched_scan_plan_interval = - MT76_CONNAC_MAX_SCHED_SCAN_INTERVAL; + MT76_CONNAC_MAX_TIME_SCHED_SCAN_INTERVAL; wiphy->max_sched_scan_ie_len = IEEE80211_MAX_DATA_LEN; wiphy->max_sched_scan_ssids = MT76_CONNAC_MAX_SCHED_SCAN_SSID; wiphy->max_match_sets = MT76_CONNAC_MAX_SCAN_MATCH; From 49c9a263d76a0cf2bb0e36f193036b45545d4eee Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 9 Jun 2021 17:13:58 +0200 Subject: [PATCH 075/170] mt76: reduce rx buffer size to 2048 Reduce rx buffer size to 2048 for mt7921/mt7915/mt7615 since we now support rx amsdu offload Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/dma.c | 9 ++------- drivers/net/wireless/mediatek/mt76/mt7915/dma.c | 12 +++++------- drivers/net/wireless/mediatek/mt76/mt7921/dma.c | 8 +++----- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c index b6184234cad2..00aefea1bf61 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c @@ -222,14 +222,9 @@ void mt7615_dma_start(struct mt7615_dev *dev) int mt7615_dma_init(struct mt7615_dev *dev) { int rx_ring_size = MT7615_RX_RING_SIZE; - int rx_buf_size = MT_RX_BUF_SIZE; u32 mask; int ret; - /* Increase buffer size to receive large VHT MPDUs */ - if (dev->mphy.cap.has_5ghz) - rx_buf_size *= 2; - mt76_dma_attach(&dev->mt76); mt76_wr(dev, MT_WPDMA_GLO_CFG, @@ -270,7 +265,7 @@ int mt7615_dma_init(struct mt7615_dev *dev) /* init rx queues */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1, - MT7615_RX_MCU_RING_SIZE, rx_buf_size, + MT7615_RX_MCU_RING_SIZE, MT_RX_BUF_SIZE, MT_RX_RING_BASE); if (ret) return ret; @@ -279,7 +274,7 @@ int mt7615_dma_init(struct mt7615_dev *dev) rx_ring_size /= 2; ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], 0, - rx_ring_size, rx_buf_size, MT_RX_RING_BASE); + rx_ring_size, MT_RX_BUF_SIZE, MT_RX_RING_BASE); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c index 69a7e3dce113..9182568f95c7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -79,8 +79,6 @@ void mt7915_dma_prefetch(struct mt7915_dev *dev) int mt7915_dma_init(struct mt7915_dev *dev) { - /* Increase buffer size to receive large VHT/HE MPDUs */ - int rx_buf_size = MT_RX_BUF_SIZE * 2; u32 hif1_ofs = 0; int ret; @@ -144,28 +142,28 @@ int mt7915_dma_init(struct mt7915_dev *dev) /* event from WM */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], MT7915_RXQ_MCU_WM, MT7915_RX_MCU_RING_SIZE, - rx_buf_size, MT_RX_EVENT_RING_BASE); + MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE); if (ret) return ret; /* event from WA */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], MT7915_RXQ_MCU_WA, MT7915_RX_MCU_RING_SIZE, - rx_buf_size, MT_RX_EVENT_RING_BASE); + MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE); if (ret) return ret; /* rx data queue */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], MT7915_RXQ_BAND0, MT7915_RX_RING_SIZE, - rx_buf_size, MT_RX_DATA_RING_BASE); + MT_RX_BUF_SIZE, MT_RX_DATA_RING_BASE); if (ret) return ret; if (dev->dbdc_support) { ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_EXT], MT7915_RXQ_BAND1, MT7915_RX_RING_SIZE, - rx_buf_size, + MT_RX_BUF_SIZE, MT_RX_DATA_RING_BASE + hif1_ofs); if (ret) return ret; @@ -174,7 +172,7 @@ int mt7915_dma_init(struct mt7915_dev *dev) ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_EXT_WA], MT7915_RXQ_MCU_WA_EXT, MT7915_RX_MCU_RING_SIZE, - rx_buf_size, + MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE + hif1_ofs); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c index 5e745e9c2185..7d7d43a5422f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c @@ -380,9 +380,7 @@ int mt7921_wpdma_reinit_cond(struct mt7921_dev *dev) int mt7921_dma_init(struct mt7921_dev *dev) { - /* Increase buffer size to receive large VHT/HE MPDUs */ struct mt76_bus_ops *bus_ops; - int rx_buf_size = MT_RX_BUF_SIZE * 2; int ret; dev->bus_ops = dev->mt76.bus; @@ -430,7 +428,7 @@ int mt7921_dma_init(struct mt7921_dev *dev) ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], MT7921_RXQ_MCU_WM, MT7921_RX_MCU_RING_SIZE, - rx_buf_size, MT_RX_EVENT_RING_BASE); + MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE); if (ret) return ret; @@ -438,14 +436,14 @@ int mt7921_dma_init(struct mt7921_dev *dev) ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], MT7921_RXQ_MCU_WM, MT7921_RX_MCU_RING_SIZE, - rx_buf_size, MT_WFDMA0(0x540)); + MT_RX_BUF_SIZE, MT_WFDMA0(0x540)); if (ret) return ret; /* rx data */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], MT7921_RXQ_BAND0, MT7921_RX_RING_SIZE, - rx_buf_size, MT_RX_DATA_RING_BASE); + MT_RX_BUF_SIZE, MT_RX_DATA_RING_BASE); if (ret) return ret; From 90052b844d7a6db8649239434b262d28b1430cf4 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 10 Jun 2021 09:44:12 +0200 Subject: [PATCH 076/170] mt76: move mt76_get_next_pkt_id in mt76.h In order to remove duplicated code, move mt76_get_next_pkt_id routine in mt76.h Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 11 +++++++++++ drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 15 +++------------ drivers/net/wireless/mediatek/mt76/tx.c | 7 +------ 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 338219024ba7..a50ba8e9344e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1276,4 +1276,15 @@ mt76_token_put(struct mt76_dev *dev, int token) return txwi; } + +static inline int +mt76_get_next_pkt_id(struct mt76_wcid *wcid) +{ + wcid->packet_id = (wcid->packet_id + 1) & MT_PACKET_ID_MASK; + if (wcid->packet_id == MT_PACKET_ID_NO_ACK || + wcid->packet_id == MT_PACKET_ID_NO_SKB) + wcid->packet_id = MT_PACKET_ID_FIRST; + + return wcid->packet_id; +} #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index ed886f8633b1..8e2252c1acd4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -13,16 +13,6 @@ #define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\ IEEE80211_RADIOTAP_HE_##f) -static u8 -mt7921_next_pid(struct mt7921_dev *dev, struct mt76_wcid *wcid) -{ - wcid->packet_id = (wcid->packet_id + 1) & MT_PACKET_ID_MASK; - if (wcid->packet_id == MT_PACKET_ID_NO_ACK || - wcid->packet_id == MT_PACKET_ID_NO_SKB) - wcid->packet_id = MT_PACKET_ID_FIRST; - return wcid->packet_id; -} - static unsigned long mt7921_next_txs_set(struct mt7921_dev *dev, struct mt76_wcid *wcid, u32 timeout) @@ -756,7 +746,7 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; struct mt76_phy *mphy = &dev->mphy; - u8 pid, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; + u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; u16 tx_count = 15; u32 val; @@ -829,8 +819,9 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, if ((FIELD_GET(MT_TXD2_FRAME_TYPE, txwi[2]) & (IEEE80211_FTYPE_DATA >> 2)) && mt7921_next_txs_timeout(dev, wcid)) { + u8 pid = mt76_get_next_pkt_id(wcid); + mt7921_next_txs_set(dev, wcid, 250); - pid = mt7921_next_pid(dev, wcid); val = MT_TXD5_TX_STATUS_MCU | FIELD_PREP(MT_TXD5_PID, pid); txwi[5] |= cpu_to_le32(val); } diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 5cc3e4d75c4f..f0f7a913eaab 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -129,12 +129,7 @@ mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid, spin_lock_bh(&dev->status_list.lock); memset(cb, 0, sizeof(*cb)); - wcid->packet_id = (wcid->packet_id + 1) & MT_PACKET_ID_MASK; - if (wcid->packet_id == MT_PACKET_ID_NO_ACK || - wcid->packet_id == MT_PACKET_ID_NO_SKB) - wcid->packet_id = MT_PACKET_ID_FIRST; - - pid = wcid->packet_id; + pid = mt76_get_next_pkt_id(wcid); cb->wcid = wcid->idx; cb->pktid = pid; cb->jiffies = jiffies; From 1f9dde02aab74a32e896ef10e15d72c39e54bb14 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 5 Jun 2021 13:50:52 +0200 Subject: [PATCH 077/170] mt76: connac: check band caps in mt76_connac_mcu_set_rate_txpower Check device band capabilities before configuring single-sku Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index d7d7cede955b..78498d86efc3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1809,11 +1809,20 @@ int mt76_connac_mcu_set_rate_txpower(struct mt76_phy *phy) { int err; - err = mt76_connac_mcu_rate_txpower_band(phy, NL80211_BAND_2GHZ); - if (err < 0) - return err; + if (phy->cap.has_2ghz) { + err = mt76_connac_mcu_rate_txpower_band(phy, + NL80211_BAND_2GHZ); + if (err < 0) + return err; + } + if (phy->cap.has_5ghz) { + err = mt76_connac_mcu_rate_txpower_band(phy, + NL80211_BAND_5GHZ); + if (err < 0) + return err; + } - return mt76_connac_mcu_rate_txpower_band(phy, NL80211_BAND_5GHZ); + return 0; } EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_rate_txpower); From 0d733327c531814c0fb9ef4eea86ca0d6eddfe9e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 25 May 2021 18:45:04 +0200 Subject: [PATCH 078/170] mt76: mt7915: drop the use of repeater entries for station interfaces There are firmware or hardware issues, which are currently causing tx hangs when attempting to use these interfaces Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 6 ------ drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 2485f65766e7..c25f8da590dd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -139,12 +139,6 @@ static int get_omac_idx(enum nl80211_iftype type, u64 mask) if (type != NL80211_IFTYPE_STATION) break; - /* next, try to find a free repeater entry for the sta */ - i = get_free_idx(mask >> REPEATER_BSSID_START, 0, - REPEATER_BSSID_MAX - REPEATER_BSSID_START); - if (i) - return i + 32 - 1; - i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); if (i) return i - 1; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index a4b32e0d64e9..b0cdd53098ef 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -9,7 +9,7 @@ #include "../mt76.h" #include "regs.h" -#define MT7915_MAX_INTERFACES 32 +#define MT7915_MAX_INTERFACES 19 #define MT7915_MAX_WMM_SETS 4 #define MT7915_WTBL_SIZE 288 #define MT7915_WTBL_RESERVED (MT7915_WTBL_SIZE - 1) From c560b137a2164c7160f4edc1813f3e335de6bdff Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Fri, 11 Jun 2021 02:43:45 +0800 Subject: [PATCH 079/170] mt76: make mt76_update_survey() per phy Reduce duplicated survey for DBDC. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 15 +++--- drivers/net/wireless/mediatek/mt76/mt76.h | 4 +- .../net/wireless/mediatek/mt76/mt7603/mac.c | 8 ++-- .../wireless/mediatek/mt76/mt7603/mt7603.h | 2 +- .../net/wireless/mediatek/mt76/mt7615/mac.c | 48 +++++++++---------- .../wireless/mediatek/mt76/mt7615/mt7615.h | 2 +- .../net/wireless/mediatek/mt76/mt76x02_mac.c | 8 ++-- .../net/wireless/mediatek/mt76/mt76x02_mac.h | 2 +- .../net/wireless/mediatek/mt76/mt7915/mac.c | 15 ++---- .../wireless/mediatek/mt76/mt7915/mt7915.h | 2 +- .../net/wireless/mediatek/mt76/mt7921/mac.c | 12 ++--- .../wireless/mediatek/mt76/mt7921/mt7921.h | 2 +- 12 files changed, 55 insertions(+), 65 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 49da219d4e52..d03aedc3286b 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -659,20 +659,19 @@ void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time) } EXPORT_SYMBOL_GPL(mt76_update_survey_active_time); -void mt76_update_survey(struct mt76_dev *dev) +void mt76_update_survey(struct mt76_phy *phy) { + struct mt76_dev *dev = phy->dev; ktime_t cur_time; if (dev->drv->update_survey) - dev->drv->update_survey(dev); + dev->drv->update_survey(phy); cur_time = ktime_get_boottime(); - mt76_update_survey_active_time(&dev->phy, cur_time); - if (dev->phy2) - mt76_update_survey_active_time(dev->phy2, cur_time); + mt76_update_survey_active_time(phy, cur_time); if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { - struct mt76_channel_state *state = dev->phy.chan_state; + struct mt76_channel_state *state = phy->chan_state; spin_lock_bh(&dev->cc_lock); state->cc_bss_rx += dev->cur_cc_bss_rx; @@ -691,7 +690,7 @@ void mt76_set_channel(struct mt76_phy *phy) int timeout = HZ / 5; wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout); - mt76_update_survey(dev); + mt76_update_survey(phy); phy->chandef = *chandef; phy->chan_state = mt76_channel_state(phy, chandef->chan); @@ -716,7 +715,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, mutex_lock(&dev->mutex); if (idx == 0 && dev->drv->update_survey) - mt76_update_survey(dev); + mt76_update_survey(phy); sband = &phy->sband_2g; if (idx >= sband->sband.n_channels) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index a50ba8e9344e..022e9c573ddd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -337,7 +337,7 @@ struct mt76_driver_ops { u16 token_size; u8 mcs_rates; - void (*update_survey)(struct mt76_dev *dev); + void (*update_survey)(struct mt76_phy *phy); int (*tx_prepare_skb)(struct mt76_dev *dev, void *txwi_ptr, enum mt76_txq_id qid, struct mt76_wcid *wcid, @@ -1047,7 +1047,7 @@ void mt76_release_buffered_frames(struct ieee80211_hw *hw, bool more_data); bool mt76_has_tx_pending(struct mt76_phy *phy); void mt76_set_channel(struct mt76_phy *phy); -void mt76_update_survey(struct mt76_dev *dev); +void mt76_update_survey(struct mt76_phy *phy); void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time); int mt76_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index 4e76f9868b9b..8435e9597688 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -1584,12 +1584,12 @@ trigger: return true; } -void mt7603_update_channel(struct mt76_dev *mdev) +void mt7603_update_channel(struct mt76_phy *mphy) { - struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); + struct mt7603_dev *dev = container_of(mphy->dev, struct mt7603_dev, mt76); struct mt76_channel_state *state; - state = mdev->phy.chan_state; + state = mphy->chan_state; state->cc_busy += mt76_rr(dev, MT_MIB_STAT_CCA); } @@ -1806,7 +1806,7 @@ void mt7603_mac_work(struct work_struct *work) mutex_lock(&dev->mt76.mutex); dev->mphy.mac_work_count++; - mt76_update_survey(&dev->mt76); + mt76_update_survey(&dev->mphy); mt7603_edcca_check(dev); for (i = 0, idx = 0; i < 2; i++) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h index 1df5b9fed2bb..0fd46d907638 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h @@ -256,7 +256,7 @@ void mt7603_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, void mt7603_pre_tbtt_tasklet(struct tasklet_struct *t); -void mt7603_update_channel(struct mt76_dev *mdev); +void mt7603_update_channel(struct mt76_phy *mphy); void mt7603_edcca_set_strict(struct mt7603_dev *dev, bool val); void mt7603_cca_stats_reset(struct mt7603_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index f540b6188ba1..a057859aa050 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1819,43 +1819,41 @@ mt7615_phy_update_channel(struct mt76_phy *mphy, int idx) state->noise = -(phy->noise >> 4); } -static void __mt7615_update_channel(struct mt7615_dev *dev) -{ - struct mt76_dev *mdev = &dev->mt76; - - mt7615_phy_update_channel(&mdev->phy, 0); - if (mdev->phy2) - mt7615_phy_update_channel(mdev->phy2, 1); - - /* reset obss airtime */ - mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR); -} - -void mt7615_update_channel(struct mt76_dev *mdev) -{ - struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); - - if (mt76_connac_pm_wake(&dev->mphy, &dev->pm)) - return; - - __mt7615_update_channel(dev); - mt76_connac_power_save_sched(&dev->mphy, &dev->pm); -} -EXPORT_SYMBOL_GPL(mt7615_update_channel); - static void mt7615_update_survey(struct mt7615_dev *dev) { struct mt76_dev *mdev = &dev->mt76; ktime_t cur_time; - __mt7615_update_channel(dev); + /* MT7615 can only update both phys simultaneously + * since some reisters are shared across bands. + */ + + mt7615_phy_update_channel(&mdev->phy, 0); + if (mdev->phy2) + mt7615_phy_update_channel(mdev->phy2, 1); + cur_time = ktime_get_boottime(); mt76_update_survey_active_time(&mdev->phy, cur_time); if (mdev->phy2) mt76_update_survey_active_time(mdev->phy2, cur_time); + + /* reset obss airtime */ + mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR); } +void mt7615_update_channel(struct mt76_phy *mphy) +{ + struct mt7615_dev *dev = container_of(mphy->dev, struct mt7615_dev, mt76); + + if (mt76_connac_pm_wake(&dev->mphy, &dev->pm)) + return; + + mt7615_update_survey(dev); + mt76_connac_power_save_sched(&dev->mphy, &dev->pm); +} +EXPORT_SYMBOL_GPL(mt7615_update_channel); + static void mt7615_mac_update_mib_stats(struct mt7615_phy *phy) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 8f03dddba8cf..8fbaf8356e1a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -471,7 +471,7 @@ int mt7615_set_channel(struct mt7615_phy *phy); void mt7615_init_work(struct mt7615_dev *dev); int mt7615_mcu_restart(struct mt76_dev *dev); -void mt7615_update_channel(struct mt76_dev *mdev); +void mt7615_update_channel(struct mt76_phy *mphy); bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask); void mt7615_mac_reset_counters(struct mt7615_dev *dev); void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 0da37867cb64..7572c793aa51 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -1022,12 +1022,12 @@ void mt76x02_mac_set_tx_protection(struct mt76x02_dev *dev, bool legacy_prot, mt76_wr(dev, MT_TX_PROT_CFG6 + i * 4, vht_prot[i]); } -void mt76x02_update_channel(struct mt76_dev *mdev) +void mt76x02_update_channel(struct mt76_phy *mphy) { - struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); + struct mt76x02_dev *dev = container_of(mphy->dev, struct mt76x02_dev, mt76); struct mt76_channel_state *state; - state = mdev->phy.chan_state; + state = mphy->chan_state; state->cc_busy += mt76_rr(dev, MT_CH_BUSY); spin_lock_bh(&dev->mt76.cc_lock); @@ -1169,7 +1169,7 @@ void mt76x02_mac_work(struct work_struct *work) mutex_lock(&dev->mt76.mutex); - mt76_update_survey(&dev->mt76); + mt76_update_survey(&dev->mphy); for (i = 0, idx = 0; i < 16; i++) { u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 0cfbaca50210..5dc6c834111e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -195,7 +195,7 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, struct ieee80211_sta *sta, int len); void mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq); void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e); -void mt76x02_update_channel(struct mt76_dev *mdev); +void mt76x02_update_channel(struct mt76_phy *mphy); void mt76x02_mac_work(struct work_struct *work); void mt76x02_mac_cc_reset(struct mt76x02_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 741899aaaed8..c093c13bf1f1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1471,16 +1471,16 @@ mt7915_phy_get_nf(struct mt7915_phy *phy, int idx) return sum / n; } -static void -mt7915_phy_update_channel(struct mt76_phy *mphy, int idx) +void mt7915_update_channel(struct mt76_phy *mphy) { struct mt7915_phy *phy = (struct mt7915_phy *)mphy->priv; struct mt76_channel_state *state = mphy->chan_state; + bool ext_phy = phy != &phy->dev->phy; int nf; mt7915_mcu_get_chan_mib_info(phy, false); - nf = mt7915_phy_get_nf(phy, idx); + nf = mt7915_phy_get_nf(phy, ext_phy); if (!phy->noise) phy->noise = nf << 4; else if (nf) @@ -1489,13 +1489,6 @@ mt7915_phy_update_channel(struct mt76_phy *mphy, int idx) state->noise = -(phy->noise >> 4); } -void mt7915_update_channel(struct mt76_dev *mdev) -{ - mt7915_phy_update_channel(&mdev->phy, 0); - if (mdev->phy2) - mt7915_phy_update_channel(mdev->phy2, 1); -} - static bool mt7915_wait_reset_state(struct mt7915_dev *dev, u32 state) { @@ -1804,7 +1797,7 @@ void mt7915_mac_work(struct work_struct *work) mutex_lock(&mphy->dev->mutex); - mt76_update_survey(mphy->dev); + mt76_update_survey(mphy); if (++mphy->mac_work_count == 5) { mphy->mac_work_count = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index b0cdd53098ef..7833f6e3781d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -436,7 +436,7 @@ int mt76_dfs_start_rdd(struct mt7915_dev *dev, bool force); int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy); void mt7915_set_stream_he_caps(struct mt7915_phy *phy); void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy); -void mt7915_update_channel(struct mt76_dev *mdev); +void mt7915_update_channel(struct mt76_phy *mphy); int mt7915_init_debugfs(struct mt7915_dev *dev); #ifdef CONFIG_MAC80211_DEBUGFS void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 8e2252c1acd4..1d710f276884 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1227,18 +1227,18 @@ mt7921_phy_update_channel(struct mt76_phy *mphy, int idx) state->noise = -(phy->noise >> 4); } -void mt7921_update_channel(struct mt76_dev *mdev) +void mt7921_update_channel(struct mt76_phy *mphy) { - struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + struct mt7921_dev *dev = container_of(mphy->dev, struct mt7921_dev, mt76); - if (mt76_connac_pm_wake(&dev->mphy, &dev->pm)) + if (mt76_connac_pm_wake(mphy, &dev->pm)) return; - mt7921_phy_update_channel(&mdev->phy, 0); + mt7921_phy_update_channel(mphy, 0); /* reset obss airtime */ mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR); - mt76_connac_power_save_sched(&dev->mphy, &dev->pm); + mt76_connac_power_save_sched(mphy, &dev->pm); } void mt7921_tx_token_put(struct mt7921_dev *dev) @@ -1436,7 +1436,7 @@ void mt7921_mac_work(struct work_struct *work) mt7921_mutex_acquire(phy->dev); - mt76_update_survey(mphy->dev); + mt76_update_survey(mphy); if (++mphy->mac_work_count == 2) { mphy->mac_work_count = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 087067e7ea5b..a6ff704d0023 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -356,7 +356,7 @@ void mt7921_stats_work(struct work_struct *work); void mt7921_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *txwi); void mt7921_set_stream_he_caps(struct mt7921_phy *phy); -void mt7921_update_channel(struct mt76_dev *mdev); +void mt7921_update_channel(struct mt76_phy *mphy); int mt7921_init_debugfs(struct mt7921_dev *dev); int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev, From fd843822231337f356f2cb2af2f7e43efac015bb Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Fri, 11 Jun 2021 02:43:46 +0800 Subject: [PATCH 080/170] mt76: mt7915: introduce mt7915_mcu_set_txbf() Use mt7915_mcu_set_txbf() to reduce global functions. This can be easily extended to support other TxBF commands in further patches. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7915/debugfs.c | 3 +- .../net/wireless/mediatek/mt76/mt7915/init.c | 7 +- .../net/wireless/mediatek/mt76/mt7915/mcu.c | 83 +++++++++---------- .../net/wireless/mediatek/mt76/mt7915/mcu.h | 6 ++ .../wireless/mediatek/mt76/mt7915/mt7915.h | 4 +- 5 files changed, 50 insertions(+), 53 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 3961d46e0df8..c6e9a7038311 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -3,6 +3,7 @@ #include "mt7915.h" #include "eeprom.h" +#include "mcu.h" /** global debugfs **/ @@ -16,7 +17,7 @@ mt7915_implicit_txbf_set(void *data, u64 val) dev->ibf = !!val; - return mt7915_mcu_set_txbf_type(dev); + return mt7915_mcu_set_txbf(dev, MT_BF_TYPE_UPDATE); } static int diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 10c8d9244dc9..36bb7121c57f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -313,20 +313,19 @@ static int mt7915_txbf_init(struct mt7915_dev *dev) { int ret; - if (dev->dbdc_support) { - ret = mt7915_mcu_set_txbf_module(dev); + ret = mt7915_mcu_set_txbf(dev, MT_BF_MODULE_UPDATE); if (ret) return ret; } /* trigger sounding packets */ - ret = mt7915_mcu_set_txbf_sounding(dev); + ret = mt7915_mcu_set_txbf(dev, MT_BF_SOUNDING_ON); if (ret) return ret; /* enable eBF */ - return mt7915_mcu_set_txbf_type(dev); + return mt7915_mcu_set_txbf(dev, MT_BF_TYPE_UPDATE); } static int mt7915_register_ext_phy(struct mt7915_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index e28396938ce9..ca633c1bb8c7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -3893,57 +3893,50 @@ int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band) &req, sizeof(req), false); } -int mt7915_mcu_set_txbf_module(struct mt7915_dev *dev) +int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action) { -#define MT_BF_MODULE_UPDATE 25 struct { u8 action; - u8 bf_num; - u8 bf_bitmap; - u8 bf_sel[8]; - u8 rsv[8]; + union { + struct { + u8 snd_mode; + u8 sta_num; + u8 rsv; + u8 wlan_idx[4]; + __le32 snd_period; /* ms */ + } __packed snd; + struct { + bool ebf; + bool ibf; + u8 rsv; + } __packed type; + struct { + u8 bf_num; + u8 bf_bitmap; + u8 bf_sel[8]; + u8 rsv[5]; + } __packed mod; + }; } __packed req = { - .action = MT_BF_MODULE_UPDATE, - .bf_num = 2, - .bf_bitmap = GENMASK(1, 0), + .action = action, }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXBF_ACTION), &req, - sizeof(req), true); -} - -int mt7915_mcu_set_txbf_type(struct mt7915_dev *dev) -{ -#define MT_BF_TYPE_UPDATE 20 - struct { - u8 action; - bool ebf; - bool ibf; - u8 rsv; - } __packed req = { - .action = MT_BF_TYPE_UPDATE, - .ebf = true, - .ibf = dev->ibf, - }; - - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXBF_ACTION), &req, - sizeof(req), true); -} - -int mt7915_mcu_set_txbf_sounding(struct mt7915_dev *dev) -{ -#define MT_BF_PROCESSING 4 - struct { - u8 action; - u8 snd_mode; - u8 sta_num; - u8 rsv; - u8 wlan_idx[4]; - __le32 snd_period; /* ms */ - } __packed req = { - .action = true, - .snd_mode = MT_BF_PROCESSING, - }; +#define MT_BF_PROCESSING 4 + switch (action) { + case MT_BF_SOUNDING_ON: + req.snd.snd_mode = MT_BF_PROCESSING; + break; + case MT_BF_TYPE_UPDATE: + req.type.ebf = true; + req.type.ibf = dev->ibf; + break; + case MT_BF_MODULE_UPDATE: + req.mod.bf_num = 2; + req.mod.bf_bitmap = GENMASK(1, 0); + break; + default: + return -EINVAL; + } return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXBF_ACTION), &req, sizeof(req), true); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 70ab06d9f954..9087a7771c35 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -1120,6 +1120,12 @@ enum { MT_IBF = BIT(1) /* implicit beamforming */ }; +enum { + MT_BF_SOUNDING_ON = 1, + MT_BF_TYPE_UPDATE = 20, + MT_BF_MODULE_UPDATE = 25 +}; + #define MT7915_WTBL_UPDATE_MAX_SIZE (sizeof(struct wtbl_req_hdr) + \ sizeof(struct wtbl_generic) + \ sizeof(struct wtbl_rx) + \ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 7833f6e3781d..3f613fae6218 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -356,9 +356,7 @@ int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter); int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable); int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy); int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len); -int mt7915_mcu_set_txbf_type(struct mt7915_dev *dev); -int mt7915_mcu_set_txbf_module(struct mt7915_dev *dev); -int mt7915_mcu_set_txbf_sounding(struct mt7915_dev *dev); +int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action); int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val); int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev, const struct mt7915_dfs_pulse *pulse); From b70946ced192a04a4d462e384ee1b44caed79acd Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Fri, 11 Jun 2021 04:03:26 +0800 Subject: [PATCH 081/170] mt76: mt7915: improve MU stability - Adjust starec flow since VHT MU group is only updated by starec_vht follows starec_bf settings. - Drop unnecessary MU BF checks. TX MPDU PER (Status = Success): TOT_MPDU_CNT FAIL_MPDU_CNT TX_PER WCID Rate 1 VHT_BW80_2SS_MCS7_LGI_LDPC_MUBF 114 0 0.00% VHT_BW80_2SS_MCS7_LGI_LDPC_MUBF_MU 64 0 0.00% VHT_BW80_2SS_MCS7_SGI_LDPC_MUBF 128 0 0.00% VHT_BW80_2SS_MCS7_SGI_LDPC_MUBF_MU 745 0 0.00% VHT_BW80_2SS_MCS8_LGI_LDPC_MUBF_MU 856 0 0.00% VHT_BW80_2SS_MCS8_SGI_LDPC_MUBF_MU 1430 4 0.28% VHT_BW80_2SS_MCS9_LGI_LDPC_MUBF_MU 5220 31 0.59% VHT_BW80_2SS_MCS9_LGI_LDPC_iBF 59 0 0.00% VHT_BW80_2SS_MCS9_SGI_LDPC_MUBF 64 2 3.12% VHT_BW80_2SS_MCS9_SGI_LDPC_MUBF_MU 22132 76 0.34% VHT_BW80_2SS_MCS9_SGI_LDPC_iBF 2866 1 0.03% 2 VHT_BW80_2SS_MCS7_LGI_LDPC_MUBF_MU 3781 5 0.13% VHT_BW80_2SS_MCS7_SGI_LDPC_MUBF_MU 735 0 0.00% VHT_BW80_2SS_MCS8_LGI_LDPC_MUBF_MU 1270 365 28.74% VHT_BW80_2SS_MCS8_SGI_LDPC_MUBF_MU 3420 57 1.67% VHT_BW80_2SS_MCS9_LGI_LDPC_MUBF 128 0 0.00% VHT_BW80_2SS_MCS9_LGI_LDPC_MUBF_MU 64 0 0.00% VHT_BW80_2SS_MCS9_SGI_LDPC_MUBF 191 0 0.00% VHT_BW80_2SS_MCS9_SGI_LDPC_MUBF_MU 18833 320 1.70% VHT_BW80_2SS_MCS9_SGI_LDPC_iBF 6040 0 0.00% 287 OFDM 6M Tested-by: Evelyn Tsai Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7915/debugfs.c | 12 ++- .../net/wireless/mediatek/mt76/mt7915/mcu.c | 98 +++++++++---------- .../net/wireless/mediatek/mt76/mt7915/regs.h | 5 + 3 files changed, 64 insertions(+), 51 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index c6e9a7038311..64048243e34b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -148,6 +148,9 @@ mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s) { struct mt7915_dev *dev = s->private; bool ext_phy = phy != &dev->phy; + static const char * const bw[] = { + "BW20", "BW40", "BW80", "BW160" + }; int cnt; if (!phy) @@ -165,11 +168,16 @@ mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s) seq_puts(s, "Tx Beamformer Rx feedback statistics: "); cnt = mt76_rr(dev, MT_ETBF_RX_FB_CNT(ext_phy)); - seq_printf(s, "All: %ld, HE: %ld, VHT: %ld, HT: %ld\n", + seq_printf(s, "All: %ld, HE: %ld, VHT: %ld, HT: %ld, ", FIELD_GET(MT_ETBF_RX_FB_ALL, cnt), FIELD_GET(MT_ETBF_RX_FB_HE, cnt), FIELD_GET(MT_ETBF_RX_FB_VHT, cnt), FIELD_GET(MT_ETBF_RX_FB_HT, cnt)); + cnt = mt76_rr(dev, MT_ETBF_RX_FB_CONT(ext_phy)); + seq_printf(s, "%s, NC: %ld, NR: %ld\n", + bw[FIELD_GET(MT_ETBF_RX_FB_BW, cnt)], + FIELD_GET(MT_ETBF_RX_FB_NC, cnt), + FIELD_GET(MT_ETBF_RX_FB_NR, cnt)); /* Tx Beamformee Rx NDPA & Tx feedback report */ cnt = mt76_rr(dev, MT_ETBF_TX_NDP_BFRP(ext_phy)); @@ -205,7 +213,7 @@ mt7915_tx_stats_show(struct seq_file *file, void *data) mt7915_txbf_stat_read_phy(mt7915_ext_phy(dev), file); /* Tx amsdu info */ - seq_puts(file, "Tx MSDU stat:\n"); + seq_puts(file, "Tx MSDU statistics:\n"); for (i = 0, n = 0; i < ARRAY_SIZE(stat); i++) { stat[i] = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i)); n += stat[i]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index ca633c1bb8c7..b565024404cf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1685,27 +1685,18 @@ mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]); } -static int -mt7915_mcu_add_mu(struct mt7915_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +static void +mt7915_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) { - struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; - struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; - struct sk_buff *skb; - int len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_muru); + struct sta_rec_vht *vht; + struct tlv *tlv; - if (!sta->vht_cap.vht_supported && !sta->he_cap.has_he) - return 0; + tlv = mt7915_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht)); - skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); - if (IS_ERR(skb)) - return PTR_ERR(skb); - - /* starec muru */ - mt7915_mcu_sta_muru_tlv(skb, sta); - - return mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_EXT_CMD(STA_REC_UPDATE), true); + vht = (struct sta_rec_vht *)tlv; + vht->vht_cap = cpu_to_le32(sta->vht_cap.cap); + vht->vht_rx_mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map; + vht->vht_tx_mcs_map = sta->vht_cap.vht_mcs.tx_mcs_map; } static void @@ -1757,17 +1748,6 @@ mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb, mt7915_mcu_sta_amsdu_tlv(skb, sta); } - /* starec vht */ - if (sta->vht_cap.vht_supported) { - struct sta_rec_vht *vht; - - tlv = mt7915_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht)); - vht = (struct sta_rec_vht *)tlv; - vht->vht_cap = cpu_to_le32(sta->vht_cap.cap); - vht->vht_rx_mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map; - vht->vht_tx_mcs_map = sta->vht_cap.vht_mcs.tx_mcs_map; - } - /* starec he */ if (sta->he_cap.has_he) mt7915_mcu_sta_he_tlv(skb, sta); @@ -2157,26 +2137,21 @@ mt7915_mcu_add_txbf(struct mt7915_dev *dev, struct ieee80211_vif *vif, vc = mt7915_get_he_phy_cap(phy, vif); ve = &vc->he_cap_elem; - ebfee = !!((HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]) || - HE_PHY(CAP4_MU_BEAMFORMER, pe->phy_cap_info[4])) && + ebfee = !!(HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]) && HE_PHY(CAP4_SU_BEAMFORMEE, ve->phy_cap_info[4])); - ebf = !!((HE_PHY(CAP3_SU_BEAMFORMER, ve->phy_cap_info[3]) || - HE_PHY(CAP4_MU_BEAMFORMER, ve->phy_cap_info[4])) && + ebf = !!(HE_PHY(CAP3_SU_BEAMFORMER, ve->phy_cap_info[3]) && HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4])); } else if (sta->vht_cap.vht_supported) { struct ieee80211_sta_vht_cap *pc; struct ieee80211_sta_vht_cap *vc; - u32 cr, ce; pc = &sta->vht_cap; vc = &phy->mt76->sband_5g.sband.vht_cap; - cr = IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | - IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE; - ce = IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | - IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; - ebfee = !!((pc->cap & cr) && (vc->cap & ce)); - ebf = !!((vc->cap & cr) && (pc->cap & ce)); + ebfee = !!((pc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) && + (vc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)); + ebf = !!((vc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) && + (pc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)); } /* must keep each tag independent */ @@ -2379,6 +2354,38 @@ mt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif, sizeof(req), true); } +static int +mt7915_mcu_add_mu(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct sk_buff *skb; + int ret; + + if (!sta->vht_cap.vht_supported && !sta->he_cap.has_he) + return 0; + + ret = mt7915_mcu_add_group(dev, vif, sta); + if (ret) + return ret; + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, + MT7915_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + /* wait until TxBF and MU ready to update stare vht */ + + /* starec muru */ + mt7915_mcu_sta_muru_tlv(skb, sta); + /* starec vht */ + mt7915_mcu_sta_vht_tlv(skb, sta); + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD(STA_REC_UPDATE), true); +} + int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { @@ -2388,22 +2395,15 @@ int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif, return 0; /* must keep the order */ - ret = mt7915_mcu_add_group(dev, vif, sta); - if (ret) - return ret; - ret = mt7915_mcu_add_txbf(dev, vif, sta, enable); - if (ret) + if (ret || !enable) return ret; ret = mt7915_mcu_add_mu(dev, vif, sta); if (ret) return ret; - if (enable) - return mt7915_mcu_add_rate_ctrl(dev, vif, sta); - - return 0; + return mt7915_mcu_add_rate_ctrl(dev, vif, sta); } int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index 56c33eaa9d79..a213b5cb82f8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -99,6 +99,11 @@ #define MT_ETBF_TX_FB_CPL GENMASK(31, 16) #define MT_ETBF_TX_FB_TRI GENMASK(15, 0) +#define MT_ETBF_RX_FB_CONT(_band) MT_WF_ETBF(_band, 0x068) +#define MT_ETBF_RX_FB_BW GENMASK(7, 6) +#define MT_ETBF_RX_FB_NC GENMASK(5, 3) +#define MT_ETBF_RX_FB_NR GENMASK(2, 0) + #define MT_ETBF_TX_APP_CNT(_band) MT_WF_ETBF(_band, 0x0f0) #define MT_ETBF_TX_IBF_CNT GENMASK(31, 16) #define MT_ETBF_TX_EBF_CNT GENMASK(15, 0) From c44ccf1dcce89c1d29500d209d93092acd32349d Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Thu, 10 Jun 2021 14:44:37 -0700 Subject: [PATCH 082/170] mt76: add a space between comment char and SPDX tag checkpatch expects a space between '#' and 'SPDX...' Add a space. Signed-off-by: Tom Rix Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/Makefile | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/Makefile | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/Makefile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile index e8fc4a7ae9bc..83f9861ff522 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile @@ -1,4 +1,4 @@ -#SPDX-License-Identifier: ISC +# SPDX-License-Identifier: ISC obj-$(CONFIG_MT7615_COMMON) += mt7615-common.o obj-$(CONFIG_MT7615E) += mt7615e.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/Makefile b/drivers/net/wireless/mediatek/mt76/mt7915/Makefile index 40c8061787e9..80e49244348e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7915/Makefile @@ -1,4 +1,4 @@ -#SPDX-License-Identifier: ISC +# SPDX-License-Identifier: ISC obj-$(CONFIG_MT7915E) += mt7915e.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile index e531666f9fb4..0ebb59966a08 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile @@ -1,4 +1,4 @@ -#SPDX-License-Identifier: ISC +# SPDX-License-Identifier: ISC obj-$(CONFIG_MT7921E) += mt7921e.o From e7f1c44192df90c17d486d8e3614a338772132d5 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Thu, 10 Jun 2021 14:44:38 -0700 Subject: [PATCH 083/170] mt76: use SPDX header file comment style header files should use '/* SPDX ... */ Change from c file comment syle to header style Signed-off-by: Tom Rix Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/sdio.h | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/testmode.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h index 05180971de84..03877d89e152 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: ISC +/* SPDX-License-Identifier: ISC */ /* Copyright (C) 2020 MediaTek Inc. * * Author: Sean Wang diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h index 8f8533ef9859..397a6b5532bc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: ISC +/* SPDX-License-Identifier: ISC */ /* Copyright (C) 2020 MediaTek Inc. */ #ifndef __MT7915_TESTMODE_H From 2707ff4dd7b1479dbd44ebb3c74788084cc95245 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 12 Jun 2021 02:04:20 +0800 Subject: [PATCH 084/170] mt76: mt7915: fix IEEE80211_HE_PHY_CAP7_MAX_NC for station mode The value of station mode is always 0. Fixed: 00b2e16e0063 ("mt76: mt7915: add TxBF capabilities") Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 36bb7121c57f..7af1cdbbfebd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -568,6 +568,9 @@ mt7915_set_stream_he_txbf_caps(struct ieee80211_sta_he_cap *he_cap, if (nss < 2) return; + /* the maximum cap is 4 x 3, (Nr, Nc) = (3, 2) */ + elem->phy_cap_info[7] |= min_t(int, nss - 1, 2) << 3; + if (vif != NL80211_IFTYPE_AP) return; @@ -581,9 +584,6 @@ mt7915_set_stream_he_txbf_caps(struct ieee80211_sta_he_cap *he_cap, c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB; elem->phy_cap_info[6] |= c; - - /* the maximum cap is 4 x 3, (Nr, Nc) = (3, 2) */ - elem->phy_cap_info[7] |= min_t(int, nss - 1, 2) << 3; } static void From f5056657f995f0e36bc9e30e5f608ff55c1bdf72 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Mon, 10 May 2021 23:14:52 +0800 Subject: [PATCH 085/170] mt76: mt7921: enable deep sleep at runtime Enable the deep sleep mode with that firmware is able to trap into the doze state at runtime to reduce the power consumption further. The deep sleep mode is not allowed in the STA state transition with the firmware to have the fast connection experience as we've done in the full power mode Reviewed-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7615/mcu.c | 8 ++- .../wireless/mediatek/mt76/mt76_connac_mcu.c | 40 +++++++++--- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 20 ++++-- .../net/wireless/mediatek/mt76/mt7921/init.c | 6 +- .../net/wireless/mediatek/mt76/mt7921/main.c | 63 ++++++++++++------- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 9 ++- .../wireless/mediatek/mt76/mt7921/mt7921.h | 7 ++- .../net/wireless/mediatek/mt76/mt7921/pci.c | 1 + 8 files changed, 110 insertions(+), 44 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index ea1f23e99ca1..f8a09692d3e4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1028,9 +1028,10 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif, if (IS_ERR(sskb)) return PTR_ERR(sskb); - mt76_connac_mcu_sta_basic_tlv(sskb, vif, sta, enable); + mt76_connac_mcu_sta_basic_tlv(sskb, vif, sta, enable, true); if (enable && sta) - mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif, 0); + mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif, 0, + MT76_STA_INFO_STATE_ASSOC); wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid, WTBL_RESET_AND_SET, NULL, @@ -1157,11 +1158,12 @@ __mt7615_mcu_add_sta(struct mt76_phy *phy, struct ieee80211_vif *vif, .vif = vif, .offload_fw = offload_fw, .enable = enable, + .newly = true, .cmd = cmd, }; info.wcid = sta ? (struct mt76_wcid *)sta->drv_priv : &mvif->sta.wcid; - return mt76_connac_mcu_add_sta_cmd(phy, &info); + return mt76_connac_mcu_sta_cmd(phy, &info); } static int diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 78498d86efc3..302318e3a964 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -304,7 +304,7 @@ EXPORT_SYMBOL_GPL(mt76_connac_mcu_alloc_wtbl_req); void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta, - bool enable) + bool enable, bool newly) { struct sta_rec_basic *basic; struct tlv *tlv; @@ -316,7 +316,8 @@ void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb, basic->extra_info = cpu_to_le16(EXTRA_INFO_VER); if (enable) { - basic->extra_info |= cpu_to_le16(EXTRA_INFO_NEW); + if (newly) + basic->extra_info |= cpu_to_le16(EXTRA_INFO_NEW); basic->conn_state = CONN_STATE_PORT_SECURE; } else { basic->conn_state = CONN_STATE_DISCONNECT; @@ -709,7 +710,7 @@ mt76_connac_get_phy_mode_v2(struct mt76_phy *mphy, struct ieee80211_vif *vif, void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, struct ieee80211_sta *sta, struct ieee80211_vif *vif, - u8 rcpi) + u8 rcpi, u8 sta_state) { struct cfg80211_chan_def *chandef = &mphy->chandef; enum nl80211_band band = chandef->chan->band; @@ -774,7 +775,7 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_STATE, sizeof(*state)); state = (struct sta_rec_state *)tlv; - state->state = 2; + state->state = sta_state; if (sta->vht_cap.vht_supported) { state->vht_opmode = sta->bandwidth; @@ -866,8 +867,8 @@ void mt76_connac_mcu_wtbl_ht_tlv(struct mt76_dev *dev, struct sk_buff *skb, } EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_ht_tlv); -int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy, - struct mt76_sta_cmd_info *info) +int mt76_connac_mcu_sta_cmd(struct mt76_phy *phy, + struct mt76_sta_cmd_info *info) { struct mt76_vif *mvif = (struct mt76_vif *)info->vif->drv_priv; struct mt76_dev *dev = phy->dev; @@ -881,10 +882,11 @@ int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy, if (info->sta || !info->offload_fw) mt76_connac_mcu_sta_basic_tlv(skb, info->vif, info->sta, - info->enable); + info->enable, info->newly); if (info->sta && info->enable) mt76_connac_mcu_sta_tlv(phy, skb, info->sta, - info->vif, info->rcpi); + info->vif, info->rcpi, + info->state); sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); @@ -908,7 +910,7 @@ int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy, return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true); } -EXPORT_SYMBOL_GPL(mt76_connac_mcu_add_sta_cmd); +EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_cmd); void mt76_connac_mcu_wtbl_ba_tlv(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_ampdu_params *params, @@ -1616,6 +1618,26 @@ int mt76_connac_mcu_set_deep_sleep(struct mt76_dev *dev, bool enable) } EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_deep_sleep); +int mt76_connac_sta_state_dp(struct mt76_dev *dev, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state) +{ + if ((old_state == IEEE80211_STA_ASSOC && + new_state == IEEE80211_STA_AUTHORIZED) || + (old_state == IEEE80211_STA_NONE && + new_state == IEEE80211_STA_NOTEXIST)) + mt76_connac_mcu_set_deep_sleep(dev, true); + + if ((old_state == IEEE80211_STA_NOTEXIST && + new_state == IEEE80211_STA_NONE) || + (old_state == IEEE80211_STA_AUTHORIZED && + new_state == IEEE80211_STA_ASSOC)) + mt76_connac_mcu_set_deep_sleep(dev, false); + + return 0; +} +EXPORT_SYMBOL_GPL(mt76_connac_sta_state_dp); + void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb, struct mt76_connac_coredump *coredump) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 9f3c87902db8..1c73beb22677 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -927,6 +927,12 @@ struct mt76_connac_suspend_tlv { u8 pad[5]; } __packed; +enum mt76_sta_info_state { + MT76_STA_INFO_STATE_NONE, + MT76_STA_INFO_STATE_AUTH, + MT76_STA_INFO_STATE_ASSOC +}; + struct mt76_sta_cmd_info { struct ieee80211_sta *sta; struct mt76_wcid *wcid; @@ -935,8 +941,10 @@ struct mt76_sta_cmd_info { bool offload_fw; bool enable; + bool newly; int cmd; u8 rcpi; + u8 state; }; #define MT_SKU_POWER_LIMIT 161 @@ -1006,7 +1014,8 @@ int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy); int mt76_connac_mcu_set_vif_ps(struct mt76_dev *dev, struct ieee80211_vif *vif); void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enable); + struct ieee80211_sta *sta, bool enable, + bool newly); void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta, void *sta_wtbl, @@ -1021,7 +1030,7 @@ int mt76_connac_mcu_sta_update_hdr_trans(struct mt76_dev *dev, void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, struct ieee80211_sta *sta, struct ieee80211_vif *vif, - u8 rcpi); + u8 rcpi, u8 state); void mt76_connac_mcu_wtbl_ht_tlv(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_sta *sta, void *sta_wtbl, void *wtbl_tlv); @@ -1043,8 +1052,8 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy, struct ieee80211_vif *vif, struct mt76_wcid *wcid, bool enable); -int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy, - struct mt76_sta_cmd_info *info); +int mt76_connac_mcu_sta_cmd(struct mt76_phy *phy, + struct mt76_sta_cmd_info *info); void mt76_connac_mcu_beacon_loss_iter(void *priv, u8 *mac, struct ieee80211_vif *vif); int mt76_connac_mcu_set_rts_thresh(struct mt76_dev *dev, u32 val, u8 band); @@ -1076,6 +1085,9 @@ int mt76_connac_mcu_update_gtk_rekey(struct ieee80211_hw *hw, int mt76_connac_mcu_set_hif_suspend(struct mt76_dev *dev, bool suspend); void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif); +int mt76_connac_sta_state_dp(struct mt76_dev *dev, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state); int mt76_connac_mcu_chip_config(struct mt76_dev *dev); int mt76_connac_mcu_set_deep_sleep(struct mt76_dev *dev, bool enable); void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index b399f3b8b5d7..aca057c7576b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -231,7 +231,11 @@ int mt7921_register_device(struct mt7921_dev *dev) if (ret) return ret; - return mt7921_init_debugfs(dev); + ret = mt7921_init_debugfs(dev); + if (ret) + return ret; + + return mt76_connac_mcu_set_deep_sleep(&dev->mt76, dev->pm.enable); } void mt7921_unregister_device(struct mt7921_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 5fc6cf7e5455..07e86bab0348 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -577,7 +577,8 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw, mt7921_mcu_uni_bss_ps(dev, vif); if (changed & BSS_CHANGED_ASSOC) { - mt7921_mcu_sta_add(dev, NULL, vif, true); + mt7921_mcu_sta_update(dev, NULL, vif, true, + MT76_STA_INFO_STATE_ASSOC); mt7921_bss_bcnft_apply(dev, vif, info->assoc); } @@ -616,17 +617,14 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (ret) return ret; - if (vif->type == NL80211_IFTYPE_STATION) { + if (vif->type == NL80211_IFTYPE_STATION) mvif->wep_sta = msta; - if (!sta->tdls) - mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, - &mvif->sta.wcid, true); - } mt7921_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - ret = mt7921_mcu_sta_add(dev, sta, vif, true); + ret = mt7921_mcu_sta_update(dev, sta, vif, true, + MT76_STA_INFO_STATE_NONE); if (ret) return ret; @@ -635,6 +633,27 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, return 0; } +void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + + mt7921_mutex_acquire(dev); + + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) + mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, &mvif->sta.wcid, + true); + + mt7921_mac_wtbl_update(dev, msta->wcid.idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + mt7921_mcu_sta_update(dev, sta, vif, true, MT76_STA_INFO_STATE_ASSOC); + + mt7921_mutex_release(dev); +} + void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { @@ -644,7 +663,7 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid); mt76_connac_pm_wake(&dev->mphy, &dev->pm); - mt7921_mcu_sta_add(dev, sta, vif, false); + mt7921_mcu_sta_update(dev, sta, vif, false, MT76_STA_INFO_STATE_NONE); mt7921_mac_wtbl_update(dev, msta->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); @@ -790,20 +809,21 @@ mt7921_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return ret; } -static int -mt7921_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +static int mt7921_sta_state(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state) { - return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST, - IEEE80211_STA_NONE); -} + struct mt7921_dev *dev = mt7921_hw_dev(hw); -static int -mt7921_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NONE, - IEEE80211_STA_NOTEXIST); + if (dev->pm.enable) { + mt7921_mutex_acquire(dev); + mt76_connac_sta_state_dp(&dev->mt76, old_state, new_state); + mt7921_mutex_release(dev); + } + + return mt76_sta_state(hw, vif, sta, old_state, new_state); } static int @@ -1149,8 +1169,7 @@ const struct ieee80211_ops mt7921_ops = { .conf_tx = mt7921_conf_tx, .configure_filter = mt7921_configure_filter, .bss_info_changed = mt7921_bss_info_changed, - .sta_add = mt7921_sta_add, - .sta_remove = mt7921_sta_remove, + .sta_state = mt7921_sta_state, .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, .set_key = mt7921_set_key, .sta_set_decap_offload = mt7921_sta_set_decap_offload, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index ca481e37d22c..23ec0c816d64 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -1267,8 +1267,9 @@ int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, sizeof(req), false); } -int mt7921_mcu_sta_add(struct mt7921_dev *dev, struct ieee80211_sta *sta, - struct ieee80211_vif *vif, bool enable) +int mt7921_mcu_sta_update(struct mt7921_dev *dev, struct ieee80211_sta *sta, + struct ieee80211_vif *vif, bool enable, + enum mt76_sta_info_state state) { struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; int rssi = -ewma_rssi_read(&mvif->rssi); @@ -1277,6 +1278,7 @@ int mt7921_mcu_sta_add(struct mt7921_dev *dev, struct ieee80211_sta *sta, .vif = vif, .enable = enable, .cmd = MCU_UNI_CMD_STA_REC_UPDATE, + .state = state, .offload_fw = true, .rcpi = to_rcpi(rssi), }; @@ -1284,8 +1286,9 @@ int mt7921_mcu_sta_add(struct mt7921_dev *dev, struct ieee80211_sta *sta, msta = sta ? (struct mt7921_sta *)sta->drv_priv : NULL; info.wcid = msta ? &msta->wcid : &mvif->sta.wcid; + info.newly = msta ? state != MT76_STA_INFO_STATE_ASSOC : true; - return mt76_connac_mcu_add_sta_cmd(&dev->mphy, &info); + return mt76_connac_mcu_sta_cmd(&dev->mphy, &info); } int __mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index a6ff704d0023..92cf38444b46 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -261,8 +261,9 @@ int mt7921_mcu_init(struct mt7921_dev *dev); int mt7921_mcu_add_key(struct mt7921_dev *dev, struct ieee80211_vif *vif, struct mt7921_sta *msta, struct ieee80211_key_conf *key, enum set_key_cmd cmd); -int mt7921_mcu_sta_add(struct mt7921_dev *dev, struct ieee80211_sta *sta, - struct ieee80211_vif *vif, bool enable); +int mt7921_mcu_sta_update(struct mt7921_dev *dev, struct ieee80211_sta *sta, + struct ieee80211_vif *vif, bool enable, + enum mt76_sta_info_state state); int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd); int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif); int mt7921_mcu_set_eeprom(struct mt7921_dev *dev); @@ -334,6 +335,8 @@ void mt7921_mac_fill_rx_vector(struct mt7921_dev *dev, struct sk_buff *skb); void mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb); int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); +void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void mt7921_mac_work(struct work_struct *work); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index 13263f50dc00..27906b2cd912 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -106,6 +106,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev, .rx_poll_complete = mt7921_rx_poll_complete, .sta_ps = mt7921_sta_ps, .sta_add = mt7921_mac_sta_add, + .sta_assoc = mt7921_mac_sta_assoc, .sta_remove = mt7921_mac_sta_remove, .update_survey = mt7921_update_channel, }; From aa967eb791198f9cf5304493c93f7567dfc8a5ff Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Mon, 10 May 2021 23:14:53 +0800 Subject: [PATCH 086/170] mt76: mt7921: add deep sleep control to runtime-pm knob Add addtional the deep sleep control to runtime-pm knob to allow us to control driver switching between the full power mode and the deep sleep mode the firmware is able to support. Reviewed-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7921/debugfs.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c index 6602903c0d02..c8cba1821cd7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c @@ -250,6 +250,9 @@ mt7921_pm_set(void *data, u64 val) ieee80211_iterate_active_interfaces(mphy->hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7921_pm_interface_iter, mphy->priv); + + mt76_connac_mcu_set_deep_sleep(&dev->mt76, !!pm->enable); + mt7921_mutex_release(dev); return 0; @@ -267,6 +270,20 @@ mt7921_pm_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(fops_pm, mt7921_pm_get, mt7921_pm_set, "%lld\n"); +static int +mt7921_deep_sleep_set(void *data, u64 val) +{ + struct mt7921_dev *dev = data; + + mt7921_mutex_acquire(dev); + mt76_connac_mcu_set_deep_sleep(&dev->mt76, !!val); + mt7921_mutex_release(dev); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_ds, NULL, mt7921_deep_sleep_set, "%lld\n"); + static int mt7921_pm_stats(struct seq_file *s, void *data) { @@ -358,6 +375,7 @@ int mt7921_init_debugfs(struct mt7921_dev *dev) debugfs_create_file("chip_reset", 0600, dir, dev, &fops_reset); debugfs_create_devm_seqfile(dev->mt76.dev, "runtime_pm_stats", dir, mt7921_pm_stats); + debugfs_create_file("deep-sleep", 0600, dir, dev, &fops_ds); return 0; } From e5bca8c5d2cd3502c15170a57c81a7587a38e957 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 12 Jun 2021 14:43:03 +0200 Subject: [PATCH 087/170] mt76: mt7921: improve code readability for mt7921_update_txs Introduce mt7921_update_txs routine in order to improve code readability for tx timestamp parsing/configuration. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7921/mac.c | 47 +++++++------------ 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 1d710f276884..70f9618eee4a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -13,26 +13,6 @@ #define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\ IEEE80211_RADIOTAP_HE_##f) -static unsigned long -mt7921_next_txs_set(struct mt7921_dev *dev, struct mt76_wcid *wcid, - u32 timeout) -{ - struct mt7921_sta *msta; - - msta = container_of(wcid, struct mt7921_sta, wcid); - msta->next_txs_ts = jiffies + msecs_to_jiffies(timeout); - return msta->next_txs_ts; -} - -static bool -mt7921_next_txs_timeout(struct mt7921_dev *dev, struct mt76_wcid *wcid) -{ - struct mt7921_sta *msta; - - msta = container_of(wcid, struct mt7921_sta, wcid); - return time_is_before_jiffies(msta->next_txs_ts); -} - static struct mt76_wcid *mt7921_rx_get_wcid(struct mt7921_dev *dev, u16 idx, bool unicast) { @@ -739,6 +719,23 @@ mt7921_mac_write_txwi_80211(struct mt7921_dev *dev, __le32 *txwi, txwi[7] |= cpu_to_le32(val); } +static void mt7921_update_txs(struct mt76_wcid *wcid, __le32 *txwi) +{ + struct mt7921_sta *msta = container_of(wcid, struct mt7921_sta, wcid); + u32 pid, frame_type = FIELD_GET(MT_TXD2_FRAME_TYPE, txwi[2]); + + if (!(frame_type & (IEEE80211_FTYPE_DATA >> 2))) + return; + + if (time_is_after_eq_jiffies(msta->next_txs_ts)) + return; + + msta->next_txs_ts = jiffies + msecs_to_jiffies(250); + pid = mt76_get_next_pkt_id(wcid); + txwi[5] |= cpu_to_le32(MT_TXD5_TX_STATUS_MCU | + FIELD_PREP(MT_TXD5_PID, pid)); +} + void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, bool beacon) @@ -816,15 +813,7 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); } - if ((FIELD_GET(MT_TXD2_FRAME_TYPE, txwi[2]) & - (IEEE80211_FTYPE_DATA >> 2)) && - mt7921_next_txs_timeout(dev, wcid)) { - u8 pid = mt76_get_next_pkt_id(wcid); - - mt7921_next_txs_set(dev, wcid, 250); - val = MT_TXD5_TX_STATUS_MCU | FIELD_PREP(MT_TXD5_PID, pid); - txwi[5] |= cpu_to_le32(val); - } + mt7921_update_txs(wcid, txwi); } static void From 8225816d2974204c09228f94c0451bd959575475 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 12 Jun 2021 14:48:48 +0200 Subject: [PATCH 088/170] mt76: mt7921: limit txpower according to userlevel power Limit tx power for single-sku according to userlevel power. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.c | 28 +++++++++++++------ .../net/wireless/mediatek/mt76/mt7921/main.c | 3 ++ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 302318e3a964..5c3a81e5f559 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1768,12 +1768,15 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, 142, 144, 149, 151, 153, 155, 157, 159, 161, 165 }; + int i, n_chan, batch_size, idx = 0, tx_power, last_ch; struct mt76_connac_sku_tlv sku_tlbv; - int i, n_chan, batch_size, idx = 0; struct mt76_power_limits limits; const u8 *ch_list; sku_len = is_mt7921(dev) ? sizeof(sku_tlbv) : sizeof(sku_tlbv) - 92; + tx_power = 2 * phy->hw->conf.power_level; + if (!tx_power) + tx_power = 127; if (band == NL80211_BAND_2GHZ) { n_chan = ARRAY_SIZE(chan_list_2ghz); @@ -1784,39 +1787,48 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, } batch_size = DIV_ROUND_UP(n_chan, batch_len); + if (!phy->cap.has_5ghz) + last_ch = chan_list_2ghz[n_chan - 1]; + else + last_ch = chan_list_5ghz[n_chan - 1]; + for (i = 0; i < batch_size; i++) { - bool last_msg = i == batch_size - 1; - int num_ch = last_msg ? n_chan % batch_len : batch_len; struct mt76_connac_tx_power_limit_tlv tx_power_tlv = { .band = band == NL80211_BAND_2GHZ ? 1 : 2, - .n_chan = num_ch, - .last_msg = last_msg, }; + int j, err, msg_len, num_ch; struct sk_buff *skb; - int j, err, msg_len; + num_ch = i == batch_size - 1 ? n_chan % batch_len : batch_len; msg_len = sizeof(tx_power_tlv) + num_ch * sizeof(sku_tlbv); skb = mt76_mcu_msg_alloc(dev, NULL, msg_len); if (!skb) return -ENOMEM; + skb_reserve(skb, sizeof(tx_power_tlv)); + BUILD_BUG_ON(sizeof(dev->alpha2) > sizeof(tx_power_tlv.alpha2)); memcpy(tx_power_tlv.alpha2, dev->alpha2, sizeof(dev->alpha2)); + tx_power_tlv.n_chan = num_ch; - skb_put_data(skb, &tx_power_tlv, sizeof(tx_power_tlv)); for (j = 0; j < num_ch; j++, idx++) { struct ieee80211_channel chan = { .hw_value = ch_list[idx], .band = band, }; - mt76_get_rate_power_limits(phy, &chan, &limits, 127); + mt76_get_rate_power_limits(phy, &chan, &limits, + tx_power); + tx_power_tlv.last_msg = ch_list[idx] == last_ch; sku_tlbv.channel = ch_list[idx]; + mt76_connac_mcu_build_sku(dev, sku_tlbv.pwr_limit, &limits, band); skb_put_data(skb, &sku_tlbv, sku_len); } + __skb_push(skb, sizeof(tx_power_tlv)); + memcpy(skb->data, &tx_power_tlv, sizeof(tx_power_tlv)); err = mt76_mcu_skb_send_msg(dev, skb, MCU_CMD_SET_RATE_TX_POWER, false); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 07e86bab0348..6fd5c869bb4d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -432,6 +432,9 @@ static int mt7921_config(struct ieee80211_hw *hw, u32 changed) mt7921_mutex_acquire(dev); + if (changed & IEEE80211_CONF_CHANGE_POWER) + mt76_connac_mcu_set_rate_txpower(phy->mt76); + if (changed & IEEE80211_CONF_CHANGE_MONITOR) { bool enabled = !!(hw->conf.flags & IEEE80211_CONF_MONITOR); From 495cd981afe78b12fee635bfe35897eae427d89e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 12 Jun 2021 16:49:30 +0200 Subject: [PATCH 089/170] mt76: mt7921: introduce dedicated control for deep_sleep Introduce ds_enable switch to fully control fw deep_sleep capability Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac.h | 1 + .../wireless/mediatek/mt76/mt7921/debugfs.c | 22 ++++++++++++++++--- .../net/wireless/mediatek/mt76/mt7921/init.c | 3 ++- .../net/wireless/mediatek/mt76/mt7921/main.c | 2 +- .../net/wireless/mediatek/mt76/mt7921/pci.c | 14 +++++++----- 5 files changed, 32 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 9b3f8d22f17e..93a37ed0c483 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -46,6 +46,7 @@ enum { struct mt76_connac_pm { bool enable; + bool ds_enable; bool suspended; spinlock_t txq_lock; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c index c8cba1821cd7..77468bdae460 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c @@ -251,7 +251,7 @@ mt7921_pm_set(void *data, u64 val) IEEE80211_IFACE_ITER_RESUME_ALL, mt7921_pm_interface_iter, mphy->priv); - mt76_connac_mcu_set_deep_sleep(&dev->mt76, !!pm->enable); + mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable); mt7921_mutex_release(dev); @@ -274,15 +274,31 @@ static int mt7921_deep_sleep_set(void *data, u64 val) { struct mt7921_dev *dev = data; + struct mt76_connac_pm *pm = &dev->pm; + bool enable = !!val; mt7921_mutex_acquire(dev); - mt76_connac_mcu_set_deep_sleep(&dev->mt76, !!val); + if (pm->ds_enable != enable) { + mt76_connac_mcu_set_deep_sleep(&dev->mt76, enable); + pm->ds_enable = enable; + } mt7921_mutex_release(dev); return 0; } -DEFINE_DEBUGFS_ATTRIBUTE(fops_ds, NULL, mt7921_deep_sleep_set, "%lld\n"); +static int +mt7921_deep_sleep_get(void *data, u64 *val) +{ + struct mt7921_dev *dev = data; + + *val = dev->pm.ds_enable; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_ds, mt7921_deep_sleep_get, + mt7921_deep_sleep_set, "%lld\n"); static int mt7921_pm_stats(struct seq_file *s, void *data) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index aca057c7576b..9925c15ac9df 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -201,6 +201,7 @@ int mt7921_register_device(struct mt7921_dev *dev) dev->pm.stats.last_wake_event = jiffies; dev->pm.stats.last_doze_event = jiffies; dev->pm.enable = true; + dev->pm.ds_enable = true; ret = mt7921_init_hardware(dev); if (ret) @@ -235,7 +236,7 @@ int mt7921_register_device(struct mt7921_dev *dev) if (ret) return ret; - return mt76_connac_mcu_set_deep_sleep(&dev->mt76, dev->pm.enable); + return mt76_connac_mcu_set_deep_sleep(&dev->mt76, dev->pm.ds_enable); } void mt7921_unregister_device(struct mt7921_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 6fd5c869bb4d..0fb152ac4d87 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -820,7 +820,7 @@ static int mt7921_sta_state(struct ieee80211_hw *hw, { struct mt7921_dev *dev = mt7921_hw_dev(hw); - if (dev->pm.enable) { + if (dev->pm.ds_enable) { mt7921_mutex_acquire(dev); mt76_connac_sta_state_dp(&dev->mt76, old_state, new_state); mt7921_mutex_release(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index 27906b2cd912..c3905bcab360 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -208,8 +208,10 @@ static int mt7921_pci_suspend(struct pci_dev *pdev, pm_message_t state) goto restore_suspend; } - if (!pm->enable) - mt76_connac_mcu_set_deep_sleep(&dev->mt76, true); + /* always enable deep sleep during suspend to reduce + * power consumption + */ + mt76_connac_mcu_set_deep_sleep(&dev->mt76, true); napi_disable(&mdev->tx_napi); mt76_worker_disable(&mdev->tx_worker); @@ -252,7 +254,7 @@ restore_napi: } napi_enable(&mdev->tx_napi); - if (!pm->enable) + if (!pm->ds_enable) mt76_connac_mcu_set_deep_sleep(&dev->mt76, false); if (hif_suspend) @@ -268,9 +270,10 @@ static int mt7921_pci_resume(struct pci_dev *pdev) { struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + struct mt76_connac_pm *pm = &dev->pm; int i, err; - dev->pm.suspended = false; + pm->suspended = false; err = pci_set_power_state(pdev, PCI_D0); if (err) return err; @@ -301,7 +304,8 @@ static int mt7921_pci_resume(struct pci_dev *pdev) napi_enable(&mdev->tx_napi); napi_schedule(&mdev->tx_napi); - if (!dev->pm.enable) + /* restore previous ds setting */ + if (!pm->ds_enable) mt76_connac_mcu_set_deep_sleep(&dev->mt76, false); if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state)) From 78b0328ff8c46fce64eb969d2572c3f631735dc1 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 16 Jun 2021 05:31:10 +0800 Subject: [PATCH 090/170] mt76: mt7921: fix kernel warning when reset on vif is not sta ieee80211_disconnect is only called for the staton mode. [ 714.050429] WARNING: CPU: 1 PID: 382 at net/mac80211/mlme.c:2787 ieee80211_disconnect+0x108/0x118 [mac80211] [ 714.116704] Hardware name: MediaTek Asurada rev1 board (DT) [ 714.122303] Workqueue: mt76 mt7921_mac_reset_work [mt7921e] [ 714.127877] pstate: 20c00009 (nzCv daif +PAN +UAO) [ 714.132761] pc : ieee80211_disconnect+0x108/0x118 [mac80211] [ 714.138430] lr : mt7921_vif_connect_iter+0x28/0x54 [mt7921e] [ 714.144083] sp : ffffffc0107cbbd0 [ 714.147394] x29: ffffffc0107cbbd0 x28: ffffffb26c9cb928 [ 714.152706] x27: ffffffb26c9cbd98 x26: 0000000000000000 [ 714.158017] x25: 0000000000000003 x24: ffffffb26c9c9c38 [ 714.163328] x23: ffffffb26c9c9c38 x22: ffffffb26c9c8860 [ 714.168639] x21: ffffffb23b940000 x20: ffffffb26c9c8860 [ 714.173950] x19: 0000000000000001 x18: 000000000000b67e [ 714.179261] x17: 00000000064dd409 x16: ffffffd739cb28f0 [ 714.184571] x15: 0000000000000000 x14: 0000000000000227 [ 714.189881] x13: 0000000000000400 x12: ffffffd73a4eb060 [ 714.195191] x11: 0000000000000000 x10: 0000000000000000 [ 714.200502] x9 : ffffffd703a0a000 x8 : 0000000000000006 [ 714.205812] x7 : 2828282828282828 x6 : ffffffb200440396 [ 714.211122] x5 : 0000000000000000 x4 : 0000000000000004 [ 714.216432] x3 : 0000000000000000 x2 : ffffffb23b940c90 [ 714.221743] x1 : 0000000000000001 x0 : ffffffb23b940c90 [ 714.227054] Call trace: [ 714.229594] ieee80211_disconnect+0x108/0x118 [mac80211] [ 714.234913] mt7921_vif_connect_iter+0x28/0x54 [mt7921e] [ 714.240313] __iterate_interfaces+0xc4/0xdc [mac80211] [ 714.245541] ieee80211_iterate_interfaces+0x4c/0x68 [mac80211] [ 714.251381] mt7921_mac_reset_work+0x410/0x468 [mt7921e] [ 714.256696] process_one_work+0x208/0x3c8 [ 714.260706] worker_thread+0x23c/0x3e8 [ 714.264456] kthread+0x140/0x17c [ 714.267685] ret_from_fork+0x10/0x18 Fixes: 0c1ce9884607 ("mt76: mt7921: add wifi reset support") Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 70f9618eee4a..740773da2193 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1258,7 +1258,8 @@ mt7921_vif_connect_iter(void *priv, u8 *mac, struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; struct mt7921_dev *dev = mvif->phy->dev; - ieee80211_disconnect(vif, true); + if (vif->type == NL80211_IFTYPE_STATION) + ieee80211_disconnect(vif, true); mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, true); mt7921_mcu_set_tx(dev, vif); From 723885a6750102e5d807429b3d06aa6b0d29cc66 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Thu, 17 Jun 2021 09:39:19 +0800 Subject: [PATCH 091/170] mt76: mt7921: fix the coredump is being truncated Fix the maximum size of the coredump generated with current mt7921 firmware. Otherwise, a truncated coredump would be reported to userland via dev_coredumpv. Also, there is an additional error handling enhanced in the patch to avoid the possible invalid buffer access when the system failed to create the buffer to hold the coredump. Fixes: 0da3c795d07b ("mt76: mt7921: add coredump support") Co-developed-by: YN Chen Signed-off-by: YN Chen Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac.h | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 93a37ed0c483..f49d97d0a1c5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -13,7 +13,7 @@ #define MT76_CONNAC_MAX_SCAN_MATCH 16 #define MT76_CONNAC_COREDUMP_TIMEOUT (HZ / 20) -#define MT76_CONNAC_COREDUMP_SZ (128 * 1024) +#define MT76_CONNAC_COREDUMP_SZ (1300 * 1024) enum { CMD_CBW_20MHZ = IEEE80211_STA_RX_BW_20, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 740773da2193..b8e64c58b9ed 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1548,7 +1548,7 @@ void mt7921_coredump_work(struct work_struct *work) break; skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); - if (data + skb->len - dump > MT76_CONNAC_COREDUMP_SZ) { + if (!dump || data + skb->len - dump > MT76_CONNAC_COREDUMP_SZ) { dev_kfree_skb(skb); continue; } @@ -1558,7 +1558,10 @@ void mt7921_coredump_work(struct work_struct *work) dev_kfree_skb(skb); } - dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ, - GFP_KERNEL); + + if (dump) + dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ, + GFP_KERNEL); + mt7921_reset(&dev->mt76); } From c368362c36d3d4cedbc9a1c9caa95960912cc429 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Thu, 17 Jun 2021 15:17:49 +0800 Subject: [PATCH 092/170] mt76: fix iv and CCMP header insertion The iv from RXD is only for TKIP_RSC/CCMP_PN/GCMP_PN, and it needs a check for CCMP header insertion. Move mt76_cipher_type to mt76.h to reduce duplicated code. Signed-off-by: Xing Song Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 16 +++++ .../net/wireless/mediatek/mt76/mt7603/mac.c | 33 +++++++--- .../net/wireless/mediatek/mt76/mt7603/regs.h | 12 ---- .../net/wireless/mediatek/mt76/mt7615/mac.c | 64 +++++++++++++++---- .../net/wireless/mediatek/mt76/mt7615/mac.h | 42 ------------ .../net/wireless/mediatek/mt76/mt76x02_mac.c | 28 ++++---- .../net/wireless/mediatek/mt76/mt76x02_regs.h | 18 +++--- .../net/wireless/mediatek/mt76/mt7915/mac.c | 29 ++++++--- .../net/wireless/mediatek/mt76/mt7915/mcu.c | 30 ++++----- .../net/wireless/mediatek/mt76/mt7915/mcu.h | 23 ++++--- .../net/wireless/mediatek/mt76/mt7921/mac.c | 29 ++++++--- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 30 ++++----- .../net/wireless/mediatek/mt76/mt7921/mcu.h | 23 ++++--- 13 files changed, 208 insertions(+), 169 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 022e9c573ddd..25c5ceef5257 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -87,6 +87,22 @@ enum mt76_rxq_id { __MT_RXQ_MAX }; +enum mt76_cipher_type { + MT_CIPHER_NONE, + MT_CIPHER_WEP40, + MT_CIPHER_TKIP, + MT_CIPHER_TKIP_NO_MIC, + MT_CIPHER_AES_CCMP, + MT_CIPHER_WEP104, + MT_CIPHER_BIP_CMAC_128, + MT_CIPHER_WEP128, + MT_CIPHER_WAPI, + MT_CIPHER_CCMP_CCX, + MT_CIPHER_CCMP_256, + MT_CIPHER_GCMP, + MT_CIPHER_GCMP_256, +}; + struct mt76_queue_buf { dma_addr_t addr; u16 len; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index 8435e9597688..3972c56136a2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -550,14 +550,27 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb) u8 *data = (u8 *)rxd; if (status->flag & RX_FLAG_DECRYPTED) { - status->iv[0] = data[5]; - status->iv[1] = data[4]; - status->iv[2] = data[3]; - status->iv[3] = data[2]; - status->iv[4] = data[1]; - status->iv[5] = data[0]; - - insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) { + case MT_CIPHER_AES_CCMP: + case MT_CIPHER_CCMP_CCX: + case MT_CIPHER_CCMP_256: + insert_ccmp_hdr = + FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + fallthrough; + case MT_CIPHER_TKIP: + case MT_CIPHER_TKIP_NO_MIC: + case MT_CIPHER_GCMP: + case MT_CIPHER_GCMP_256: + status->iv[0] = data[5]; + status->iv[1] = data[4]; + status->iv[2] = data[3]; + status->iv[3] = data[2]; + status->iv[4] = data[1]; + status->iv[5] = data[0]; + break; + default: + break; + } } rxd += 4; @@ -831,7 +844,7 @@ void mt7603_wtbl_set_rates(struct mt7603_dev *dev, struct mt7603_sta *sta, sta->wcid.tx_info |= MT_WCID_TX_INFO_SET; } -static enum mt7603_cipher_type +static enum mt76_cipher_type mt7603_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) { memset(key_data, 0, 32); @@ -863,7 +876,7 @@ mt7603_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) int mt7603_wtbl_set_key(struct mt7603_dev *dev, int wcid, struct ieee80211_key_conf *key) { - enum mt7603_cipher_type cipher; + enum mt76_cipher_type cipher; u32 addr = mt7603_wtbl3_addr(wcid); u8 key_data[32]; int key_len = sizeof(key_data); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/regs.h b/drivers/net/wireless/mediatek/mt76/mt7603/regs.h index 6741e6907194..3b901090b29c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/regs.h @@ -765,16 +765,4 @@ enum { #define MT_WTBL1_OR (MT_WTBL1_BASE + 0x2300) #define MT_WTBL1_OR_PSM_WRITE BIT(31) -enum mt7603_cipher_type { - MT_CIPHER_NONE, - MT_CIPHER_WEP40, - MT_CIPHER_TKIP, - MT_CIPHER_TKIP_NO_MIC, - MT_CIPHER_AES_CCMP, - MT_CIPHER_WEP104, - MT_CIPHER_BIP_CMAC_128, - MT_CIPHER_WEP128, - MT_CIPHER_WAPI, -}; - #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index a057859aa050..f41fbb641e87 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -57,6 +57,33 @@ static const struct mt7615_dfs_radar_spec jp_radar_specs = { }, }; +static enum mt76_cipher_type +mt7615_mac_get_cipher(int cipher) +{ + switch (cipher) { + case WLAN_CIPHER_SUITE_WEP40: + return MT_CIPHER_WEP40; + case WLAN_CIPHER_SUITE_WEP104: + return MT_CIPHER_WEP104; + case WLAN_CIPHER_SUITE_TKIP: + return MT_CIPHER_TKIP; + case WLAN_CIPHER_SUITE_AES_CMAC: + return MT_CIPHER_BIP_CMAC_128; + case WLAN_CIPHER_SUITE_CCMP: + return MT_CIPHER_AES_CCMP; + case WLAN_CIPHER_SUITE_CCMP_256: + return MT_CIPHER_CCMP_256; + case WLAN_CIPHER_SUITE_GCMP: + return MT_CIPHER_GCMP; + case WLAN_CIPHER_SUITE_GCMP_256: + return MT_CIPHER_GCMP_256; + case WLAN_CIPHER_SUITE_SMS4: + return MT_CIPHER_WAPI; + default: + return MT_CIPHER_NONE; + } +} + static struct mt76_wcid *mt7615_rx_get_wcid(struct mt7615_dev *dev, u8 idx, bool unicast) { @@ -313,14 +340,27 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) u8 *data = (u8 *)rxd; if (status->flag & RX_FLAG_DECRYPTED) { - status->iv[0] = data[5]; - status->iv[1] = data[4]; - status->iv[2] = data[3]; - status->iv[3] = data[2]; - status->iv[4] = data[1]; - status->iv[5] = data[0]; - - insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) { + case MT_CIPHER_AES_CCMP: + case MT_CIPHER_CCMP_CCX: + case MT_CIPHER_CCMP_256: + insert_ccmp_hdr = + FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + fallthrough; + case MT_CIPHER_TKIP: + case MT_CIPHER_TKIP_NO_MIC: + case MT_CIPHER_GCMP: + case MT_CIPHER_GCMP_256: + status->iv[0] = data[5]; + status->iv[1] = data[4]; + status->iv[2] = data[3]; + status->iv[3] = data[2]; + status->iv[4] = data[1]; + status->iv[5] = data[0]; + break; + default: + break; + } } rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) @@ -1078,7 +1118,7 @@ EXPORT_SYMBOL_GPL(mt7615_mac_set_rates); static int mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, - enum mt7615_cipher_type cipher, u16 cipher_mask, + enum mt76_cipher_type cipher, u16 cipher_mask, enum set_key_cmd cmd) { u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx) + 30 * 4; @@ -1118,7 +1158,7 @@ mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, static int mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid, - enum mt7615_cipher_type cipher, u16 cipher_mask, + enum mt76_cipher_type cipher, u16 cipher_mask, int keyidx, enum set_key_cmd cmd) { u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx), w0, w1; @@ -1157,7 +1197,7 @@ mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid, static void mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev, struct mt76_wcid *wcid, - enum mt7615_cipher_type cipher, u16 cipher_mask, + enum mt76_cipher_type cipher, u16 cipher_mask, enum set_key_cmd cmd) { u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx); @@ -1183,7 +1223,7 @@ int __mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct ieee80211_key_conf *key, enum set_key_cmd cmd) { - enum mt7615_cipher_type cipher; + enum mt76_cipher_type cipher; u16 cipher_mask = wcid->cipher; int err; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h index 6bf9da040196..46f283eb8d0f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h @@ -383,48 +383,6 @@ struct mt7615_dfs_radar_spec { struct mt7615_dfs_pattern radar_pattern[16]; }; -enum mt7615_cipher_type { - MT_CIPHER_NONE, - MT_CIPHER_WEP40, - MT_CIPHER_TKIP, - MT_CIPHER_TKIP_NO_MIC, - MT_CIPHER_AES_CCMP, - MT_CIPHER_WEP104, - MT_CIPHER_BIP_CMAC_128, - MT_CIPHER_WEP128, - MT_CIPHER_WAPI, - MT_CIPHER_CCMP_256 = 10, - MT_CIPHER_GCMP, - MT_CIPHER_GCMP_256, -}; - -static inline enum mt7615_cipher_type -mt7615_mac_get_cipher(int cipher) -{ - switch (cipher) { - case WLAN_CIPHER_SUITE_WEP40: - return MT_CIPHER_WEP40; - case WLAN_CIPHER_SUITE_WEP104: - return MT_CIPHER_WEP104; - case WLAN_CIPHER_SUITE_TKIP: - return MT_CIPHER_TKIP; - case WLAN_CIPHER_SUITE_AES_CMAC: - return MT_CIPHER_BIP_CMAC_128; - case WLAN_CIPHER_SUITE_CCMP: - return MT_CIPHER_AES_CCMP; - case WLAN_CIPHER_SUITE_CCMP_256: - return MT_CIPHER_CCMP_256; - case WLAN_CIPHER_SUITE_GCMP: - return MT_CIPHER_GCMP; - case WLAN_CIPHER_SUITE_GCMP_256: - return MT_CIPHER_GCMP_256; - case WLAN_CIPHER_SUITE_SMS4: - return MT_CIPHER_WAPI; - default: - return MT_CIPHER_NONE; - } -} - static inline struct mt7615_txp_common * mt7615_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 7572c793aa51..c32e6dc68773 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -34,24 +34,24 @@ mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) { memset(key_data, 0, 32); if (!key) - return MT_CIPHER_NONE; + return MT76X02_CIPHER_NONE; if (key->keylen > 32) - return MT_CIPHER_NONE; + return MT76X02_CIPHER_NONE; memcpy(key_data, key->key, key->keylen); switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: - return MT_CIPHER_WEP40; + return MT76X02_CIPHER_WEP40; case WLAN_CIPHER_SUITE_WEP104: - return MT_CIPHER_WEP104; + return MT76X02_CIPHER_WEP104; case WLAN_CIPHER_SUITE_TKIP: - return MT_CIPHER_TKIP; + return MT76X02_CIPHER_TKIP; case WLAN_CIPHER_SUITE_CCMP: - return MT_CIPHER_AES_CCMP; + return MT76X02_CIPHER_AES_CCMP; default: - return MT_CIPHER_NONE; + return MT76X02_CIPHER_NONE; } } @@ -63,7 +63,7 @@ int mt76x02_mac_shared_key_setup(struct mt76x02_dev *dev, u8 vif_idx, u32 val; cipher = mt76x02_mac_get_key_info(key, key_data); - if (cipher == MT_CIPHER_NONE && key) + if (cipher == MT76X02_CIPHER_NONE && key) return -EOPNOTSUPP; val = mt76_rr(dev, MT_SKEY_MODE(vif_idx)); @@ -91,10 +91,10 @@ void mt76x02_mac_wcid_sync_pn(struct mt76x02_dev *dev, u8 idx, eiv = mt76_rr(dev, MT_WCID_IV(idx) + 4); pn = (u64)eiv << 16; - if (cipher == MT_CIPHER_TKIP) { + if (cipher == MT76X02_CIPHER_TKIP) { pn |= (iv >> 16) & 0xff; pn |= (iv & 0xff) << 8; - } else if (cipher >= MT_CIPHER_AES_CCMP) { + } else if (cipher >= MT76X02_CIPHER_AES_CCMP) { pn |= iv & 0xffff; } else { return; @@ -112,7 +112,7 @@ int mt76x02_mac_wcid_set_key(struct mt76x02_dev *dev, u8 idx, u64 pn; cipher = mt76x02_mac_get_key_info(key, key_data); - if (cipher == MT_CIPHER_NONE && key) + if (cipher == MT76X02_CIPHER_NONE && key) return -EOPNOTSUPP; mt76_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data)); @@ -126,16 +126,16 @@ int mt76x02_mac_wcid_set_key(struct mt76x02_dev *dev, u8 idx, pn = atomic64_read(&key->tx_pn); iv_data[3] = key->keyidx << 6; - if (cipher >= MT_CIPHER_TKIP) { + if (cipher >= MT76X02_CIPHER_TKIP) { iv_data[3] |= 0x20; put_unaligned_le32(pn >> 16, &iv_data[4]); } - if (cipher == MT_CIPHER_TKIP) { + if (cipher == MT76X02_CIPHER_TKIP) { iv_data[0] = (pn >> 8) & 0xff; iv_data[1] = (iv_data[0] | 0x20) & 0x7f; iv_data[2] = pn & 0xff; - } else if (cipher >= MT_CIPHER_AES_CCMP) { + } else if (cipher >= MT76X02_CIPHER_AES_CCMP) { put_unaligned_le16((pn & 0xffff), &iv_data[0]); } } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h index 3e722276b5c2..fa7872ac22bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h @@ -692,15 +692,15 @@ struct mt76_wcid_key { } __packed __aligned(4); enum mt76x02_cipher_type { - MT_CIPHER_NONE, - MT_CIPHER_WEP40, - MT_CIPHER_WEP104, - MT_CIPHER_TKIP, - MT_CIPHER_AES_CCMP, - MT_CIPHER_CKIP40, - MT_CIPHER_CKIP104, - MT_CIPHER_CKIP128, - MT_CIPHER_WAPI, + MT76X02_CIPHER_NONE, + MT76X02_CIPHER_WEP40, + MT76X02_CIPHER_WEP104, + MT76X02_CIPHER_TKIP, + MT76X02_CIPHER_AES_CCMP, + MT76X02_CIPHER_CKIP40, + MT76X02_CIPHER_CKIP104, + MT76X02_CIPHER_CKIP128, + MT76X02_CIPHER_WAPI, }; #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index c093c13bf1f1..2462704094b0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -413,14 +413,27 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) u8 *data = (u8 *)rxd; if (status->flag & RX_FLAG_DECRYPTED) { - status->iv[0] = data[5]; - status->iv[1] = data[4]; - status->iv[2] = data[3]; - status->iv[3] = data[2]; - status->iv[4] = data[1]; - status->iv[5] = data[0]; - - insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + switch (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1)) { + case MT_CIPHER_AES_CCMP: + case MT_CIPHER_CCMP_CCX: + case MT_CIPHER_CCMP_256: + insert_ccmp_hdr = + FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + fallthrough; + case MT_CIPHER_TKIP: + case MT_CIPHER_TKIP_NO_MIC: + case MT_CIPHER_GCMP: + case MT_CIPHER_GCMP_256: + status->iv[0] = data[5]; + status->iv[1] = data[4]; + status->iv[2] = data[3]; + status->iv[3] = data[2]; + status->iv[4] = data[1]; + status->iv[5] = data[0]; + break; + default: + break; + } } rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index b565024404cf..863aa18b3024 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -88,28 +88,28 @@ struct mt7915_fw_region { #define HE_PHY(p, c) u8_get_bits(c, IEEE80211_HE_PHY_##p) #define HE_MAC(m, c) u8_get_bits(c, IEEE80211_HE_MAC_##m) -static enum mt7915_cipher_type +static enum mcu_cipher_type mt7915_mcu_get_cipher(int cipher) { switch (cipher) { case WLAN_CIPHER_SUITE_WEP40: - return MT_CIPHER_WEP40; + return MCU_CIPHER_WEP40; case WLAN_CIPHER_SUITE_WEP104: - return MT_CIPHER_WEP104; + return MCU_CIPHER_WEP104; case WLAN_CIPHER_SUITE_TKIP: - return MT_CIPHER_TKIP; + return MCU_CIPHER_TKIP; case WLAN_CIPHER_SUITE_AES_CMAC: - return MT_CIPHER_BIP_CMAC_128; + return MCU_CIPHER_BIP_CMAC_128; case WLAN_CIPHER_SUITE_CCMP: - return MT_CIPHER_AES_CCMP; + return MCU_CIPHER_AES_CCMP; case WLAN_CIPHER_SUITE_CCMP_256: - return MT_CIPHER_CCMP_256; + return MCU_CIPHER_CCMP_256; case WLAN_CIPHER_SUITE_GCMP: - return MT_CIPHER_GCMP; + return MCU_CIPHER_GCMP; case WLAN_CIPHER_SUITE_GCMP_256: - return MT_CIPHER_GCMP_256; + return MCU_CIPHER_GCMP_256; case WLAN_CIPHER_SUITE_SMS4: - return MT_CIPHER_WAPI; + return MCU_CIPHER_WAPI; default: return MT_CIPHER_NONE; } @@ -1207,14 +1207,14 @@ mt7915_mcu_sta_key_tlv(struct mt7915_sta *msta, struct sk_buff *skb, sec_key = &sec->key[0]; sec_key->cipher_len = sizeof(*sec_key); - if (cipher == MT_CIPHER_BIP_CMAC_128) { - sec_key->cipher_id = MT_CIPHER_AES_CCMP; + if (cipher == MCU_CIPHER_BIP_CMAC_128) { + sec_key->cipher_id = MCU_CIPHER_AES_CCMP; sec_key->key_id = bip->keyidx; sec_key->key_len = 16; memcpy(sec_key->key, bip->key, 16); sec_key = &sec->key[1]; - sec_key->cipher_id = MT_CIPHER_BIP_CMAC_128; + sec_key->cipher_id = MCU_CIPHER_BIP_CMAC_128; sec_key->cipher_len = sizeof(*sec_key); sec_key->key_len = 16; memcpy(sec_key->key, key->key, 16); @@ -1226,14 +1226,14 @@ mt7915_mcu_sta_key_tlv(struct mt7915_sta *msta, struct sk_buff *skb, sec_key->key_len = key->keylen; memcpy(sec_key->key, key->key, key->keylen); - if (cipher == MT_CIPHER_TKIP) { + if (cipher == MCU_CIPHER_TKIP) { /* Rx/Tx MIC keys are swapped */ memcpy(sec_key->key + 16, key->key + 24, 8); memcpy(sec_key->key + 24, key->key + 16, 8); } /* store key_conf for BIP batch update */ - if (cipher == MT_CIPHER_AES_CCMP) { + if (cipher == MCU_CIPHER_AES_CCMP) { memcpy(bip->key, key->key, key->keylen); bip->keyidx = key->keyidx; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 9087a7771c35..edd3ba3a0c2d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -1072,18 +1072,17 @@ enum { STA_REC_MAX_NUM }; -enum mt7915_cipher_type { - MT_CIPHER_NONE, - MT_CIPHER_WEP40, - MT_CIPHER_WEP104, - MT_CIPHER_WEP128, - MT_CIPHER_TKIP, - MT_CIPHER_AES_CCMP, - MT_CIPHER_CCMP_256, - MT_CIPHER_GCMP, - MT_CIPHER_GCMP_256, - MT_CIPHER_WAPI, - MT_CIPHER_BIP_CMAC_128, +enum mcu_cipher_type { + MCU_CIPHER_WEP40 = 1, + MCU_CIPHER_WEP104, + MCU_CIPHER_WEP128, + MCU_CIPHER_TKIP, + MCU_CIPHER_AES_CCMP, + MCU_CIPHER_CCMP_256, + MCU_CIPHER_GCMP, + MCU_CIPHER_GCMP_256, + MCU_CIPHER_WAPI, + MCU_CIPHER_BIP_CMAC_128, }; enum { diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index b8e64c58b9ed..143dae97ef77 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -403,14 +403,27 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) u8 *data = (u8 *)rxd; if (status->flag & RX_FLAG_DECRYPTED) { - status->iv[0] = data[5]; - status->iv[1] = data[4]; - status->iv[2] = data[3]; - status->iv[3] = data[2]; - status->iv[4] = data[1]; - status->iv[5] = data[0]; - - insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + switch (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1)) { + case MT_CIPHER_AES_CCMP: + case MT_CIPHER_CCMP_CCX: + case MT_CIPHER_CCMP_256: + insert_ccmp_hdr = + FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + fallthrough; + case MT_CIPHER_TKIP: + case MT_CIPHER_TKIP_NO_MIC: + case MT_CIPHER_GCMP: + case MT_CIPHER_GCMP_256: + status->iv[0] = data[5]; + status->iv[1] = data[4]; + status->iv[2] = data[3]; + status->iv[3] = data[2]; + status->iv[4] = data[1]; + status->iv[5] = data[0]; + break; + default: + break; + } } rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 23ec0c816d64..c2c4dc196802 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -88,28 +88,28 @@ struct mt7921_fw_region { #define to_wcid_lo(id) FIELD_GET(GENMASK(7, 0), (u16)id) #define to_wcid_hi(id) FIELD_GET(GENMASK(9, 8), (u16)id) -static enum mt7921_cipher_type +static enum mcu_cipher_type mt7921_mcu_get_cipher(int cipher) { switch (cipher) { case WLAN_CIPHER_SUITE_WEP40: - return MT_CIPHER_WEP40; + return MCU_CIPHER_WEP40; case WLAN_CIPHER_SUITE_WEP104: - return MT_CIPHER_WEP104; + return MCU_CIPHER_WEP104; case WLAN_CIPHER_SUITE_TKIP: - return MT_CIPHER_TKIP; + return MCU_CIPHER_TKIP; case WLAN_CIPHER_SUITE_AES_CMAC: - return MT_CIPHER_BIP_CMAC_128; + return MCU_CIPHER_BIP_CMAC_128; case WLAN_CIPHER_SUITE_CCMP: - return MT_CIPHER_AES_CCMP; + return MCU_CIPHER_AES_CCMP; case WLAN_CIPHER_SUITE_CCMP_256: - return MT_CIPHER_CCMP_256; + return MCU_CIPHER_CCMP_256; case WLAN_CIPHER_SUITE_GCMP: - return MT_CIPHER_GCMP; + return MCU_CIPHER_GCMP; case WLAN_CIPHER_SUITE_GCMP_256: - return MT_CIPHER_GCMP_256; + return MCU_CIPHER_GCMP_256; case WLAN_CIPHER_SUITE_SMS4: - return MT_CIPHER_WAPI; + return MCU_CIPHER_WAPI; default: return MT_CIPHER_NONE; } @@ -625,14 +625,14 @@ mt7921_mcu_sta_key_tlv(struct mt7921_sta *msta, struct sk_buff *skb, sec_key = &sec->key[0]; sec_key->cipher_len = sizeof(*sec_key); - if (cipher == MT_CIPHER_BIP_CMAC_128) { - sec_key->cipher_id = MT_CIPHER_AES_CCMP; + if (cipher == MCU_CIPHER_BIP_CMAC_128) { + sec_key->cipher_id = MCU_CIPHER_AES_CCMP; sec_key->key_id = bip->keyidx; sec_key->key_len = 16; memcpy(sec_key->key, bip->key, 16); sec_key = &sec->key[1]; - sec_key->cipher_id = MT_CIPHER_BIP_CMAC_128; + sec_key->cipher_id = MCU_CIPHER_BIP_CMAC_128; sec_key->cipher_len = sizeof(*sec_key); sec_key->key_len = 16; memcpy(sec_key->key, key->key, 16); @@ -644,14 +644,14 @@ mt7921_mcu_sta_key_tlv(struct mt7921_sta *msta, struct sk_buff *skb, sec_key->key_len = key->keylen; memcpy(sec_key->key, key->key, key->keylen); - if (cipher == MT_CIPHER_TKIP) { + if (cipher == MCU_CIPHER_TKIP) { /* Rx/Tx MIC keys are swapped */ memcpy(sec_key->key + 16, key->key + 24, 8); memcpy(sec_key->key + 24, key->key + 16, 8); } /* store key_conf for BIP batch update */ - if (cipher == MT_CIPHER_AES_CCMP) { + if (cipher == MCU_CIPHER_AES_CCMP) { memcpy(bip->key, key->key, key->keylen); bip->keyidx = key->keyidx; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h index 89fed2f71161..d76cf8f8dfdf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h @@ -198,18 +198,17 @@ struct sta_rec_sec { struct sec_key key[2]; } __packed; -enum mt7921_cipher_type { - MT_CIPHER_NONE, - MT_CIPHER_WEP40, - MT_CIPHER_WEP104, - MT_CIPHER_WEP128, - MT_CIPHER_TKIP, - MT_CIPHER_AES_CCMP, - MT_CIPHER_CCMP_256, - MT_CIPHER_GCMP, - MT_CIPHER_GCMP_256, - MT_CIPHER_WAPI, - MT_CIPHER_BIP_CMAC_128, +enum mcu_cipher_type { + MCU_CIPHER_WEP40 = 1, + MCU_CIPHER_WEP104, + MCU_CIPHER_WEP128, + MCU_CIPHER_TKIP, + MCU_CIPHER_AES_CCMP, + MCU_CIPHER_CCMP_256, + MCU_CIPHER_GCMP, + MCU_CIPHER_GCMP_256, + MCU_CIPHER_WAPI, + MCU_CIPHER_BIP_CMAC_128, }; enum { From 5512c974437c6b9d2be9c9e723b7dfc21c32a5f8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 17 Jun 2021 13:02:09 +0200 Subject: [PATCH 093/170] mt76: disable TWT capabilities for the moment Disable TWT REQ/RES mac capabilities since TWT is not supported yet in mt7915/mt7921. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 4 ---- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 2 -- 2 files changed, 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 7af1cdbbfebd..4798d6344305 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -667,8 +667,6 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, switch (i) { case NL80211_IFTYPE_AP: - he_cap_elem->mac_cap_info[0] |= - IEEE80211_HE_MAC_CAP0_TWT_RES; he_cap_elem->mac_cap_info[2] |= IEEE80211_HE_MAC_CAP2_BSR; he_cap_elem->mac_cap_info[4] |= @@ -682,8 +680,6 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; break; case NL80211_IFTYPE_STATION: - he_cap_elem->mac_cap_info[0] |= - IEEE80211_HE_MAC_CAP0_TWT_REQ; he_cap_elem->mac_cap_info[1] |= IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 0fb152ac4d87..45aefa3132ae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -84,8 +84,6 @@ mt7921_init_he_caps(struct mt7921_phy *phy, enum nl80211_band band, switch (i) { case NL80211_IFTYPE_STATION: - he_cap_elem->mac_cap_info[0] |= - IEEE80211_HE_MAC_CAP0_TWT_REQ; he_cap_elem->mac_cap_info[1] |= IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US; From 1153668eefca6860dba3a6e94f24bf7146d62d50 Mon Sep 17 00:00:00 2001 From: Deren Wu Date: Thu, 17 Jun 2021 22:38:25 +0800 Subject: [PATCH 094/170] mt76: mt7921: enable HE BFee capability Enables HE MU/SU beamformee functionality Signed-off-by: Eric-SY Chang Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 45aefa3132ae..7fd21049ff5a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -79,8 +79,11 @@ mt7921_init_he_caps(struct mt7921_phy *phy, enum nl80211_band band, he_cap_elem->phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD; he_cap_elem->phy_cap_info[2] = + IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | - IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ; + IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | + IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | + IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO; switch (i) { case NL80211_IFTYPE_STATION: @@ -100,7 +103,15 @@ mt7921_init_he_caps(struct mt7921_phy *phy, enum nl80211_band band, he_cap_elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK | IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK; + he_cap_elem->phy_cap_info[4] |= + IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4; + he_cap_elem->phy_cap_info[5] |= + IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK | + IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK; he_cap_elem->phy_cap_info[6] |= + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU | IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB | IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE | IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; From aac5104bf631e27032944346a526533b106506d5 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 18 Jun 2021 10:08:20 +0200 Subject: [PATCH 095/170] mt76: sdio: do not run mt76_txq_schedule directly In order to support runtime-pm for sdio, do not run mt76_txq_schedule directly, but schedule tx_worker instead Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/sdio.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c index 1665fe88ebb8..783a15635ec5 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/sdio.c @@ -184,9 +184,6 @@ static int mt76s_process_tx_queue(struct mt76_dev *dev, struct mt76_queue *q) if (!q->queued) wake_up(&dev->tx_wait); - if (!mcu) - mt76_txq_schedule(&dev->phy, q->qid); - return nframes; } @@ -195,19 +192,28 @@ static void mt76s_status_worker(struct mt76_worker *w) struct mt76_sdio *sdio = container_of(w, struct mt76_sdio, status_worker); struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio); + bool resched = false; int i, nframes; do { + int ndata_frames = 0; + nframes = mt76s_process_tx_queue(dev, dev->q_mcu[MT_MCUQ_WM]); for (i = 0; i <= MT_TXQ_PSD; i++) - nframes += mt76s_process_tx_queue(dev, - dev->phy.q_tx[i]); + ndata_frames += mt76s_process_tx_queue(dev, + dev->phy.q_tx[i]); + nframes += ndata_frames; + if (ndata_frames > 0) + resched = true; if (dev->drv->tx_status_data && !test_and_set_bit(MT76_READING_STATS, &dev->phy.state)) queue_work(dev->wq, &dev->sdio.stat_work); } while (nframes > 0); + + if (resched) + mt76_worker_schedule(&dev->sdio.txrx_worker); } static void mt76s_tx_status_data(struct work_struct *work) From 50a97efe218e848e26b7fd4d09fb6d9f88f90e6e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 18 Jun 2021 10:08:21 +0200 Subject: [PATCH 096/170] mt76: mt7663s: rely on pm reference counting As already done for mt7921 and mt7663e, rely on pm reference counting in drv/fw_own Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7615/sdio_mcu.c | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c index d1be78b0711c..6c23c6dbf1c6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c @@ -55,6 +55,7 @@ static int __mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev) { struct sdio_func *func = dev->mt76.sdio.func; struct mt76_phy *mphy = &dev->mt76.phy; + struct mt76_connac_pm *pm = &dev->pm; u32 status; int ret; @@ -64,39 +65,44 @@ static int __mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev) ret = readx_poll_timeout(mt7663s_read_pcr, dev, status, status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000); - if (ret < 0) { + if (ret < 0) dev_err(dev->mt76.dev, "Cannot get ownership from device"); - set_bit(MT76_STATE_PM, &mphy->state); - sdio_release_host(func); - - return ret; - } + else + clear_bit(MT76_STATE_PM, &mphy->state); sdio_release_host(func); - dev->pm.last_activity = jiffies; + pm->last_activity = jiffies; - return 0; + return ret; } static int mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev) { struct mt76_phy *mphy = &dev->mt76.phy; + int ret = 0; - if (test_and_clear_bit(MT76_STATE_PM, &mphy->state)) - return __mt7663s_mcu_drv_pmctrl(dev); + mutex_lock(&dev->pm.mutex); - return 0; + if (test_bit(MT76_STATE_PM, &mphy->state)) + ret = __mt7663s_mcu_drv_pmctrl(dev); + + mutex_unlock(&dev->pm.mutex); + + return ret; } static int mt7663s_mcu_fw_pmctrl(struct mt7615_dev *dev) { struct sdio_func *func = dev->mt76.sdio.func; struct mt76_phy *mphy = &dev->mt76.phy; + struct mt76_connac_pm *pm = &dev->pm; + int ret = 0; u32 status; - int ret; - if (test_and_set_bit(MT76_STATE_PM, &mphy->state)) - return 0; + mutex_lock(&pm->mutex); + + if (mt76_connac_skip_fw_pmctrl(mphy, pm)) + goto out; sdio_claim_host(func); @@ -110,6 +116,8 @@ static int mt7663s_mcu_fw_pmctrl(struct mt7615_dev *dev) } sdio_release_host(func); +out: + mutex_unlock(&pm->mutex); return ret; } From c2f9e631f098caf7176cbabda7a9cc2721352ff2 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 18 Jun 2021 10:08:22 +0200 Subject: [PATCH 097/170] mt76: mt7663s: rely on mt76_connac_pm_ref/mt76_connac_pm_unref in tx path Similar to mt7663e, rely on mt76_connac_pm_ref/mt76_connac_pm_unref to check PM state and increment/decrement wake counter Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 14 ++++++++++---- .../wireless/mediatek/mt76/mt7615/sdio_txrx.c | 16 ++++++++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index f41fbb641e87..bd0d18914994 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1942,12 +1942,18 @@ void mt7615_pm_wake_work(struct work_struct *work) mphy = dev->phy.mt76; if (!mt7615_mcu_set_drv_ctrl(dev)) { + struct mt76_dev *mdev = &dev->mt76; int i; - mt76_for_each_q_rx(&dev->mt76, i) - napi_schedule(&dev->mt76.napi[i]); - mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); - mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false); + if (mt76_is_sdio(mdev)) { + mt76_worker_schedule(&mdev->sdio.txrx_worker); + } else { + mt76_for_each_q_rx(mdev, i) + napi_schedule(&mdev->napi[i]); + mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); + mt76_queue_tx_cleanup(dev, mdev->q_mcu[MT_MCUQ_WM], + false); + } if (test_bit(MT76_STATE_RUNNING, &mphy->state)) ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, MT7615_WATCHDOG_TIME); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c index 4393dd21ebbb..04f4c89b7499 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c @@ -283,9 +283,15 @@ void mt7663s_txrx_worker(struct mt76_worker *w) { struct mt76_sdio *sdio = container_of(w, struct mt76_sdio, txrx_worker); - struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio); + struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio); + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); int i, nframes, ret; + if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) { + queue_work(mdev->wq, &dev->pm.wake_work); + return; + } + /* disable interrupt */ sdio_claim_host(sdio->func); sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL); @@ -295,16 +301,16 @@ void mt7663s_txrx_worker(struct mt76_worker *w) /* tx */ for (i = 0; i <= MT_TXQ_PSD; i++) { - ret = mt7663s_tx_run_queue(dev, dev->phy.q_tx[i]); + ret = mt7663s_tx_run_queue(mdev, mdev->phy.q_tx[i]); if (ret > 0) nframes += ret; } - ret = mt7663s_tx_run_queue(dev, dev->q_mcu[MT_MCUQ_WM]); + ret = mt7663s_tx_run_queue(mdev, mdev->q_mcu[MT_MCUQ_WM]); if (ret > 0) nframes += ret; /* rx */ - ret = mt7663s_rx_handler(dev); + ret = mt7663s_rx_handler(mdev); if (ret > 0) nframes += ret; } while (nframes > 0); @@ -312,6 +318,8 @@ void mt7663s_txrx_worker(struct mt76_worker *w) /* enable interrupt */ sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL); sdio_release_host(sdio->func); + + mt76_connac_pm_unref(&dev->mphy, &dev->pm); } void mt7663s_sdio_irq(struct sdio_func *func) From 8aff2d915d7f434582d6e840535f19a88a8c71ab Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 18 Jun 2021 10:08:23 +0200 Subject: [PATCH 098/170] mt76: mt7663s: enable runtime-pm Allow the user to enable runtime-pm for mt7663s driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c | 2 +- .../net/wireless/mediatek/mt76/mt7615/sdio_mcu.c | 13 ++++++++++--- .../net/wireless/mediatek/mt76/mt76_connac_mac.c | 4 ++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index 8cb4426e757c..cb4659771fd9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -75,7 +75,7 @@ mt7615_pm_set(void *data, u64 val) if (!mt7615_wait_for_mcu_init(dev)) return 0; - if (!mt7615_firmware_offload(dev) || !mt76_is_mmio(&dev->mt76)) + if (!mt7615_firmware_offload(dev) || mt76_is_usb(&dev->mt76)) return -EOPNOTSUPP; if (val == pm->enable) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c index 6c23c6dbf1c6..45c1cd3b9f49 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c @@ -65,13 +65,16 @@ static int __mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev) ret = readx_poll_timeout(mt7663s_read_pcr, dev, status, status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000); - if (ret < 0) + if (ret < 0) { dev_err(dev->mt76.dev, "Cannot get ownership from device"); - else + } else { clear_bit(MT76_STATE_PM, &mphy->state); + pm->stats.last_wake_event = jiffies; + pm->stats.doze_time += pm->stats.last_wake_event - + pm->stats.last_doze_event; + } sdio_release_host(func); - pm->last_activity = jiffies; return ret; } @@ -113,6 +116,10 @@ static int mt7663s_mcu_fw_pmctrl(struct mt7615_dev *dev) if (ret < 0) { dev_err(dev->mt76.dev, "Cannot set ownership to device"); clear_bit(MT76_STATE_PM, &mphy->state); + } else { + pm->stats.last_doze_event = jiffies; + pm->stats.awake_time += pm->stats.last_doze_event - + pm->stats.last_wake_event; } sdio_release_host(func); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 5f2705fbd680..af43bcb54578 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -10,7 +10,7 @@ int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm) if (!pm->enable) return 0; - if (!mt76_is_mmio(dev)) + if (mt76_is_usb(dev)) return 0; cancel_delayed_work_sync(&pm->ps_work); @@ -37,7 +37,7 @@ void mt76_connac_power_save_sched(struct mt76_phy *phy, { struct mt76_dev *dev = phy->dev; - if (!mt76_is_mmio(dev)) + if (mt76_is_usb(dev)) return; if (!pm->enable) From a27238a0488e14b2e558053b8b8a9a501e9385c6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 18 Jun 2021 10:08:24 +0200 Subject: [PATCH 099/170] mt76: mt7615: set macwork timeout according to runtime-pm Set macwork timeout value according to runtime-pm in order to reduce power consumption Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7615/mac.c | 15 +++++++++++---- .../net/wireless/mediatek/mt76/mt7615/main.c | 18 +++++++++++------- .../net/wireless/mediatek/mt76/mt7615/mt7615.h | 7 ++++++- .../wireless/mediatek/mt76/mt7615/pci_mac.c | 7 ++++--- 4 files changed, 32 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index bd0d18914994..ff3f85e4087c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1954,9 +1954,14 @@ void mt7615_pm_wake_work(struct work_struct *work) mt76_queue_tx_cleanup(dev, mdev->q_mcu[MT_MCUQ_WM], false); } - if (test_bit(MT76_STATE_RUNNING, &mphy->state)) + + if (test_bit(MT76_STATE_RUNNING, &mphy->state)) { + unsigned long timeout; + + timeout = mt7615_get_macwork_timeout(dev); ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, - MT7615_WATCHDOG_TIME); + timeout); + } } ieee80211_wake_queues(mphy->hw); @@ -1991,6 +1996,7 @@ void mt7615_mac_work(struct work_struct *work) { struct mt7615_phy *phy; struct mt76_phy *mphy; + unsigned long timeout; mphy = (struct mt76_phy *)container_of(work, struct mt76_phy, mac_work.work); @@ -2009,8 +2015,9 @@ void mt7615_mac_work(struct work_struct *work) mt7615_mutex_release(phy->dev); mt76_tx_status_check(mphy->dev, NULL, false); - ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, - MT7615_WATCHDOG_TIME); + + timeout = mt7615_get_macwork_timeout(phy->dev); + ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, timeout); } void mt7615_tx_token_put(struct mt7615_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index bd2f42ef5ad7..dada43d6d879 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -28,6 +28,7 @@ static int mt7615_start(struct ieee80211_hw *hw) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); + unsigned long timeout; bool running; int ret; @@ -78,8 +79,8 @@ static int mt7615_start(struct ieee80211_hw *hw) set_bit(MT76_STATE_RUNNING, &phy->mt76->state); - ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, - MT7615_WATCHDOG_TIME); + timeout = mt7615_get_macwork_timeout(dev); + ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, timeout); if (!running) mt7615_mac_reset_counters(dev); @@ -350,10 +351,12 @@ out: mt7615_mutex_release(dev); mt76_worker_schedule(&dev->mt76.tx_worker); - if (!mt76_testmode_enabled(phy->mt76)) + if (!mt76_testmode_enabled(phy->mt76)) { + unsigned long timeout = mt7615_get_macwork_timeout(dev); + ieee80211_queue_delayed_work(phy->mt76->hw, - &phy->mt76->mac_work, - MT7615_WATCHDOG_TIME); + &phy->mt76->mac_work, timeout); + } return ret; } @@ -1225,6 +1228,7 @@ static int mt7615_resume(struct ieee80211_hw *hw) { struct mt7615_phy *phy = mt7615_hw_phy(hw); struct mt7615_dev *dev = mt7615_hw_dev(hw); + unsigned long timeout; bool running; mt7615_mutex_acquire(dev); @@ -1248,8 +1252,8 @@ static int mt7615_resume(struct ieee80211_hw *hw) mt76_connac_mcu_set_suspend_iter, phy->mt76); - ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, - MT7615_WATCHDOG_TIME); + timeout = mt7615_get_macwork_timeout(dev); + ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, timeout); mt7615_mutex_release(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 8fbaf8356e1a..d0c64a9b09cf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -20,7 +20,6 @@ MT7615_MAX_INTERFACES) #define MT7615_PM_TIMEOUT (HZ / 12) -#define MT7615_WATCHDOG_TIME (HZ / 10) #define MT7615_HW_SCAN_TIMEOUT (HZ / 10) #define MT7615_RESET_TIMEOUT (30 * HZ) #define MT7615_RATE_RETRY 2 @@ -461,6 +460,12 @@ static inline u32 mt7615_tx_mcu_int_mask(struct mt7615_dev *dev) return MT_INT_TX_DONE(dev->mt76.q_mcu[MT_MCUQ_WM]->hw_idx); } +static inline unsigned long +mt7615_get_macwork_timeout(struct mt7615_dev *dev) +{ + return dev->pm.enable ? HZ / 3 : HZ / 10; +} + void mt7615_dma_reset(struct mt7615_dev *dev); void mt7615_scan_work(struct work_struct *work); void mt7615_roc_work(struct work_struct *work); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c index cc278d8cb888..da87c02a73eb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c @@ -268,6 +268,7 @@ void mt7615_mac_reset_work(struct work_struct *work) struct mt7615_phy *phy2; struct mt76_phy *ext_phy; struct mt7615_dev *dev; + unsigned long timeout; dev = container_of(work, struct mt7615_dev, reset_work); ext_phy = dev->mt76.phy2; @@ -345,11 +346,11 @@ void mt7615_mac_reset_work(struct work_struct *work) mt7615_mutex_release(dev); + timeout = mt7615_get_macwork_timeout(dev); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, - MT7615_WATCHDOG_TIME); + timeout); if (phy2) ieee80211_queue_delayed_work(ext_phy->hw, - &phy2->mt76->mac_work, - MT7615_WATCHDOG_TIME); + &phy2->mt76->mac_work, timeout); } From 61a1f99dd1e3c145fce9d601b52e7adb8f37322a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 18 Jun 2021 12:30:47 +0200 Subject: [PATCH 100/170] mt76: mt7921: allow chip reset during device restart Disable chip full reset just during device probing but allow it during hw restart. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/init.c | 8 +++++++- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 8 +++++--- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 3 ++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 9925c15ac9df..a9ce10b98827 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -236,7 +236,13 @@ int mt7921_register_device(struct mt7921_dev *dev) if (ret) return ret; - return mt76_connac_mcu_set_deep_sleep(&dev->mt76, dev->pm.ds_enable); + ret = mt76_connac_mcu_set_deep_sleep(&dev->mt76, dev->pm.ds_enable); + if (ret) + return ret; + + dev->hw_init_done = true; + + return 0; } void mt7921_unregister_device(struct mt7921_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 143dae97ef77..7fe2e3a50428 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1390,11 +1390,13 @@ void mt7921_reset(struct mt76_dev *mdev) { struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); - if (!test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) + if (!dev->hw_init_done) return; - if (!dev->hw_full_reset) - queue_work(dev->mt76.wq, &dev->reset_work); + if (dev->hw_full_reset) + return; + + queue_work(dev->mt76.wq, &dev->reset_work); } static void diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 92cf38444b46..2d8bd6bfc820 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -160,7 +160,8 @@ struct mt7921_dev { u16 chainmask; struct work_struct reset_work; - bool hw_full_reset; + bool hw_full_reset:1; + bool hw_init_done:1; struct list_head sta_poll_list; spinlock_t sta_poll_lock; From c240b044edefa3c3af4014a4030e017dd95b59a1 Mon Sep 17 00:00:00 2001 From: Pascal Terjan Date: Sat, 24 Apr 2021 18:29:59 +0100 Subject: [PATCH 101/170] rtl8xxxu: Fix device info for RTL8192EU devices Based on 2001:3319 and 2357:0109 which I used to test the fix and 0bda:818b and 2357:0108 for which I found efuse dumps online. == 2357:0109 == === Before === Vendor: Realtek Product: \x03802.11n NI Serial: === After === Vendor: Realtek Product: 802.11n NIC Serial not available. == 2001:3319 == === Before === Vendor: Realtek Product: Wireless N Serial: no USB Adap === After === Vendor: Realtek Product: Wireless N Nano USB Adapter Serial not available. Signed-off-by: Pascal Terjan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210424172959.1559890-1-pterjan@google.com --- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 11 +--- .../realtek/rtl8xxxu/rtl8xxxu_8192e.c | 59 +++++++++++++++++-- 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index d1a566cc0c9e..01735776345a 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -853,15 +853,10 @@ struct rtl8192eu_efuse { u8 usb_optional_function; u8 res9[2]; u8 mac_addr[ETH_ALEN]; /* 0xd7 */ - u8 res10[2]; - u8 vendor_name[7]; - u8 res11[2]; - u8 device_name[0x0b]; /* 0xe8 */ - u8 res12[2]; - u8 serial[0x0b]; /* 0xf5 */ - u8 res13[0x30]; + u8 device_info[80]; + u8 res11[3]; u8 unknown[0x0d]; /* 0x130 */ - u8 res14[0xc3]; + u8 res12[0xc3]; }; struct rtl8xxxu_reg8val { diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c index cfe2dfdae928..b06508d0cdf8 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c @@ -554,9 +554,43 @@ rtl8192e_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) } } +static void rtl8192eu_log_next_device_info(struct rtl8xxxu_priv *priv, + char *record_name, + char *device_info, + unsigned int *record_offset) +{ + char *record = device_info + *record_offset; + + /* A record is [ total length | 0x03 | value ] */ + unsigned char l = record[0]; + + /* + * The whole device info section seems to be 80 characters, make sure + * we don't read further. + */ + if (*record_offset + l > 80) { + dev_warn(&priv->udev->dev, + "invalid record length %d while parsing \"%s\" at offset %u.\n", + l, record_name, *record_offset); + return; + } + + if (l >= 2) { + char value[80]; + + memcpy(value, &record[2], l - 2); + value[l - 2] = '\0'; + dev_info(&priv->udev->dev, "%s: %s\n", record_name, value); + *record_offset = *record_offset + l; + } else { + dev_info(&priv->udev->dev, "%s not available.\n", record_name); + } +} + static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv) { struct rtl8192eu_efuse *efuse = &priv->efuse_wifi.efuse8192eu; + unsigned int record_offset; int i; if (efuse->rtl_id != cpu_to_le16(0x8129)) @@ -604,12 +638,25 @@ static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv) priv->has_xtalk = 1; priv->xtalk = priv->efuse_wifi.efuse8192eu.xtal_k & 0x3f; - dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name); - dev_info(&priv->udev->dev, "Product: %.11s\n", efuse->device_name); - if (memchr_inv(efuse->serial, 0xff, 11)) - dev_info(&priv->udev->dev, "Serial: %.11s\n", efuse->serial); - else - dev_info(&priv->udev->dev, "Serial not available.\n"); + /* + * device_info section seems to be laid out as records + * [ total length | 0x03 | value ] so: + * - vendor length + 2 + * - 0x03 + * - vendor string (not null terminated) + * - product length + 2 + * - 0x03 + * - product string (not null terminated) + * Then there is one or 2 0x00 on all the 4 devices I own or found + * dumped online. + * As previous version of the code handled an optional serial + * string, I now assume there may be a third record if the + * length is not 0. + */ + record_offset = 0; + rtl8192eu_log_next_device_info(priv, "Vendor", efuse->device_info, &record_offset); + rtl8192eu_log_next_device_info(priv, "Product", efuse->device_info, &record_offset); + rtl8192eu_log_next_device_info(priv, "Serial", efuse->device_info, &record_offset); if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) { unsigned char *raw = priv->efuse_wifi.raw; From adf6a0f8c0a656df3d29403f314bf3e0dbb2dd77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8D=C3=B1igo=20Huguet?= Date: Tue, 11 May 2021 09:19:27 +0200 Subject: [PATCH 102/170] rtl8xxxu: avoid parsing short RX packet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One USB data buffer can contain multiple received network packets. If that's the case, they're processed this way: 1. Original buffer is cloned 2. Original buffer is trimmed to contain only the first network packet 3. This first network packet is passed to network stack 4. Cloned buffer is trimmed to eliminate the first network packet 5. Repeat with the cloned buffer until there are no more network packets inside However, if the space remaining in original buffer after the first network packet is not enough to contain at least another network packet descriptor, it is not cloned. The loop parsing this packets ended if remaining space == 0. But if the remaining space was > 0 but < packet descriptor size, another iteration of the loop was done, processing again the previous packet because cloning didn't happen. Moreover, the ownership of this packet had been passed to network stack in the previous iteration. This patch ensures that no extra iteration is done if the remaining size is not enough for one packet, and also avoid the first iteration for the same reason. Probably this doesn't happen in practice, but can happen theoretically. Signed-off-by: Íñigo Huguet Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210511071926.8951-1-ihuguet@redhat.com --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 9ff09cf7eb62..ac1061caacd6 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5554,6 +5554,11 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) urb_len = skb->len; pkt_cnt = 0; + if (urb_len < sizeof(struct rtl8xxxu_rxdesc16)) { + kfree_skb(skb); + return RX_TYPE_ERROR; + } + do { rx_desc = (struct rtl8xxxu_rxdesc16 *)skb->data; _rx_desc_le = (__le32 *)skb->data; @@ -5581,7 +5586,7 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) * at least cover the rx descriptor */ if (pkt_cnt > 1 && - urb_len > (pkt_offset + sizeof(struct rtl8xxxu_rxdesc16))) + urb_len >= (pkt_offset + sizeof(struct rtl8xxxu_rxdesc16))) next_skb = skb_clone(skb, GFP_ATOMIC); rx_status = IEEE80211_SKB_RXCB(skb); @@ -5627,7 +5632,9 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) pkt_cnt--; urb_len -= pkt_offset; - } while (skb && urb_len > 0 && pkt_cnt > 0); + next_skb = NULL; + } while (skb && pkt_cnt > 0 && + urb_len >= sizeof(struct rtl8xxxu_rxdesc16)); return RX_TYPE_DATA_PKT; } From 8a952a955de705724b715e4b595a89bee8c11b9f Mon Sep 17 00:00:00 2001 From: Caleb Connolly Date: Thu, 17 Jun 2021 11:29:40 +0300 Subject: [PATCH 103/170] ath10k: demote chan info without scan request warning Some devices/firmwares cause this to be printed every 5-15 seconds, though it has no impact on functionality. Demote this to a debug message. I see this on SDM845 and MSM8998 platforms, specifically the OnePlus 6 devices, PocoPhone F1 and OnePlus 5. On the OnePlus 6 (SDM845) we are stuck with the following signed vendor fw: [ 9.339873] ath10k_snoc 18800000.wifi: qmi chip_id 0x30214 chip_family 0x4001 board_id 0xff soc_id 0x40030001 [ 9.339897] ath10k_snoc 18800000.wifi: qmi fw_version 0x20060029 fw_build_timestamp 2019-07-12 02:14 fw_build_id QC_IMAGE_VERSION_STRING=WLAN.HL.2.0.c8-00041-QCAHLSWMTPLZ-1 The OnePlus 5 (MSM8998) is using firmware: [ 6096.956799] ath10k_snoc 18800000.wifi: qmi chip_id 0x30214 chip_family 0x4001 board_id 0xff soc_id 0x40010002 [ 6096.956824] ath10k_snoc 18800000.wifi: qmi fw_version 0x1007007e fw_build_timestamp 2020-04-14 22:45 fw_build_id QC_IMAGE_VERSION_STRING=WLAN.HL.1.0.c6-00126-QCAHLSWMTPLZ-1.211883.1.278648. Tested-on: WCN3990 hw1.0 SNOC WLAN.HL.2.0.c8-00041-QCAHLSWMTPLZ-1 Tested-on: WCN3990 hw1.0 SNOC WLAN.HL.1.0.c6-00126-QCAHLSWMTPLZ-1.211883.1.278648 Signed-off-by: Caleb Connolly Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210522171609.299611-1-caleb@connolly.tech --- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index f42bf2c8f9e7..b8a4bbfe10b8 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2795,7 +2795,7 @@ void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) switch (ar->scan.state) { case ATH10K_SCAN_IDLE: case ATH10K_SCAN_STARTING: - ath10k_warn(ar, "received chan info event without a scan request, ignoring\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "received chan info event without a scan request, ignoring\n"); goto exit; case ATH10K_SCAN_RUNNING: case ATH10K_SCAN_ABORTING: From 49f5b114e36ebc69318ab95f98b57df7458b0f42 Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Thu, 17 Jun 2021 11:29:40 +0300 Subject: [PATCH 104/170] ath11k: Enable QCN9074 device The issues mentioned in commit 4e80946197a8 ("ath11k: add qcn9074 pci device support") are fixed in firmware. This patch enables QCN9074 device. Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01838-QCAHKSWPL_SILICONZ-1 Signed-off-by: Anilkumar Kolli Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210615211348.92168-1-jouni@codeaurora.org --- drivers/net/wireless/ath/ath11k/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index f8f6b2090dad..646ad79f309c 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -41,7 +41,7 @@ static const struct pci_device_id ath11k_pci_id_table[] = { { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) }, { PCI_VDEVICE(QCOM, WCN6855_DEVICE_ID) }, - /* TODO: add QCN9074_DEVICE_ID) once firmware issues are resolved */ + { PCI_VDEVICE(QCOM, QCN9074_DEVICE_ID) }, {0} }; From 7119f02b5d3449cea7736161590ae45289a57963 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Sat, 12 Jun 2021 14:32:34 +0300 Subject: [PATCH 105/170] iwlwifi: mvm: support BIOS enable/disable for 11ax in Russia Read the new BIOS DSM and Pass to FW if to disable\enable 11ax for Russia according to the BIOS key. This is needed to enable OEMs to control enable/disable 11ax in Russia. Also add support for future "enable 11ax in country X" features. Signed-off-by: Miri Korenblit Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210612142637.a705f7cedff8.I580f1021cabcc37e88f5ec5e9a6bbf00aae514b6@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 50 +++++++++++++++----- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 9 ++++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 26 ++++++---- 3 files changed, 63 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index e31bba836c6f..8cf7bc3aa09a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -163,6 +163,27 @@ int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, } IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u8); +/* + * Evaluate a DSM with no arguments and a u32 return value, + */ +int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, + const guid_t *guid, u32 *value) +{ + int ret; + u64 val; + + ret = iwl_acpi_get_dsm_integer(dev, rev, func, + guid, &val, sizeof(u32)); + + if (ret < 0) + return ret; + + /* cast val (u64) to be u32 */ + *value = (u32)val; + return 0; +} +IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u32); + union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev, union acpi_object *data, int data_size, int *tbl_rev) @@ -734,30 +755,35 @@ out: __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) { - u32 ret; + int ret; + u8 value; __le32 config_bitmap = 0; /* ** Evaluate func 'DSM_FUNC_ENABLE_INDONESIA_5G2' */ - ret = iwl_acpi_eval_dsm_func(fwrt->dev, DSM_FUNC_ENABLE_INDONESIA_5G2); + ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0, + DSM_FUNC_ENABLE_INDONESIA_5G2, + &iwl_guid, &value); - if (ret == DSM_VALUE_INDONESIA_ENABLE) + if (!ret && value == DSM_VALUE_INDONESIA_ENABLE) config_bitmap |= cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK); /* ** Evaluate func 'DSM_FUNC_DISABLE_SRD' */ - ret = iwl_acpi_eval_dsm_func(fwrt->dev, DSM_FUNC_DISABLE_SRD); - - if (ret == DSM_VALUE_SRD_PASSIVE) - config_bitmap |= - cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); - - else if (ret == DSM_VALUE_SRD_DISABLE) - config_bitmap |= - cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); + ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0, + DSM_FUNC_DISABLE_SRD, + &iwl_guid, &value); + if (!ret) { + if (value == DSM_VALUE_SRD_PASSIVE) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); + else if (value == DSM_VALUE_SRD_DISABLE) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); + } return config_bitmap; } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index d16e6ec08c9f..9fe64476083d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -116,6 +116,9 @@ void *iwl_acpi_get_object(struct device *dev, acpi_string method); int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, const guid_t *guid, u8 *value); +int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, + const guid_t *guid, u32 *value); + union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev, union acpi_object *data, int data_size, int *tbl_rev); @@ -182,6 +185,12 @@ static inline int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, return -ENOENT; } +static inline int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, + const guid_t *guid, u32 *value) +{ + return -ENOENT; +} + static inline union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev, union acpi_object *data, int data_size, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 8aa5f1a2c58c..9f2a5dee59d8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1139,14 +1139,19 @@ static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) { - int cmd_ret; + int ret; + u32 value; struct iwl_lari_config_change_cmd_v3 cmd = {}; cmd.config_bitmap = iwl_acpi_get_lari_config_bitmap(&mvm->fwrt); + ret = iwl_acpi_get_dsm_u32((&mvm->fwrt)->dev, 0, DSM_FUNC_11AX_ENABLEMENT, + &iwl_guid, &value); + if (!ret) + cmd.oem_11ax_allow_bitmap = cpu_to_le32(value); /* apply more config masks here */ - if (cmd.config_bitmap) { + if (cmd.config_bitmap || cmd.oem_11ax_allow_bitmap) { size_t cmd_size; u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, REGULATORY_AND_NVM_GROUP, @@ -1159,16 +1164,17 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) cmd_size = sizeof(struct iwl_lari_config_change_cmd_v1); IWL_DEBUG_RADIO(mvm, - "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x\n", - le32_to_cpu(cmd.config_bitmap)); - cmd_ret = iwl_mvm_send_cmd_pdu(mvm, - WIDE_ID(REGULATORY_AND_NVM_GROUP, - LARI_CONFIG_CHANGE), - 0, cmd_size, &cmd); - if (cmd_ret < 0) + "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n", + le32_to_cpu(cmd.config_bitmap), + le32_to_cpu(cmd.oem_11ax_allow_bitmap)); + ret = iwl_mvm_send_cmd_pdu(mvm, + WIDE_ID(REGULATORY_AND_NVM_GROUP, + LARI_CONFIG_CHANGE), + 0, cmd_size, &cmd); + if (ret < 0) IWL_DEBUG_RADIO(mvm, "Failed to send LARI_CONFIG_CHANGE (%d)\n", - cmd_ret); + ret); } } #else /* CONFIG_ACPI */ From c4ae8b9d0f3217308766e1ed3eaad14054b02467 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Sat, 12 Jun 2021 14:32:35 +0300 Subject: [PATCH 106/170] iwlwifi: mvm: pass the clock type to iwl_mvm_get_sync_time() Allow the caller to pass the clock type to iwl_mvm_get_sync_time() so callers with different needs can decide whether to use boottime or realtime. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210612142637.093f6660e69b.Ifd2328ac2130269f729c9c1bceec44ba01d79e88@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c | 4 ++-- .../net/wireless/intel/iwlwifi/mvm/ftm-initiator.c | 5 +++-- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 5 ++++- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 11 ++++++++--- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index 38d0bfb649cc..7d9faeffd154 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -460,7 +460,7 @@ static ssize_t iwl_dbgfs_os_device_timediff_read(struct file *file, int pos = 0; mutex_lock(&mvm->mutex); - iwl_mvm_get_sync_time(mvm, &curr_gp2, &curr_os); + iwl_mvm_get_sync_time(mvm, CLOCK_BOOTTIME, &curr_gp2, &curr_os, NULL); mutex_unlock(&mvm->mutex); do_div(curr_os, NSEC_PER_USEC); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index a456b8a0ae58..a24e6c0490e9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2021 Intel Corporation */ #include #include @@ -879,7 +879,8 @@ static u64 iwl_mvm_ftm_get_host_time(struct iwl_mvm *mvm, __le32 fw_gp2_ts) u32 curr_gp2, diff; u64 now_from_boot_ns; - iwl_mvm_get_sync_time(mvm, &curr_gp2, &now_from_boot_ns); + iwl_mvm_get_sync_time(mvm, CLOCK_BOOTTIME, &curr_gp2, + &now_from_boot_ns, NULL); if (curr_gp2 >= gp2_ts) diff = curr_gp2 - gp2_ts; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 4d9d4d6892fc..b137f8130b6d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -16,6 +16,8 @@ #include #endif +#include + #include "iwl-op-mode.h" #include "iwl-trans.h" #include "fw/notif-wait.h" @@ -1450,7 +1452,8 @@ u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac); void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); u8 first_antenna(u8 mask); u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); -void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime); +void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, int clock_type, u32 *gp2, + u64 *boottime, ktime_t *realtime); u32 iwl_mvm_get_systime(struct iwl_mvm *mvm); /* Tx / Host Commands */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index c566be99a4c7..99105272139d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -1398,7 +1398,8 @@ u32 iwl_mvm_get_systime(struct iwl_mvm *mvm) return iwl_read_prph(mvm->trans, reg_addr); } -void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime) +void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, int clock_type, + u32 *gp2, u64 *boottime, ktime_t *realtime) { bool ps_disabled; @@ -1412,7 +1413,11 @@ void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime) } *gp2 = iwl_mvm_get_systime(mvm); - *boottime = ktime_get_boottime_ns(); + + if (clock_type == CLOCK_BOOTTIME && boottime) + *boottime = ktime_get_boottime_ns(); + else if (clock_type == CLOCK_REALTIME && realtime) + *realtime = ktime_get_real(); if (!ps_disabled) { mvm->ps_disabled = ps_disabled; From e348b8a62c147a2def03ebfa8218f1c8de157bf8 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Sat, 12 Jun 2021 14:32:36 +0300 Subject: [PATCH 107/170] iwlwifi: mvm: fix indentation in some scan functions Two functions had indentation mistakes which were causing sparse warnings. Fix them. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210612142637.12f3b9fea57e.I42a7556d43de78ec6387e3a699eca10482b0485d@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 5a0696c44f6d..0368b7101222 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -2327,9 +2327,9 @@ static int iwl_mvm_scan_umac_v12(struct iwl_mvm *mvm, struct ieee80211_vif *vif, &scan_p->general_params, gen_flags); - ret = iwl_mvm_fill_scan_sched_params(params, - scan_p->periodic_params.schedule, - &scan_p->periodic_params.delay); + ret = iwl_mvm_fill_scan_sched_params(params, + scan_p->periodic_params.schedule, + &scan_p->periodic_params.delay); if (ret) return ret; @@ -2362,9 +2362,9 @@ static int iwl_mvm_scan_umac_v14(struct iwl_mvm *mvm, struct ieee80211_vif *vif, &scan_p->general_params, gen_flags); - ret = iwl_mvm_fill_scan_sched_params(params, - scan_p->periodic_params.schedule, - &scan_p->periodic_params.delay); + ret = iwl_mvm_fill_scan_sched_params(params, + scan_p->periodic_params.schedule, + &scan_p->periodic_params.delay); if (ret) return ret; From 7a9a44456d742bdf66a3394a6e718c6cece20f69 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Sat, 12 Jun 2021 14:32:37 +0300 Subject: [PATCH 108/170] iwlwifi: remove unused REMOTE_WAKE_CONFIG_CMD definitions We don't use this command anymore and it is going to be removed from the FW. Remove all related definitions. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210612142637.549b282ae9a4.Iced05882d73b869e19f50e6a6e7bf9ce6cd7899b@changeid Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/fw/api/commands.h | 5 -- .../net/wireless/intel/iwlwifi/fw/api/d3.h | 51 +------------------ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 1 - 3 files changed, 1 insertion(+), 56 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index c625d319142e..ce060c3dfd7b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -534,11 +534,6 @@ enum iwl_legacy_cmds { */ OFFLOADS_QUERY_CMD = 0xd5, - /** - * @REMOTE_WAKE_CONFIG_CMD: &struct iwl_wowlan_remote_wake_config - */ - REMOTE_WAKE_CONFIG_CMD = 0xd6, - /** * @D0I3_END_CMD: End D0i3/D3 state, no command data */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index 758639084e0c..6488c0f8b471 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -683,55 +683,6 @@ static inline u8 iwlmvm_wowlan_gtk_idx(struct iwl_wowlan_gtk_status *gtk) return gtk->key_flags & IWL_WOWLAN_GTK_IDX_MASK; } -#define IWL_WOWLAN_TCP_MAX_PACKET_LEN 64 -#define IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN 128 -#define IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS 2048 - -struct iwl_tcp_packet_info { - __le16 tcp_pseudo_header_checksum; - __le16 tcp_payload_length; -} __packed; /* TCP_PACKET_INFO_API_S_VER_2 */ - -struct iwl_tcp_packet { - struct iwl_tcp_packet_info info; - u8 rx_mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8]; - u8 data[IWL_WOWLAN_TCP_MAX_PACKET_LEN]; -} __packed; /* TCP_PROTOCOL_PACKET_API_S_VER_1 */ - -struct iwl_remote_wake_packet { - struct iwl_tcp_packet_info info; - u8 rx_mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8]; - u8 data[IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN]; -} __packed; /* TCP_PROTOCOL_PACKET_API_S_VER_1 */ - -struct iwl_wowlan_remote_wake_config { - __le32 connection_max_time; /* unused */ - /* TCP_PROTOCOL_CONFIG_API_S_VER_1 */ - u8 max_syn_retries; - u8 max_data_retries; - u8 tcp_syn_ack_timeout; - u8 tcp_ack_timeout; - - struct iwl_tcp_packet syn_tx; - struct iwl_tcp_packet synack_rx; - struct iwl_tcp_packet keepalive_ack_rx; - struct iwl_tcp_packet fin_tx; - - struct iwl_remote_wake_packet keepalive_tx; - struct iwl_remote_wake_packet wake_rx; - - /* REMOTE_WAKE_OFFSET_INFO_API_S_VER_1 */ - u8 sequence_number_offset; - u8 sequence_number_length; - u8 token_offset; - u8 token_length; - /* REMOTE_WAKE_PROTOCOL_PARAMS_API_S_VER_1 */ - __le32 initial_sequence_number; - __le16 keepalive_interval; - __le16 num_tokens; - u8 tokens[IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS]; -} __packed; /* REMOTE_WAKE_CONFIG_API_S_VER_2 */ - /* TODO: NetDetect API */ #endif /* __iwl_fw_api_d3_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index ebed82c590e5..af5688af9cfb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -445,7 +445,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(D3_CONFIG_CMD), HCMD_NAME(PROT_OFFLOAD_CONFIG_CMD), HCMD_NAME(OFFLOADS_QUERY_CMD), - HCMD_NAME(REMOTE_WAKE_CONFIG_CMD), HCMD_NAME(MATCH_FOUND_NOTIFICATION), HCMD_NAME(DTS_MEASUREMENT_NOTIFICATION), HCMD_NAME(WOWLAN_PATTERNS), From 8835a64f74c46baebfc946cd5a2c861b866ebcee Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 12 Jun 2021 14:32:38 +0300 Subject: [PATCH 109/170] iwlwifi: mvm: don't change band on bound PHY contexts When we have a P2P Device active, we attempt to only change the PHY context it uses when we get a new remain-on-channel, if the P2P Device is the only user of the PHY context. This is fine if we're switching within a band, but if we're switching bands then the switch implies a removal and re-add of the PHY context, which isn't permitted by the firmware while it's bound to an interface. Fix the code to skip the unbind/release/... cycle only if the band doesn't change (or we have old devices that can switch the band on the fly as well.) Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210612142637.e9ac313f70f3.I713b9d109957df7e7d9ed0861d5377ce3f8fccd3@changeid Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 607d5d564928..141d9fc299b0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3800,6 +3800,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct cfg80211_chan_def chandef; struct iwl_mvm_phy_ctxt *phy_ctxt; + bool band_change_removal; int ret, i; IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value, @@ -3880,19 +3881,30 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT); /* - * Change the PHY context configuration as it is currently referenced - * only by the P2P Device MAC + * Check if the remain-on-channel is on a different band and that + * requires context removal, see iwl_mvm_phy_ctxt_changed(). If + * so, we'll need to release and then re-configure here, since we + * must not remove a PHY context that's part of a binding. */ - if (mvmvif->phy_ctxt->ref == 1) { + band_change_removal = + fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT) && + mvmvif->phy_ctxt->channel->band != chandef.chan->band; + + if (mvmvif->phy_ctxt->ref == 1 && !band_change_removal) { + /* + * Change the PHY context configuration as it is currently + * referenced only by the P2P Device MAC (and we can modify it) + */ ret = iwl_mvm_phy_ctxt_changed(mvm, mvmvif->phy_ctxt, &chandef, 1, 1); if (ret) goto out_unlock; } else { /* - * The PHY context is shared with other MACs. Need to remove the - * P2P Device from the binding, allocate an new PHY context and - * create a new binding + * The PHY context is shared with other MACs (or we're trying to + * switch bands), so remove the P2P Device from the binding, + * allocate an new PHY context and create a new binding. */ phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm); if (!phy_ctxt) { From f00c3f9e2cfc144d5f40803ea3cd0d0cb09745cc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 12 Jun 2021 14:32:39 +0300 Subject: [PATCH 110/170] iwlwifi: pcie: handle pcim_iomap_table() failures better pcim_iomap_table() might return NULL, so we shouldn't unconditionally dereference the return value by taking the [0] entry. Handle this better by checking for NULL first, and then separately checking if the [0] entry is NULL. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210612142637.9aa4f0e3574a.I458b283f203d5f927f00be1bfbd4b8ebf11c5ae4@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 239bc177a3e5..1009e3d254cd 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -3413,6 +3413,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, struct iwl_trans *trans; int ret, addr_size; const struct iwl_trans_ops *ops = &trans_ops_pcie_gen2; + void __iomem * const *table; if (!cfg_trans->gen2) ops = &trans_ops_pcie; @@ -3485,9 +3486,16 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, goto out_no_pci; } - trans_pcie->hw_base = pcim_iomap_table(pdev)[0]; - if (!trans_pcie->hw_base) { + table = pcim_iomap_table(pdev); + if (!table) { dev_err(&pdev->dev, "pcim_iomap_table failed\n"); + ret = -ENOMEM; + goto out_no_pci; + } + + trans_pcie->hw_base = table[0]; + if (!trans_pcie->hw_base) { + dev_err(&pdev->dev, "couldn't find IO mem in first BAR\n"); ret = -ENODEV; goto out_no_pci; } From 5cc816ef9db1fe03f73e56e9d8f118add9c6efe4 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Sat, 12 Jun 2021 14:32:40 +0300 Subject: [PATCH 111/170] iwlwifi: increase PNVM load timeout The FW has a watchdog of 200ms in the PNVM load flow, so the driver should have a slightly higher timeout. Change the timeout from 100ms to 250ms. Signed-off-by: Luca Coelho Fixes: 70d3ca86b025 ("iwlwifi: mvm: ring the doorbell and wait for PNVM load completion") Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210612142637.ba22aec1e2be.I36bfadc28c480f4fc57266c075a79e8ea4a6934f@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h index e4f91bce222d..61d3d4e0b7d9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /****************************************************************************** * - * Copyright(c) 2020 Intel Corporation + * Copyright(c) 2020-2021 Intel Corporation * *****************************************************************************/ @@ -10,7 +10,7 @@ #include "fw/notif-wait.h" -#define MVM_UCODE_PNVM_TIMEOUT (HZ / 10) +#define MVM_UCODE_PNVM_TIMEOUT (HZ / 4) int iwl_pnvm_load(struct iwl_trans *trans, struct iwl_notif_wait_data *notif_wait); From 7e2c14372bd89ffe4cefd678b8b1743cac376f4c Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Sat, 12 Jun 2021 14:32:41 +0300 Subject: [PATCH 112/170] iwlwifi: pcie: Add support for AX231 radio module with Ma devices Add support for AX231 radio modules, which we call Fm. These modules can be used with the Ma family of devices and above. Signed-off-by: Matti Gottlieb Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210612142637.c1fdd153d686.I7ee0485c52fb429de1fe171cb6dc0ae593a26788@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 12 ++++++++++++ drivers/net/wireless/intel/iwlwifi/iwl-config.h | 3 +++ drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 5 +++++ 3 files changed, 20 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index c2315dea9a23..0256d0042f71 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -47,6 +47,7 @@ #define IWL_MA_A_GF_A_FW_PRE "iwlwifi-ma-a0-gf-a0-" #define IWL_MA_A_GF4_A_FW_PRE "iwlwifi-ma-a0-gf4-a0-" #define IWL_MA_A_MR_A_FW_PRE "iwlwifi-ma-a0-mr-a0-" +#define IWL_MA_A_FM_A_FW_PRE "iwlwifi-ma-a0-fm-a0-" #define IWL_SNJ_A_MR_A_FW_PRE "iwlwifi-SoSnj-a0-mr-a0-" #define IWL_BZ_A_HR_B_FW_PRE "iwlwifi-bz-a0-hr-b0-" #define IWL_BZ_A_GF_A_FW_PRE "iwlwifi-bz-a0-gf-a0-" @@ -93,6 +94,8 @@ IWL_MA_A_GF4_A_FW_PRE __stringify(api) ".ucode" #define IWL_MA_A_MR_A_FW_MODULE_FIRMWARE(api) \ IWL_MA_A_MR_A_FW_PRE __stringify(api) ".ucode" +#define IWL_MA_A_FM_A_FW_MODULE_FIRMWARE(api) \ + IWL_MA_A_FM_A_FW_PRE __stringify(api) ".ucode" #define IWL_SNJ_A_MR_A_MODULE_FIRMWARE(api) \ IWL_SNJ_A_MR_A_FW_PRE __stringify(api) ".ucode" #define IWL_BZ_A_HR_B_MODULE_FIRMWARE(api) \ @@ -389,6 +392,7 @@ const char iwl_ax201_name[] = "Intel(R) Wi-Fi 6 AX201 160MHz"; const char iwl_ax203_name[] = "Intel(R) Wi-Fi 6 AX203"; const char iwl_ax211_name[] = "Intel(R) Wi-Fi 6E AX211 160MHz"; const char iwl_ax221_name[] = "Intel(R) Wi-Fi 6E AX221 160MHz"; +const char iwl_ax231_name[] = "Intel(R) Wi-Fi 6E AX231 160MHz"; const char iwl_ax411_name[] = "Intel(R) Wi-Fi 6E AX411 160MHz"; const char iwl_ax200_killer_1650w_name[] = @@ -724,6 +728,13 @@ const struct iwl_cfg iwl_cfg_ma_a0_mr_a0 = { .num_rbds = IWL_NUM_RBDS_AX210_HE, }; +const struct iwl_cfg iwl_cfg_ma_a0_fm_a0 = { + .fw_name_pre = IWL_MA_A_FM_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + const struct iwl_cfg iwl_cfg_snj_a0_mr_a0 = { .fw_name_pre = IWL_SNJ_A_MR_A_FW_PRE, .uhb_supported = true, @@ -797,6 +808,7 @@ MODULE_FIRMWARE(IWL_MA_A_HR_B_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_A_GF_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_A_GF4_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_A_MR_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_MA_A_FM_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_SNJ_A_MR_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index b35ffdfdf14b..fc2ba1ce4370 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -426,6 +426,7 @@ struct iwl_cfg { #define IWL_CFG_RF_TYPE_HR1 0x10C #define IWL_CFG_RF_TYPE_GF 0x10D #define IWL_CFG_RF_TYPE_MR 0x110 +#define IWL_CFG_RF_TYPE_FM 0x112 #define IWL_CFG_RF_ID_TH 0x1 #define IWL_CFG_RF_ID_TH1 0x1 @@ -507,6 +508,7 @@ extern const char iwl_ax210_killer_1675w_name[]; extern const char iwl_ax210_killer_1675x_name[]; extern const char iwl_ax211_name[]; extern const char iwl_ax221_name[]; +extern const char iwl_ax231_name[]; extern const char iwl_ax411_name[]; #if IS_ENABLED(CONFIG_IWLDVM) extern const struct iwl_cfg iwl5300_agn_cfg; @@ -613,6 +615,7 @@ extern const struct iwl_cfg iwl_cfg_ma_a0_hr_b0; extern const struct iwl_cfg iwl_cfg_ma_a0_gf_a0; extern const struct iwl_cfg iwl_cfg_ma_a0_gf4_a0; extern const struct iwl_cfg iwl_cfg_ma_a0_mr_a0; +extern const struct iwl_cfg iwl_cfg_ma_a0_fm_a0; extern const struct iwl_cfg iwl_cfg_snj_a0_mr_a0; extern const struct iwl_cfg iwl_cfg_so_a0_hr_a0; extern const struct iwl_cfg iwl_cfg_quz_a0_hr_b0; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index d94bd8d732e9..c0765bbd006f 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1029,6 +1029,11 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_RF_TYPE_MR, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_ma_a0_mr_a0, iwl_ax221_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_MA, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, + iwl_cfg_ma_a0_fm_a0, iwl_ax231_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_MR, IWL_CFG_ANY, From 57e6492cf0fd2e39feaa7ac39c68383f44bde6ac Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 12 Jun 2021 14:32:42 +0300 Subject: [PATCH 113/170] iwlwifi: pcie: print interrupt number, not index Printing the interrupt index in our local array isn't very useful in an error message, print the interrupt number (as also shown in e.g. /proc/interrupts) instead. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210612142637.05bc5157e606.Ifb65b5ed2e5296fd8258c40c4287b5443b06d337@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 1009e3d254cd..5b40833932a0 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1648,7 +1648,7 @@ static void iwl_pcie_irq_set_affinity(struct iwl_trans *trans) if (ret) IWL_ERR(trans_pcie->trans, "Failed to set affinity mask for IRQ %d\n", - i); + trans_pcie->msix_entries[i].vector); } } From 163c36150179503dae869f0f17355eedb32b7af4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 12 Jun 2021 14:32:43 +0300 Subject: [PATCH 114/170] iwlwifi: pcie: remove CSR_HW_RF_ID_TYPE_CHIP_ID This is duplicated with CSR_HW_RFID_TYPE so just use the latter for less typing/shorter lines. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210612142637.00b220f4ba53.I1fe216a46e7d9c1316d681daa293064f16ff1899@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 5 +---- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 12 ++++++------ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index db312abd2e09..47e5a17c0f48 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2020 Intel Corporation + * Copyright (C) 2005-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2016 Intel Deutschland GmbH */ @@ -325,9 +325,6 @@ enum { #define CSR_HW_RF_ID_TYPE_GF (0x0010D000) #define CSR_HW_RF_ID_TYPE_GF4 (0x0010E000) -/* HW_RF CHIP ID */ -#define CSR_HW_RF_ID_TYPE_CHIP_ID(_val) (((_val) >> 12) & 0xFFF) - /* HW_RF CHIP STEP */ #define CSR_HW_RF_STEP(_val) (((_val) >> 8) & 0xF) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index c0765bbd006f..a92c5f0044cd 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1214,14 +1214,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (cfg == &iwlax210_2ax_cfg_so_hr_a0) { if (iwl_trans->hw_rev == CSR_HW_REV_TYPE_TY) { iwl_trans->cfg = &iwlax210_2ax_cfg_ty_gf_a0; - } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(iwl_trans->hw_rf_id) == - CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_JF)) { + } else if (CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) == + CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF)) { iwl_trans->cfg = &iwlax210_2ax_cfg_so_jf_b0; - } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(iwl_trans->hw_rf_id) == - CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_GF)) { + } else if (CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) == + CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF)) { iwl_trans->cfg = &iwlax211_2ax_cfg_so_gf_a0; - } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(iwl_trans->hw_rf_id) == - CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_GF4)) { + } else if (CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) == + CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF4)) { iwl_trans->cfg = &iwlax411_2ax_cfg_so_gf4_a0; } } From 7e10d7ae960212f84972a2c59dd9a1a5e23fd4a4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 12 Jun 2021 14:32:44 +0300 Subject: [PATCH 115/170] iwlwifi: remove duplicate iwl_ax201_cfg_qu_hr declaration This configuration struct is declared twice, remove one of the declarations. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210612142637.a08c905ec25b.Iff706f9d5b7b666e306549c419d04dcd4d81e5fd@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index fc2ba1ce4370..3e4c6a809595 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -588,7 +588,6 @@ extern const struct iwl_cfg iwl_qu_b0_hr_b0; extern const struct iwl_cfg iwl_qu_c0_hr_b0; extern const struct iwl_cfg iwl_ax200_cfg_cc; extern const struct iwl_cfg iwl_ax201_cfg_qu_hr; -extern const struct iwl_cfg iwl_ax201_cfg_qu_hr; extern const struct iwl_cfg iwl_ax201_cfg_qu_c0_hr_b0; extern const struct iwl_cfg iwl_ax201_cfg_quz_hr; extern const struct iwl_cfg iwl_ax1650i_cfg_quz_hr; From a451b823074ca40bda686f3fb48875103e17d7da Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Sat, 12 Jun 2021 14:32:45 +0300 Subject: [PATCH 116/170] iwlwifi: yoyo: support region TLV version 2 Region TLV version 2 now includes more data, but it is not relevant for the driver. In order to support this new version, just mask the new part out. Signed-off-by: Mukesh Sisodiya Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210612142637.60dd4c60ab49.I44fe02af389d3ab089363bf9bde0d99a4c1ff383@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h | 3 ++- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 9 ++++++++- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 13 ++++++++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h index 996d5cc5bd9a..5a2d9a1f7e73 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2021 Intel Corporation */ #ifndef __iwl_fw_dbg_tlv_h__ #define __iwl_fw_dbg_tlv_h__ @@ -11,6 +11,7 @@ #define IWL_FW_INI_MAX_NAME 32 #define IWL_FW_INI_MAX_CFG_NAME 64 #define IWL_FW_INI_DOMAIN_ALWAYS_ON 0 +#define IWL_FW_INI_REGION_V2_MASK 0x0000FFFF /** * struct iwl_fw_ini_hcmd diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index cc4e18ca9566..5a534d70f253 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1933,6 +1933,13 @@ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list, u32 num_of_ranges, i, size; void *range; + /* + * The higher part of the ID in version 2 is irrelevant for + * us, so mask it out. + */ + if (le32_to_cpu(reg->hdr.version) == 2) + id &= IWL_FW_INI_REGION_V2_MASK; + if (!ops->get_num_of_ranges || !ops->get_size || !ops->fill_mem_hdr || !ops->fill_range) return 0; @@ -1957,7 +1964,7 @@ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list, num_of_ranges = ops->get_num_of_ranges(fwrt, reg_data); header = (void *)tlv->data; - header->region_id = reg->id; + header->region_id = cpu_to_le32(id); header->num_of_ranges = cpu_to_le32(num_of_ranges); header->name_len = cpu_to_le32(IWL_FW_INI_MAX_NAME); memcpy(header->name, reg->name, IWL_FW_INI_MAX_NAME); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 4cd8c39cc3e9..0ddd255a8cc1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -57,7 +57,7 @@ dbg_ver_table[IWL_DBG_TLV_TYPE_NUM] = { [IWL_DBG_TLV_TYPE_DEBUG_INFO] = {.min_ver = 1, .max_ver = 1,}, [IWL_DBG_TLV_TYPE_BUF_ALLOC] = {.min_ver = 1, .max_ver = 1,}, [IWL_DBG_TLV_TYPE_HCMD] = {.min_ver = 1, .max_ver = 1,}, - [IWL_DBG_TLV_TYPE_REGION] = {.min_ver = 1, .max_ver = 1,}, + [IWL_DBG_TLV_TYPE_REGION] = {.min_ver = 1, .max_ver = 2,}, [IWL_DBG_TLV_TYPE_TRIGGER] = {.min_ver = 1, .max_ver = 1,}, }; @@ -178,9 +178,20 @@ static int iwl_dbg_tlv_alloc_region(struct iwl_trans *trans, u32 type = le32_to_cpu(reg->type); u32 tlv_len = sizeof(*tlv) + le32_to_cpu(tlv->length); + /* + * The higher part of the ID in version 2 is irrelevant for + * us, so mask it out. + */ + if (le32_to_cpu(reg->hdr.version) == 2) + id &= IWL_FW_INI_REGION_V2_MASK; + if (le32_to_cpu(tlv->length) < sizeof(*reg)) return -EINVAL; + /* for safe use of a string from FW, limit it to IWL_FW_INI_MAX_NAME */ + IWL_DEBUG_FW(trans, "WRT: parsing region: %.*s\n", + IWL_FW_INI_MAX_NAME, reg->name); + if (id >= IWL_FW_INI_MAX_REGION_ID) { IWL_ERR(trans, "WRT: Invalid region id %u\n", id); return -EINVAL; From aa899e683fe537793eb81e06ee93ee8ec7cf3f78 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 17 Jun 2021 10:08:41 +0300 Subject: [PATCH 117/170] iwlwifi: pcie: identify the RF module Identify and print out the RF module to be able to identify (from logs and through debugfs) which one (and version) is present on the system. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210617100544.cd1ef97b2c04.Iad42a59902a87a50b45b9ce88705863686a83b54@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 4 +- .../wireless/intel/iwlwifi/pcie/internal.h | 5 +- .../wireless/intel/iwlwifi/pcie/trans-gen2.c | 71 +++++++++++++++++++ .../net/wireless/intel/iwlwifi/pcie/trans.c | 18 +++++ 4 files changed, 96 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 3ce77e4eb7e3..9a9e714bf9af 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2020 Intel Corporation + * Copyright (C) 2005-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016 Intel Deutschland GmbH */ @@ -412,6 +412,8 @@ enum { #define UREG_DOORBELL_TO_ISR6_RESUME BIT(19) #define UREG_DOORBELL_TO_ISR6_PNVM BIT(20) +#define CNVI_MBOX_C 0xA3400C + #define FSEQ_ERROR_CODE 0xA340C8 #define FSEQ_TOP_INIT_VERSION 0xA34038 #define FSEQ_CNVIO_INIT_VERSION 0xA3403C diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 76a512cd2e5c..907781714680 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2003-2015, 2018-2020 Intel Corporation + * Copyright (C) 2003-2015, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -317,6 +317,7 @@ struct cont_rec { * @alloc_page_lock: spinlock for the page allocator * @alloc_page: allocated page to still use parts of * @alloc_page_used: how much of the allocated page was already used (bytes) + * @rf_name: name/version of the CRF, if any */ struct iwl_trans_pcie { struct iwl_rxq *rxq; @@ -409,6 +410,8 @@ struct iwl_trans_pcie { bool fw_reset_handshake; bool fw_reset_done; wait_queue_head_t fw_reset_waitq; + + char rf_name[32]; }; static inline struct iwl_trans_pcie * diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index 1bcd36e9e008..56162c4500d7 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -240,6 +240,75 @@ static int iwl_pcie_gen2_nic_init(struct iwl_trans *trans) return 0; } +static void iwl_pcie_get_rf_name(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + char *buf = trans_pcie->rf_name; + size_t buflen = sizeof(trans_pcie->rf_name); + size_t pos; + u32 version; + + if (buf[0]) + return; + + switch (CSR_HW_RFID_TYPE(trans->hw_rf_id)) { + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF): + pos = scnprintf(buf, buflen, "JF"); + break; + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF): + pos = scnprintf(buf, buflen, "GF"); + break; + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF4): + pos = scnprintf(buf, buflen, "GF4"); + break; + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR): + pos = scnprintf(buf, buflen, "HR"); + break; + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR1): + pos = scnprintf(buf, buflen, "HR1"); + break; + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HRCDB): + pos = scnprintf(buf, buflen, "HRCDB"); + break; + default: + return; + } + + switch (CSR_HW_RFID_TYPE(trans->hw_rf_id)) { + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR): + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR1): + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HRCDB): + version = iwl_read_prph(trans, CNVI_MBOX_C); + switch (version) { + case 0x20000: + pos += scnprintf(buf + pos, buflen - pos, " B3"); + break; + case 0x120000: + pos += scnprintf(buf + pos, buflen - pos, " B5"); + break; + default: + pos += scnprintf(buf + pos, buflen - pos, + " (0x%x)", version); + break; + } + break; + default: + break; + } + + pos += scnprintf(buf + pos, buflen - pos, ", rfid=0x%x", + trans->hw_rf_id); + + IWL_INFO(trans, "Detected RF %s\n", buf); + + /* + * also add a \n for debugfs - need to do it after printing + * since our IWL_INFO machinery wants to see a static \n at + * the end of the string + */ + pos += scnprintf(buf + pos, buflen - pos, "\n"); +} + void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -263,6 +332,8 @@ void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr) iwl_enable_interrupts(trans); mutex_lock(&trans_pcie->mutex); iwl_pcie_check_hw_rf_kill(trans); + + iwl_pcie_get_rf_name(trans); mutex_unlock(&trans_pcie->mutex); } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 5b40833932a0..1331a6bfd767 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2848,11 +2848,28 @@ static ssize_t iwl_dbgfs_monitor_data_read(struct file *file, return bytes_copied; } +static ssize_t iwl_dbgfs_rf_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_trans *trans = file->private_data; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + if (!trans_pcie->rf_name[0]) + return -ENODEV; + + return simple_read_from_buffer(user_buf, count, ppos, + trans_pcie->rf_name, + strlen(trans_pcie->rf_name)); +} + DEBUGFS_READ_WRITE_FILE_OPS(interrupt); DEBUGFS_READ_FILE_OPS(fh_reg); DEBUGFS_READ_FILE_OPS(rx_queue); DEBUGFS_WRITE_FILE_OPS(csr); DEBUGFS_READ_WRITE_FILE_OPS(rfkill); +DEBUGFS_READ_FILE_OPS(rf); + static const struct file_operations iwl_dbgfs_tx_queue_ops = { .owner = THIS_MODULE, .open = iwl_dbgfs_tx_queue_open, @@ -2879,6 +2896,7 @@ void iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans) DEBUGFS_ADD_FILE(fh_reg, dir, 0400); DEBUGFS_ADD_FILE(rfkill, dir, 0600); DEBUGFS_ADD_FILE(monitor_data, dir, 0400); + DEBUGFS_ADD_FILE(rf, dir, 0400); } static void iwl_trans_pcie_debugfs_cleanup(struct iwl_trans *trans) From 46d1da21d0cbf237d9f80ba66261fb1435ba2103 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 17 Jun 2021 10:08:42 +0300 Subject: [PATCH 118/170] iwlwifi: mvm: don't request SMPS in AP mode This is not valid (in the spec) and mac80211 will soon warn on it, in addition to ignoring it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210617100544.d568df20e273.Id45ae38f9b16b3c56fa62266e3e89a1421ea07b0@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 99105272139d..e1e45eca09b5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -621,7 +621,7 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum ieee80211_smps_mode smps_request) { struct iwl_mvm_vif *mvmvif; - enum ieee80211_smps_mode smps_mode; + enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC; int i; lockdep_assert_held(&mvm->mutex); @@ -630,10 +630,8 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (num_of_ant(iwl_mvm_get_valid_rx_ant(mvm)) == 1) return; - if (vif->type == NL80211_IFTYPE_AP) - smps_mode = IEEE80211_SMPS_OFF; - else - smps_mode = IEEE80211_SMPS_AUTOMATIC; + if (vif->type != NL80211_IFTYPE_STATION) + return; mvmvif = iwl_mvm_vif_from_mac80211(vif); mvmvif->smps_requests[req_type] = smps_request; From a171399fd687a7d2fa56a10c9a2d7084a647677d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 17 Jun 2021 10:08:43 +0300 Subject: [PATCH 119/170] iwlwifi: mvm: apply RX diversity per PHY context SMPS requests may differ per interfaces due to e.g. Bluetooth only interfering on 2.4 GHz, so if that's the case we should, in the case of multiple PHY contexts, still allow RX diversity on PHY context that have no interfaces with SMPS requests. Fix the code to pass through the PHY context in question and skip interfaces with non-matching PHY context while iterating. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210617100544.123c6b05809d.I992e3d1c6a29850d02eeec01712b5b685b963a87@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 3 +- .../net/wireless/intel/iwlwifi/mvm/phy-ctxt.c | 15 ++++++---- .../net/wireless/intel/iwlwifi/mvm/utils.c | 28 ++++++++++++++----- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index b137f8130b6d..0b8658c7d088 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1830,7 +1830,8 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum iwl_mvm_smps_type_request req_type, enum ieee80211_smps_mode smps_request); -bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm); +bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm, + struct iwl_mvm_phy_ctxt *ctxt); /* Low latency */ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index 0fd51f6aa206..4ed2338027d1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH */ @@ -76,6 +76,7 @@ static void iwl_mvm_phy_ctxt_cmd_hdr(struct iwl_mvm_phy_ctxt *ctxt, } static void iwl_mvm_phy_ctxt_set_rxchain(struct iwl_mvm *mvm, + struct iwl_mvm_phy_ctxt *ctxt, __le32 *rxchain_info, u8 chains_static, u8 chains_dynamic) @@ -93,7 +94,7 @@ static void iwl_mvm_phy_ctxt_set_rxchain(struct iwl_mvm *mvm, * between the two antennas is sufficiently different to impact * performance. */ - if (active_cnt == 1 && iwl_mvm_rx_diversity_allowed(mvm)) { + if (active_cnt == 1 && iwl_mvm_rx_diversity_allowed(mvm, ctxt)) { idle_cnt = 2; active_cnt = 2; } @@ -113,6 +114,7 @@ static void iwl_mvm_phy_ctxt_set_rxchain(struct iwl_mvm *mvm, * Add the phy configuration to the PHY context command */ static void iwl_mvm_phy_ctxt_cmd_data_v1(struct iwl_mvm *mvm, + struct iwl_mvm_phy_ctxt *ctxt, struct iwl_phy_context_cmd_v1 *cmd, struct cfg80211_chan_def *chandef, u8 chains_static, u8 chains_dynamic) @@ -123,7 +125,7 @@ static void iwl_mvm_phy_ctxt_cmd_data_v1(struct iwl_mvm *mvm, /* Set the channel info data */ iwl_mvm_set_chan_info_chandef(mvm, &cmd->ci, chandef); - iwl_mvm_phy_ctxt_set_rxchain(mvm, &tail->rxchain_info, + iwl_mvm_phy_ctxt_set_rxchain(mvm, ctxt, &tail->rxchain_info, chains_static, chains_dynamic); tail->txchain_info = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm)); @@ -133,6 +135,7 @@ static void iwl_mvm_phy_ctxt_cmd_data_v1(struct iwl_mvm *mvm, * Add the phy configuration to the PHY context command */ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, + struct iwl_mvm_phy_ctxt *ctxt, struct iwl_phy_context_cmd *cmd, struct cfg80211_chan_def *chandef, u8 chains_static, u8 chains_dynamic) @@ -143,7 +146,7 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, /* Set the channel info data */ iwl_mvm_set_chan_info_chandef(mvm, &cmd->ci, chandef); - iwl_mvm_phy_ctxt_set_rxchain(mvm, &cmd->rxchain_info, + iwl_mvm_phy_ctxt_set_rxchain(mvm, ctxt, &cmd->rxchain_info, chains_static, chains_dynamic); } @@ -170,7 +173,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, iwl_mvm_phy_ctxt_cmd_hdr(ctxt, &cmd, action); /* Set the command data */ - iwl_mvm_phy_ctxt_cmd_data(mvm, &cmd, chandef, + iwl_mvm_phy_ctxt_cmd_data(mvm, ctxt, &cmd, chandef, chains_static, chains_dynamic); @@ -186,7 +189,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, action); /* Set the command data */ - iwl_mvm_phy_ctxt_cmd_data_v1(mvm, &cmd, chandef, + iwl_mvm_phy_ctxt_cmd_data_v1(mvm, ctxt, &cmd, chandef, chains_static, chains_dynamic); ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index e1e45eca09b5..0e8ad798ab57 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -681,23 +681,37 @@ void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm) mvm->accu_radio_stats.on_time_scan += mvm->radio_stats.on_time_scan; } +struct iwl_mvm_diversity_iter_data { + struct iwl_mvm_phy_ctxt *ctxt; + bool result; +}; + static void iwl_mvm_diversity_iter(void *_data, u8 *mac, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - bool *result = _data; + struct iwl_mvm_diversity_iter_data *data = _data; int i; + if (mvmvif->phy_ctxt != data->ctxt) + return; + for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) { if (mvmvif->smps_requests[i] == IEEE80211_SMPS_STATIC || - mvmvif->smps_requests[i] == IEEE80211_SMPS_DYNAMIC) - *result = false; + mvmvif->smps_requests[i] == IEEE80211_SMPS_DYNAMIC) { + data->result = false; + break; + } } } -bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm) +bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm, + struct iwl_mvm_phy_ctxt *ctxt) { - bool result = true; + struct iwl_mvm_diversity_iter_data data = { + .ctxt = ctxt, + .result = true, + }; lockdep_assert_held(&mvm->mutex); @@ -709,9 +723,9 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm) ieee80211_iterate_active_interfaces_atomic( mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_diversity_iter, &result); + iwl_mvm_diversity_iter, &data); - return result; + return data.result; } void iwl_mvm_send_low_latency_cmd(struct iwl_mvm *mvm, From 2a7ce54ccc23e6a6f2e619cfe657a587accb1a3e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 17 Jun 2021 10:08:44 +0300 Subject: [PATCH 120/170] iwlwifi: mvm: honour firmware SMPS requests The firmware can now request SMPS (due to thermal conditions), add some code to honour such requests and bubble them up through the stack, subject to our other SMPS constraints, e.g. from Bluetooth. Then, if the firmware requests SMPS, then we know that it supports a small extension to the PHY configuration API where a chain mask of 0 means "use 1 but pick which one yourself", so in this case we use that extension. During firmware restart, we stay in the previous state, and the FW will send us a notification at startup (only) if the temperature is below the lower or above the high threshold, to sync the state. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210617100544.85656b7684b9.I7a661a0758d070a750d3a91874d1a0f5fab9febc@changeid Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/fw/api/datapath.h | 26 +++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 4 ++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 39 +++++++++++++++++++ .../net/wireless/intel/iwlwifi/mvm/phy-ctxt.c | 11 ++++++ 4 files changed, 80 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h index d299bba3aa54..985b0dc5b52a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -63,6 +63,12 @@ enum iwl_data_path_subcmd_ids { */ RX_NO_DATA_NOTIF = 0xF5, + /** + * @THERMAL_DUAL_CHAIN_DISABLE_REQ: firmware request for SMPS mode, + * &struct iwl_thermal_dual_chain_request + */ + THERMAL_DUAL_CHAIN_REQUEST = 0xF6, + /** * @TLC_MNG_UPDATE_NOTIF: &struct iwl_tlc_update_notif */ @@ -169,4 +175,24 @@ struct iwl_datapath_monitor_notif { u8 reserved[3]; } __packed; /* MONITOR_NTF_API_S_VER_1 */ +/** + * enum iwl_thermal_dual_chain_req_events - firmware SMPS request event + * @THERMAL_DUAL_CHAIN_REQ_ENABLE: (re-)enable dual-chain operation + * (subject to other constraints) + * @THERMAL_DUAL_CHAIN_REQ_DISABLE: disable dual-chain operation + * (static SMPS) + */ +enum iwl_thermal_dual_chain_req_events { + THERMAL_DUAL_CHAIN_REQ_ENABLE, + THERMAL_DUAL_CHAIN_REQ_DISABLE, +}; /* THERMAL_DUAL_CHAIN_DISABLE_STATE_API_E_VER_1 */ + +/** + * struct iwl_thermal_dual_chain_request - SMPS request + * @event: the type of request, see &enum iwl_thermal_dual_chain_req_events + */ +struct iwl_thermal_dual_chain_request { + __le32 event; +} __packed; /* THERMAL_DUAL_CHAIN_DISABLE_REQ_NTFY_API_S_VER_1 */ + #endif /* __iwl_fw_api_datapath_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 0b8658c7d088..d89c73ae2848 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -197,6 +197,7 @@ enum iwl_mvm_smps_type_request { IWL_MVM_SMPS_REQ_BT_COEX, IWL_MVM_SMPS_REQ_TT, IWL_MVM_SMPS_REQ_PROT, + IWL_MVM_SMPS_REQ_FW, NUM_IWL_MVM_SMPS_REQ, }; @@ -993,6 +994,8 @@ struct iwl_mvm { */ bool temperature_test; /* Debug test temperature is enabled */ + bool fw_static_smps_request; + unsigned long bt_coex_last_tcm_ts; struct iwl_mvm_tcm tcm; @@ -1832,6 +1835,7 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum ieee80211_smps_mode smps_request); bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt); +void iwl_mvm_apply_fw_smps_request(struct ieee80211_vif *vif); /* Low latency */ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index af5688af9cfb..20e8d343a950 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -210,6 +210,39 @@ static void iwl_mvm_rx_monitor_notif(struct iwl_mvm *mvm, ieee80211_disconnect(vif, true); } +void iwl_mvm_apply_fw_smps_request(struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_FW, + mvm->fw_static_smps_request ? + IEEE80211_SMPS_STATIC : + IEEE80211_SMPS_AUTOMATIC); +} + +static void iwl_mvm_intf_dual_chain_req(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + iwl_mvm_apply_fw_smps_request(vif); +} + +static void iwl_mvm_rx_thermal_dual_chain_req(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_thermal_dual_chain_request *req = (void *)pkt->data; + + /* + * We could pass it to the iterator data, but also need to remember + * it for new interfaces that are added while in this state. + */ + mvm->fw_static_smps_request = + req->event == cpu_to_le32(THERMAL_DUAL_CHAIN_REQ_DISABLE); + ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_intf_dual_chain_req, NULL); +} + /** * enum iwl_rx_handler_context context for Rx handler * @RX_HANDLER_SYNC : this means that it will be called in the Rx path @@ -358,6 +391,11 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER_GRP(DATA_PATH_GROUP, MONITOR_NOTIF, iwl_mvm_rx_monitor_notif, RX_HANDLER_ASYNC_LOCKED, struct iwl_datapath_monitor_notif), + + RX_HANDLER_GRP(DATA_PATH_GROUP, THERMAL_DUAL_CHAIN_REQUEST, + iwl_mvm_rx_thermal_dual_chain_req, + RX_HANDLER_ASYNC_LOCKED, + struct iwl_thermal_dual_chain_request), }; #undef RX_HANDLER #undef RX_HANDLER_GRP @@ -502,6 +540,7 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = { HCMD_NAME(TLC_MNG_CONFIG_CMD), HCMD_NAME(CHEST_COLLECTOR_FILTER_CONFIG_CMD), HCMD_NAME(MONITOR_NOTIF), + HCMD_NAME(THERMAL_DUAL_CHAIN_REQUEST), HCMD_NAME(STA_PM_NOTIF), HCMD_NAME(MU_GROUP_MGMT_NOTIF), HCMD_NAME(RX_QUEUES_NOTIFICATION), diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index 4ed2338027d1..035336a9e755 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -99,6 +99,17 @@ static void iwl_mvm_phy_ctxt_set_rxchain(struct iwl_mvm *mvm, active_cnt = 2; } + /* + * If the firmware requested it, then we know that it supports + * getting zero for the values to indicate "use one, but pick + * which one yourself", which means it can dynamically pick one + * that e.g. has better RSSI. + */ + if (mvm->fw_static_smps_request && active_cnt == 1 && idle_cnt == 1) { + idle_cnt = 0; + active_cnt = 0; + } + *rxchain_info = cpu_to_le32(iwl_mvm_get_valid_rx_ant(mvm) << PHY_RX_CHAIN_VALID_POS); *rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS); From 976ac0af7ba2c5424bc305b926c0807d96fdcc83 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Thu, 17 Jun 2021 10:08:45 +0300 Subject: [PATCH 121/170] iwlwifi: mvm: fix error print when session protection ends When the session protection ends and the Driver is not associated or a beacon was not heard, the Driver prints "No beacons heard...". That's confusing for the case where not associated. Change the print when not associated to "Not associated...". Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210617100544.41a5a5a894fa.I9eabb76e7a3a7f4abbed8f2ef918f1df8e825726@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 83342a6a6d5b..f19081a6f046 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -310,6 +310,8 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, * and know the dtim period. */ iwl_mvm_te_check_disconnect(mvm, te_data->vif, + !te_data->vif->bss_conf.assoc ? + "Not associated and the time event is over already..." : "No beacon heard and the time event is over already..."); break; default: @@ -808,6 +810,8 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, * and know the dtim period. */ iwl_mvm_te_check_disconnect(mvm, vif, + !vif->bss_conf.assoc ? + "Not associated and the session protection is over already..." : "No beacon heard and the session protection is over already..."); spin_lock_bh(&mvm->time_event_lock); iwl_mvm_te_clear_data(mvm, te_data); From b26d4996c862864c5f74f858ee343002530473fb Mon Sep 17 00:00:00 2001 From: Harish Mitty Date: Thu, 17 Jun 2021 10:08:46 +0300 Subject: [PATCH 122/170] iwlwifi: mvm: Call NMI instead of REPLY_ERROR For IWL_DEVICE_FAMILY_22000 & greater, driver will call NMI instead of REPLY_ERROR as FW->Infra does not support this command for this family onwards. Signed-off-by: Harish Mitty Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210617100544.597f4246c79d.Ia0a1bbc2e66b4e849174db685208fc2b8bd5732e@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 63d65018d098..95f883aba148 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1023,7 +1023,9 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, mvm->fw_restart++; /* take the return value to make compiler happy - it will fail anyway */ - ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, 0, 0, NULL); + ret = iwl_mvm_send_cmd_pdu(mvm, + WIDE_ID(LONG_GROUP, REPLY_ERROR), + 0, 0, NULL); mutex_unlock(&mvm->mutex); From 1381eb5c8ed5141bbf39325b80153072647186b6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 17 Jun 2021 10:08:47 +0300 Subject: [PATCH 123/170] iwlwifi: correct HE capabilities The (default) HE capabilities for our devices weren't handled correctly, adjust them to match the correct capabilities of the devices. Since the device regulatory will not allow 160 MHz on 5 GHz, don't advertise this capability by default; do it only if an NVM file is being loaded that might change the regulatory parameters. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210617100544.e8d0b02ec86b.Ia6ef8cc0480d38af25e6ac45fad9fb15bdfcbc2c@changeid Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/iwl-nvm-parse.c | 112 ++++++++++-------- 1 file changed, 65 insertions(+), 47 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index fc75d049046d..bff6533b76a8 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2005-2014, 2018-2020 Intel Corporation + * Copyright (C) 2005-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -549,8 +549,7 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = { .mac_cap_info[2] = IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP, .mac_cap_info[3] = - IEEE80211_HE_MAC_CAP3_OMI_CONTROL | - IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2, + IEEE80211_HE_MAC_CAP3_OMI_CONTROL, .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU | IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39, @@ -579,25 +578,20 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = { IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 | IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8, - .phy_cap_info[5] = - IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 | - IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2, .phy_cap_info[6] = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB | IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, .phy_cap_info[7] = IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP | - IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI | - IEEE80211_HE_PHY_CAP7_MAX_NC_1, + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI, .phy_cap_info[8] = IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU | - IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996, + IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242, .phy_cap_info[9] = - IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED, @@ -632,19 +626,11 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = { .mac_cap_info[1] = IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, - .mac_cap_info[2] = - IEEE80211_HE_MAC_CAP2_BSR, .mac_cap_info[3] = - IEEE80211_HE_MAC_CAP3_OMI_CONTROL | - IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2, - .mac_cap_info[4] = - IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, - .mac_cap_info[5] = - IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU, + IEEE80211_HE_MAC_CAP3_OMI_CONTROL, .phy_cap_info[0] = IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G, + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G, .phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD, .phy_cap_info[2] = @@ -654,27 +640,14 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = { IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 | IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_NO_DCM | IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1, - .phy_cap_info[4] = - IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | - IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 | - IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8, - .phy_cap_info[5] = - IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 | - IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2, .phy_cap_info[6] = IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, .phy_cap_info[7] = - IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI | - IEEE80211_HE_PHY_CAP7_MAX_NC_1, + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI, .phy_cap_info[8] = IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | - IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | - IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | - IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU | - IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996, + IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242, .phy_cap_info[9] = - IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | - IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED, }, /* @@ -745,12 +718,66 @@ static void iwl_init_he_6ghz_capa(struct iwl_trans *trans, iftype_data[i].he_6ghz_capa.capa = cpu_to_le16(he_6ghz_capa); } +static void +iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, + struct ieee80211_supported_band *sband, + struct ieee80211_sband_iftype_data *iftype_data, + u8 tx_chains, u8 rx_chains) +{ + bool is_ap = iftype_data->types_mask & BIT(NL80211_IFTYPE_AP); + + /* Advertise an A-MPDU exponent extension based on + * operating band + */ + if (sband->band != NL80211_BAND_2GHZ) + iftype_data->he_cap.he_cap_elem.mac_cap_info[3] |= + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_1; + else + iftype_data->he_cap.he_cap_elem.mac_cap_info[3] |= + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3; + + if (is_ap && iwlwifi_mod_params.nvm_file) + iftype_data->he_cap.he_cap_elem.phy_cap_info[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + + if ((tx_chains & rx_chains) == ANT_AB) { + iftype_data->he_cap.he_cap_elem.phy_cap_info[5] |= + IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 | + IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2; + if (!is_ap) + iftype_data->he_cap.he_cap_elem.phy_cap_info[7] |= + IEEE80211_HE_PHY_CAP7_MAX_NC_2; + } else if (!is_ap) { + /* If not 2x2, we need to indicate 1x1 in the + * Midamble RX Max NSTS - but not for AP mode + */ + iftype_data->he_cap.he_cap_elem.phy_cap_info[1] &= + ~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS; + iftype_data->he_cap.he_cap_elem.phy_cap_info[2] &= + ~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS; + iftype_data->he_cap.he_cap_elem.phy_cap_info[7] |= + IEEE80211_HE_PHY_CAP7_MAX_NC_1; + } + + switch (CSR_HW_RFID_TYPE(trans->hw_rf_id)) { + case IWL_CFG_RF_TYPE_GF: + case IWL_CFG_RF_TYPE_MR: + iftype_data->he_cap.he_cap_elem.phy_cap_info[9] |= + IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU; + if (!is_ap) + iftype_data->he_cap.he_cap_elem.phy_cap_info[9] |= + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU; + break; + } +} + static void iwl_init_he_hw_capab(struct iwl_trans *trans, struct iwl_nvm_data *data, struct ieee80211_supported_band *sband, u8 tx_chains, u8 rx_chains) { struct ieee80211_sband_iftype_data *iftype_data; + int i; /* should only initialize once */ if (WARN_ON(sband->iftype_data)) @@ -777,19 +804,10 @@ static void iwl_init_he_hw_capab(struct iwl_trans *trans, sband->iftype_data = iftype_data; sband->n_iftype_data = ARRAY_SIZE(iwl_he_capa); - /* If not 2x2, we need to indicate 1x1 in the Midamble RX Max NSTS */ - if ((tx_chains & rx_chains) != ANT_AB) { - int i; + for (i = 0; i < sband->n_iftype_data; i++) + iwl_nvm_fixup_sband_iftd(trans, sband, &iftype_data[i], + tx_chains, rx_chains); - for (i = 0; i < sband->n_iftype_data; i++) { - iftype_data[i].he_cap.he_cap_elem.phy_cap_info[1] &= - ~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS; - iftype_data[i].he_cap.he_cap_elem.phy_cap_info[2] &= - ~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS; - iftype_data[i].he_cap.he_cap_elem.phy_cap_info[7] &= - ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK; - } - } iwl_init_he_6ghz_capa(trans, data, sband, tx_chains, rx_chains); } From 5c1f09422e666a00f99c5f821a40b46df5f871c8 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Thu, 17 Jun 2021 10:08:48 +0300 Subject: [PATCH 124/170] iwlwifi: mvm: support LMR feedback If the LMR feedback is set in the ranging request, set the corresponding flag in the fw command. Signed-off-by: Avraham Stern Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210617100544.0c00dd724f5c.I8283b95c26f4226deaea42e7be35aa9d41eb7580@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index a24e6c0490e9..59cef0d89a6d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -430,6 +430,10 @@ iwl_mvm_ftm_put_target_common(struct iwl_mvm *mvm, FTM_PUT_FLAG(TB); else if (peer->ftm.non_trigger_based) FTM_PUT_FLAG(NON_TB); + + if ((peer->ftm.trigger_based || peer->ftm.non_trigger_based) && + peer->ftm.lmr_feedback) + FTM_PUT_FLAG(LMR_FEEDBACK); } static int From 03470ba71fde9698efcfe28fc36a5c3a05045c32 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Thu, 17 Jun 2021 10:08:49 +0300 Subject: [PATCH 125/170] iwlwifi: advertise broadcast TWT support If the firmware supports broadcast TWT (know by TLV), add the broadcast TWT HE MAC capability. Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210617100544.80fee3171b53.Idfb69643f4044ec26865d023d0c2a1d6466694aa@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/file.h | 3 +- .../wireless/intel/iwlwifi/iwl-nvm-parse.c | 28 +++++++++++++------ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index f9c5cf538ad1..d189e5de478b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2008-2014, 2018-2020 Intel Corporation + * Copyright (C) 2008-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -411,6 +411,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_PROTECTED_TWT = (__force iwl_ucode_tlv_capa_t)56, IWL_UCODE_TLV_CAPA_FW_RESET_HANDSHAKE = (__force iwl_ucode_tlv_capa_t)57, IWL_UCODE_TLV_CAPA_PASSIVE_6GHZ_SCAN = (__force iwl_ucode_tlv_capa_t)58, + IWL_UCODE_TLV_CAPA_BROADCAST_TWT = (__force iwl_ucode_tlv_capa_t)60, /* set 2 */ IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index bff6533b76a8..850648ebd61c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -722,7 +722,8 @@ static void iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, struct ieee80211_supported_band *sband, struct ieee80211_sband_iftype_data *iftype_data, - u8 tx_chains, u8 rx_chains) + u8 tx_chains, u8 rx_chains, + const struct iwl_fw *fw) { bool is_ap = iftype_data->types_mask & BIT(NL80211_IFTYPE_AP); @@ -769,12 +770,17 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU; break; } + + if (fw_has_capa(&fw->ucode_capa, IWL_UCODE_TLV_CAPA_BROADCAST_TWT)) + iftype_data->he_cap.he_cap_elem.mac_cap_info[2] |= + IEEE80211_HE_MAC_CAP2_BCAST_TWT; } static void iwl_init_he_hw_capab(struct iwl_trans *trans, struct iwl_nvm_data *data, struct ieee80211_supported_band *sband, - u8 tx_chains, u8 rx_chains) + u8 tx_chains, u8 rx_chains, + const struct iwl_fw *fw) { struct ieee80211_sband_iftype_data *iftype_data; int i; @@ -806,7 +812,7 @@ static void iwl_init_he_hw_capab(struct iwl_trans *trans, for (i = 0; i < sband->n_iftype_data; i++) iwl_nvm_fixup_sband_iftd(trans, sband, &iftype_data[i], - tx_chains, rx_chains); + tx_chains, rx_chains, fw); iwl_init_he_6ghz_capa(trans, data, sband, tx_chains, rx_chains); } @@ -814,7 +820,8 @@ static void iwl_init_he_hw_capab(struct iwl_trans *trans, static void iwl_init_sbands(struct iwl_trans *trans, struct iwl_nvm_data *data, const void *nvm_ch_flags, u8 tx_chains, - u8 rx_chains, u32 sbands_flags, bool v4) + u8 rx_chains, u32 sbands_flags, bool v4, + const struct iwl_fw *fw) { struct device *dev = trans->dev; const struct iwl_cfg *cfg = trans->cfg; @@ -834,7 +841,8 @@ static void iwl_init_sbands(struct iwl_trans *trans, tx_chains, rx_chains); if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax) - iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains); + iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, + fw); sband = &data->bands[NL80211_BAND_5GHZ]; sband->band = NL80211_BAND_5GHZ; @@ -849,7 +857,8 @@ static void iwl_init_sbands(struct iwl_trans *trans, tx_chains, rx_chains); if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax) - iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains); + iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, + fw); /* 6GHz band. */ sband = &data->bands[NL80211_BAND_6GHZ]; @@ -861,7 +870,8 @@ static void iwl_init_sbands(struct iwl_trans *trans, NL80211_BAND_6GHZ); if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax) - iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains); + iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, + fw); else sband->n_channels = 0; if (n_channels != n_used) @@ -1172,7 +1182,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, sbands_flags |= IWL_NVM_SBANDS_FLAGS_NO_WIDE_IN_5GHZ; iwl_init_sbands(trans, data, ch_section, tx_chains, rx_chains, - sbands_flags, false); + sbands_flags, false, fw); data->calib_version = 255; return data; @@ -1679,7 +1689,7 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, channel_profile, nvm->valid_tx_ant & fw->valid_tx_ant, nvm->valid_rx_ant & fw->valid_rx_ant, - sbands_flags, v4); + sbands_flags, v4, fw); iwl_free_resp(&hcmd); return nvm; From bef99c7d9177b268eb08b959eed28797eff6bdae Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 17 Jun 2021 10:08:50 +0300 Subject: [PATCH 126/170] iwlwifi: pcie: fix some kernel-doc comments "ubd" is really called "used_bd", fix that. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210617100544.2d4b46c656bb.Iff9ee6a7e65d439169202911dad2cbea626fb887@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 907781714680..1c740c382b9b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -109,8 +109,8 @@ struct iwl_rx_completion_desc { * Address size is 32 bit in pre-9000 devices and 64 bit in 9000 devices. * In AX210 devices it is a pointer to a list of iwl_rx_transfer_desc's * @bd_dma: bus address of buffer of receive buffer descriptors (rbd) - * @ubd: driver's pointer to buffer of used receive buffer descriptors (rbd) - * @ubd_dma: physical address of buffer of used receive buffer descriptors (rbd) + * @used_bd: driver's pointer to buffer of used receive buffer descriptors (rbd) + * @used_bd_dma: physical address of buffer of used receive buffer descriptors (rbd) * @tr_tail: driver's pointer to the transmission ring tail buffer * @tr_tail_dma: physical address of the buffer for the transmission ring tail * @cr_tail: driver's pointer to the completion ring tail buffer From 8e08e191fc932b4fc2de014c358f8946a4af57e1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 17 Jun 2021 11:07:28 +0300 Subject: [PATCH 127/170] iwlwifi: pcie: remove TR/CR tail allocations The TR/CR tail data are meant to be per-queue-arrays, however, we allocate them completely wrong (we have a separate allocation per queue). Looking at this more closely, it turns out that the hardware never uses these - we have a separate free list per RX queue and maintain a write pointer for that in a register, and the RX itself is indicated in the RB status (rb_stts) DMA region. Despite nothing using the tail pointers, the hardware will unconditionally access them to write updates, even when we aren't using CRs/TRs. Give it dummy values that we never use/update so it can do that without causing trouble. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210617110647.5f5764e04c46.I4d5de1929be048085767f1234a1e07b517ab6a2d@changeid Signed-off-by: Luca Coelho --- .../intel/iwlwifi/pcie/ctxt-info-gen3.c | 28 +++++++-------- .../wireless/intel/iwlwifi/pcie/internal.h | 11 ------ drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 34 ------------------- 3 files changed, 14 insertions(+), 59 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index cecc32e7dbe8..49560e508b5e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -138,8 +138,15 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, /* Allocate prph information * currently we don't assign to the prph info anything, but it would get - * assigned later */ - prph_info = dma_alloc_coherent(trans->dev, sizeof(*prph_info), + * assigned later + * + * We also use the second half of this page to give the device some + * dummy TR/CR tail pointers - which shouldn't be necessary as we don't + * use this, but the hardware still reads/writes there and we can't let + * it go do that with a NULL pointer. + */ + BUILD_BUG_ON(sizeof(*prph_info) > PAGE_SIZE / 2); + prph_info = dma_alloc_coherent(trans->dev, PAGE_SIZE, &trans_pcie->prph_info_dma_addr, GFP_KERNEL); if (!prph_info) { @@ -166,13 +173,9 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, ctxt_info_gen3->cr_head_idx_arr_base_addr = cpu_to_le64(trans_pcie->rxq->rb_stts_dma); ctxt_info_gen3->tr_tail_idx_arr_base_addr = - cpu_to_le64(trans_pcie->rxq->tr_tail_dma); + cpu_to_le64(trans_pcie->prph_info_dma_addr + PAGE_SIZE / 2); ctxt_info_gen3->cr_tail_idx_arr_base_addr = - cpu_to_le64(trans_pcie->rxq->cr_tail_dma); - ctxt_info_gen3->cr_idx_arr_size = - cpu_to_le16(IWL_NUM_OF_COMPLETION_RINGS); - ctxt_info_gen3->tr_idx_arr_size = - cpu_to_le16(IWL_NUM_OF_TRANSFER_RINGS); + cpu_to_le64(trans_pcie->prph_info_dma_addr + 3 * PAGE_SIZE / 4); ctxt_info_gen3->mtr_base_addr = cpu_to_le64(trans->txqs.txq[trans->txqs.cmd.q_id]->dma_addr); ctxt_info_gen3->mcr_base_addr = @@ -216,10 +219,8 @@ err_free_ctxt_info: trans_pcie->ctxt_info_dma_addr); trans_pcie->ctxt_info_gen3 = NULL; err_free_prph_info: - dma_free_coherent(trans->dev, - sizeof(*prph_info), - prph_info, - trans_pcie->prph_info_dma_addr); + dma_free_coherent(trans->dev, PAGE_SIZE, prph_info, + trans_pcie->prph_info_dma_addr); err_free_prph_scratch: dma_free_coherent(trans->dev, @@ -251,8 +252,7 @@ void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans) trans_pcie->prph_scratch_dma_addr = 0; trans_pcie->prph_scratch = NULL; - dma_free_coherent(trans->dev, sizeof(*trans_pcie->prph_info), - trans_pcie->prph_info, + dma_free_coherent(trans->dev, PAGE_SIZE, trans_pcie->prph_info, trans_pcie->prph_info_dma_addr); trans_pcie->prph_info_dma_addr = 0; trans_pcie->prph_info = NULL; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 1c740c382b9b..292b972a25db 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -111,10 +111,6 @@ struct iwl_rx_completion_desc { * @bd_dma: bus address of buffer of receive buffer descriptors (rbd) * @used_bd: driver's pointer to buffer of used receive buffer descriptors (rbd) * @used_bd_dma: physical address of buffer of used receive buffer descriptors (rbd) - * @tr_tail: driver's pointer to the transmission ring tail buffer - * @tr_tail_dma: physical address of the buffer for the transmission ring tail - * @cr_tail: driver's pointer to the completion ring tail buffer - * @cr_tail_dma: physical address of the buffer for the completion ring tail * @read: Shared index to newest available Rx buffer * @write: Shared index to oldest written Rx packet * @free_count: Number of pre-allocated buffers in rx_free @@ -142,10 +138,6 @@ struct iwl_rxq { struct iwl_rx_completion_desc *cd; }; dma_addr_t used_bd_dma; - __le16 *tr_tail; - dma_addr_t tr_tail_dma; - __le16 *cr_tail; - dma_addr_t cr_tail_dma; u32 read; u32 write; u32 free_count; @@ -533,9 +525,6 @@ static inline void _iwl_disable_interrupts(struct iwl_trans *trans) IWL_DEBUG_ISR(trans, "Disabled interrupts\n"); } -#define IWL_NUM_OF_COMPLETION_RINGS 31 -#define IWL_NUM_OF_TRANSFER_RINGS 527 - static inline int iwl_pcie_get_num_sections(const struct fw_img *fw, int start) { diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index fb8491412be4..4f6f4b2720f0 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -663,7 +663,6 @@ static int iwl_pcie_free_bd_size(struct iwl_trans *trans, bool use_rx_td) static void iwl_pcie_free_rxq_dma(struct iwl_trans *trans, struct iwl_rxq *rxq) { - struct device *dev = trans->dev; bool use_rx_td = (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210); int free_size = iwl_pcie_free_bd_size(trans, use_rx_td); @@ -685,21 +684,6 @@ static void iwl_pcie_free_rxq_dma(struct iwl_trans *trans, rxq->used_bd, rxq->used_bd_dma); rxq->used_bd_dma = 0; rxq->used_bd = NULL; - - if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) - return; - - if (rxq->tr_tail) - dma_free_coherent(dev, sizeof(__le16), - rxq->tr_tail, rxq->tr_tail_dma); - rxq->tr_tail_dma = 0; - rxq->tr_tail = NULL; - - if (rxq->cr_tail) - dma_free_coherent(dev, sizeof(__le16), - rxq->cr_tail, rxq->cr_tail_dma); - rxq->cr_tail_dma = 0; - rxq->cr_tail = NULL; } static int iwl_pcie_alloc_rxq_dma(struct iwl_trans *trans, @@ -744,21 +728,6 @@ static int iwl_pcie_alloc_rxq_dma(struct iwl_trans *trans, rxq->rb_stts_dma = trans_pcie->base_rb_stts_dma + rxq->id * rb_stts_size; - if (!use_rx_td) - return 0; - - /* Allocate the driver's pointer to TR tail */ - rxq->tr_tail = dma_alloc_coherent(dev, sizeof(__le16), - &rxq->tr_tail_dma, GFP_KERNEL); - if (!rxq->tr_tail) - goto err; - - /* Allocate the driver's pointer to CR tail */ - rxq->cr_tail = dma_alloc_coherent(dev, sizeof(__le16), - &rxq->cr_tail_dma, GFP_KERNEL); - if (!rxq->cr_tail) - goto err; - return 0; err: @@ -1590,9 +1559,6 @@ restart: out: /* Backtrack one entry */ rxq->read = i; - /* update cr tail with the rxq read pointer */ - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) - *rxq->cr_tail = cpu_to_le16(r); spin_unlock(&rxq->lock); /* From 54b4fda5a761f97b8918607dbb4cd3b9e711aab6 Mon Sep 17 00:00:00 2001 From: Abhishek Naik Date: Thu, 17 Jun 2021 10:08:52 +0300 Subject: [PATCH 128/170] iwlwifi: mvm: Read acpi dsm to get unii4 enable/disable bitmap. Read the UNII4 setting from the ACPI table and use it in the LARI_CONFIG_CHANGE_CMD accordingly. This setting allows OEMs to enable or disable UNII4, bypassing the FW defaults. Signed-off-by: Abhishek Naik Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210617100544.223090c509c4.If03cb5393607ae494041b6187bcec134d6a1e06d@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 1 + .../wireless/intel/iwlwifi/fw/api/nvm-reg.h | 19 ++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 20 ++++++++++++++++--- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 9fe64476083d..b858e998999c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -78,6 +78,7 @@ enum iwl_dsm_funcs_rev_0 { DSM_FUNC_DISABLE_SRD = 1, DSM_FUNC_ENABLE_INDONESIA_5G2 = 2, DSM_FUNC_11AX_ENABLEMENT = 6, + DSM_FUNC_ENABLE_UNII4_CHAN = 7 }; enum iwl_dsm_values_srd { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index dc8f2777e944..cf48c6fa8f65 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -452,6 +452,25 @@ struct iwl_lari_config_change_cmd_v3 { __le32 oem_11ax_allow_bitmap; } __packed; /* LARI_CHANGE_CONF_CMD_S_VER_3 */ +/** + * struct iwl_lari_config_change_cmd_v4 - change LARI configuration + * @config_bitmap: Bitmap of the config commands. Each bit will trigger a + * different predefined FW config operation. + * @oem_uhb_allow_bitmap: Bitmap of UHB enabled MCC sets. + * @oem_11ax_allow_bitmap: Bitmap of 11ax allowed MCCs. There are two bits + * per country, one to indicate whether to override and the other to + * indicate the value to use. + * @oem_unii4_allow_bitmap: Bitmap of unii4 allowed MCCs.There are two bits + * per country, one to indicate whether to override and the other to + * indicate allow/disallow unii4 channels. + */ +struct iwl_lari_config_change_cmd_v4 { + __le32 config_bitmap; + __le32 oem_uhb_allow_bitmap; + __le32 oem_11ax_allow_bitmap; + __le32 oem_unii4_allow_bitmap; +} __packed; /* LARI_CHANGE_CONF_CMD_S_VER_4 */ + /** * struct iwl_pnvm_init_complete_ntfy - PNVM initialization complete * @status: PNVM image loading status diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 9f2a5dee59d8..38fd5886af2d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1141,7 +1141,7 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) { int ret; u32 value; - struct iwl_lari_config_change_cmd_v3 cmd = {}; + struct iwl_lari_config_change_cmd_v4 cmd = {}; cmd.config_bitmap = iwl_acpi_get_lari_config_bitmap(&mvm->fwrt); @@ -1151,12 +1151,22 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) cmd.oem_11ax_allow_bitmap = cpu_to_le32(value); /* apply more config masks here */ - if (cmd.config_bitmap || cmd.oem_11ax_allow_bitmap) { + ret = iwl_acpi_get_dsm_u32((&mvm->fwrt)->dev, 0, + DSM_FUNC_ENABLE_UNII4_CHAN, + &iwl_guid, &value); + if (!ret) + cmd.oem_unii4_allow_bitmap = cpu_to_le32(value); + + if (cmd.config_bitmap || + cmd.oem_11ax_allow_bitmap || + cmd.oem_unii4_allow_bitmap) { size_t cmd_size; u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, REGULATORY_AND_NVM_GROUP, LARI_CONFIG_CHANGE, 1); - if (cmd_ver == 3) + if (cmd_ver == 4) + cmd_size = sizeof(struct iwl_lari_config_change_cmd_v4); + else if (cmd_ver == 3) cmd_size = sizeof(struct iwl_lari_config_change_cmd_v3); else if (cmd_ver == 2) cmd_size = sizeof(struct iwl_lari_config_change_cmd_v2); @@ -1167,6 +1177,10 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n", le32_to_cpu(cmd.config_bitmap), le32_to_cpu(cmd.oem_11ax_allow_bitmap)); + IWL_DEBUG_RADIO(mvm, + "sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, cmd_ver=%d\n", + le32_to_cpu(cmd.oem_unii4_allow_bitmap), + cmd_ver); ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(REGULATORY_AND_NVM_GROUP, LARI_CONFIG_CHANGE), From 7b3954a1d69a992a781e71036950f9254f8147f6 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Fri, 18 Jun 2021 11:01:12 +0300 Subject: [PATCH 129/170] iwlwifi: mvm: Explicitly stop session protection before unbinding In case of unbinding, the FW would remove the session protection time events without sending a notification, so explicitly cancel the session protection, so future requests for mgd_prepare_tx() would not assume that the session protection is running. Signed-off-by: Ilan Peer Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210618105614.7c30f85ed241.Ibc19fdbefca7135f2c4ea83d0aef6b81b5033dcd@changeid Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 1 - .../wireless/intel/iwlwifi/mvm/time-event.c | 41 ++++++++++++++----- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 141d9fc299b0..bafff5f2c638 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -4223,7 +4223,6 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, struct ieee80211_vif *disabled_vif = NULL; lockdep_assert_held(&mvm->mutex); - iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data); switch (vif->type) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index f19081a6f046..d3307a11fcac 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -31,6 +31,13 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, return; list_del(&te_data->list); + + /* + * the list is only used for AUX ROC events so make sure it is always + * initialized + */ + INIT_LIST_HEAD(&te_data->list); + te_data->running = false; te_data->uid = 0; te_data->id = TE_MAX; @@ -609,14 +616,15 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, } static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm, - struct iwl_mvm_vif *mvmvif) + struct iwl_mvm_vif *mvmvif, + u32 id) { struct iwl_mvm_session_prot_cmd cmd = { .id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)), .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), - .conf_id = cpu_to_le32(mvmvif->time_event_data.id), + .conf_id = cpu_to_le32(id), }; int ret; @@ -634,6 +642,12 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, { u32 id; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); + enum nl80211_iftype iftype; + + if (!te_data->vif) + return false; + + iftype = te_data->vif->type; /* * It is possible that by the time we got to this point the time @@ -658,8 +672,8 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) { if (mvmvif && id < SESSION_PROTECT_CONF_MAX_ID) { /* Session protection is still ongoing. Cancel it */ - iwl_mvm_cancel_session_protection(mvm, mvmvif); - if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { + iwl_mvm_cancel_session_protection(mvm, mvmvif, id); + if (iftype == NL80211_IFTYPE_P2P_DEVICE) { set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); iwl_mvm_roc_finished(mvm); } @@ -740,11 +754,6 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, IWL_ERR(mvm, "Couldn't remove the time event\n"); } -/* - * When the firmware supports the session protection API, - * this is not needed since it'll automatically remove the - * session protection after association + beacon reception. - */ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -758,7 +767,15 @@ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, id = te_data->id; spin_unlock_bh(&mvm->time_event_lock); - if (id != TE_BSS_STA_AGGRESSIVE_ASSOC) { + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) { + if (id != SESSION_PROTECT_CONF_ASSOC) { + IWL_DEBUG_TE(mvm, + "don't remove session protection id=%u\n", + id); + return; + } + } else if (id != TE_BSS_STA_AGGRESSIVE_ASSOC) { IWL_DEBUG_TE(mvm, "don't remove TE with id=%u (not session protection)\n", id); @@ -985,7 +1002,8 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) mvmvif = iwl_mvm_vif_from_mac80211(vif); if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { - iwl_mvm_cancel_session_protection(mvm, mvmvif); + iwl_mvm_cancel_session_protection(mvm, mvmvif, + mvmvif->time_event_data.id); set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); } else { iwl_mvm_remove_aux_roc_te(mvm, mvmvif, @@ -1145,6 +1163,7 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, iwl_mvm_te_clear_data(mvm, te_data); te_data->duration = le32_to_cpu(cmd.duration_tu); + te_data->vif = vif; spin_unlock_bh(&mvm->time_event_lock); IWL_DEBUG_TE(mvm, "Add new session protection, duration %d TU\n", From b1c6cec04bbc1fe7e83cc7a1b054cc962feffb7e Mon Sep 17 00:00:00 2001 From: Naftali Goldstein Date: Fri, 18 Jun 2021 11:01:13 +0300 Subject: [PATCH 130/170] iwlwifi: mvm: don't request mac80211 to disable/enable sta's queues When operating in AP mode with NICs supporting the AP_LINK_PS hw flag, mac80211 doesn't need to start/stop queueing tx for connected stations because the FW already handles that. Signed-off-by: Naftali Goldstein Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210618105614.64df994c8fbb.I0fa5cda3a5f893a396eef30a01522422be359e69@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index f618368eda83..9c45a64c5009 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -3794,8 +3794,12 @@ void iwl_mvm_sta_modify_disable_tx_ap(struct iwl_mvm *mvm, mvm_sta->disable_tx = disable; - /* Tell mac80211 to start/stop queuing tx for this station */ - ieee80211_sta_block_awake(mvm->hw, sta, disable); + /* + * If sta PS state is handled by mac80211, tell it to start/stop + * queuing tx for this station. + */ + if (!ieee80211_hw_check(mvm->hw, AP_LINK_PS)) + ieee80211_sta_block_awake(mvm->hw, sta, disable); iwl_mvm_sta_modify_disable_tx(mvm, mvm_sta, disable); From 5b16565a7f9d82c6aa475ede72d62424b70f7726 Mon Sep 17 00:00:00 2001 From: Naftali Goldstein Date: Fri, 18 Jun 2021 11:01:14 +0300 Subject: [PATCH 131/170] iwlwifi: support ver 6 of WOWLAN_CONFIGURATION and ver 10 of WOWLAN_GET_STATUSES These two version updates deprecate the need to set/get the nonqos sequence counter during suspend/resume flow respectively; NICs supporting this version maintain this counter internally and don't lose it during the suspend/resume flow. Note that this means that for such NICs the NON_QOS_TX_COUNTER_CMD is no longer ever sent. Signed-off-by: Naftali Goldstein Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210618105614.dd25dd667798.I8db9adcdbb133304b58cf417f8698611138c83b4@changeid Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/d3.h | 12 +++++---- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 26 ++++++++++++------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index 6488c0f8b471..5373182c1364 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -339,9 +339,10 @@ enum iwl_wowlan_flags { }; /** - * struct iwl_wowlan_config_cmd - WoWLAN configuration + * struct iwl_wowlan_config_cmd - WoWLAN configuration (versions 5 and 6) * @wakeup_filter: filter from &enum iwl_wowlan_wakeup_filters - * @non_qos_seq: non-QoS sequence counter to use next + * @non_qos_seq: non-QoS sequence counter to use next. + * Reserved if the struct has version >= 6. * @qos_seq: QoS sequence counters to use next * @wowlan_ba_teardown_tids: bitmap of BA sessions to tear down * @is_11n_connection: indicates HT connection @@ -604,12 +605,13 @@ struct iwl_wowlan_status_v7 { } __packed; /* WOWLAN_STATUSES_API_S_VER_7 */ /** - * struct iwl_wowlan_status_v9 - WoWLAN status (version 9) + * struct iwl_wowlan_status_v9 - WoWLAN status (versions 9 and 10) * @gtk: GTK data * @igtk: IGTK data * @replay_ctr: GTK rekey replay counter * @pattern_number: number of the matched pattern - * @non_qos_seq_ctr: non-QoS sequence counter to use next + * @non_qos_seq_ctr: non-QoS sequence counter to use next. + * Reserved if the struct has version >= 10. * @qos_seq_ctr: QoS sequence counters to use next * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason * @num_of_gtk_rekeys: number of GTK rekeys @@ -638,7 +640,7 @@ struct iwl_wowlan_status_v9 { u8 tid_tear_down; u8 reserved[3]; u8 wake_packet[]; /* can be truncated from _length to _bufsize */ -} __packed; /* WOWLAN_STATUSES_API_S_VER_9 */ +} __packed; /* WOWLAN_STATUSES_RSP_API_S_VER_9 */ /** * struct iwl_wowlan_status - WoWLAN status diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 2e28cf299ef4..e86f0e949b86 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -636,7 +636,6 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif, struct ieee80211_sta *ap_sta) { - int ret; struct iwl_mvm_sta *mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta); /* TODO: wowlan_config_cmd->wowlan_ba_teardown_tids */ @@ -646,12 +645,16 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, wowlan_config_cmd->flags = ENABLE_L3_FILTERING | ENABLE_NBNS_FILTERING | ENABLE_DHCP_FILTERING; - /* Query the last used seqno and set it */ - ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); - if (ret < 0) - return ret; + if (iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, + WOWLAN_CONFIGURATION, 0) < 6) { + /* Query the last used seqno and set it */ + int ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); - wowlan_config_cmd->non_qos_seq = cpu_to_le16(ret); + if (ret < 0) + return ret; + + wowlan_config_cmd->non_qos_seq = cpu_to_le16(ret); + } iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, wowlan_config_cmd); @@ -1534,9 +1537,12 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, } out: - mvmvif->seqno_valid = true; - /* +0x10 because the set API expects next-to-use, not last-used */ - mvmvif->seqno = le16_to_cpu(status->non_qos_seq_ctr) + 0x10; + if (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, + WOWLAN_GET_STATUSES, 0) < 10) { + mvmvif->seqno_valid = true; + /* +0x10 because the set API expects next-to-use, not last-used */ + mvmvif->seqno = le16_to_cpu(status->non_qos_seq_ctr) + 0x10; + } return true; } @@ -1654,7 +1660,7 @@ struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm) status->gtk[0] = v7->gtk[0]; status->igtk[0] = v7->igtk[0]; - } else if (notif_ver == 9) { + } else if (notif_ver == 9 || notif_ver == 10) { struct iwl_wowlan_status_v9 *v9 = (void *)cmd.resp_pkt->data; status = iwl_mvm_parse_wowlan_status_common_v9(mvm, From d65ab7c0e0b92056754185d3f6925d7318730e94 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Fri, 18 Jun 2021 11:01:15 +0300 Subject: [PATCH 132/170] iwlwifi: mvm: support LONG_GROUP for WOWLAN_GET_STATUSES version It's been a while that the firmware uses LONG_GROUP by default and not LEGACY_GROUP. Until now the firmware wrongly advertise the WOWLAN_GET_STATUS command's version with LEGACY_GROUP, but it is now being fixed. In order to support both firmwares, first try to get the version number of the command with the LONG_GROUP and if the firmware didn't advertise the command version with LONG_GROUP, try to get the command version with LEGACY_GROUP. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210618105614.cd6f4e421430.Iec07c746c8e65bc267e4750f38e4f74f2010ca45@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index e86f0e949b86..6617fe5a7ece 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1614,8 +1614,11 @@ struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm) len = iwl_rx_packet_payload_len(cmd.resp_pkt); /* default to 7 (when we have IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL) */ - notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, - WOWLAN_GET_STATUSES, 7); + notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, + WOWLAN_GET_STATUSES, 0); + if (!notif_ver) + notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + WOWLAN_GET_STATUSES, 7); if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL)) { From 310f60f53a86eba680d9bc20a371e13b06a5f903 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 18 Jun 2021 11:01:16 +0300 Subject: [PATCH 133/170] iwlwifi: pcie: free IML DMA memory allocation In the case of gen3 devices with image loader (IML) support, we were leaking the IML DMA allocation and never freeing it. Fix that. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210618105614.07e117dbedb7.I7bb9ebbe0617656986c2a598ea5e827b533bd3b9@changeid Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c | 15 ++++++++++----- .../net/wireless/intel/iwlwifi/pcie/internal.h | 3 +++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index 49560e508b5e..c7b9ca264429 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -79,7 +79,6 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, struct iwl_prph_scratch *prph_scratch; struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl; struct iwl_prph_info *prph_info; - void *iml_img; u32 control_flags = 0; int ret; int cmdq_size = max_t(u32, IWL_CMD_QUEUE_SIZE, @@ -190,14 +189,15 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, trans_pcie->prph_scratch = prph_scratch; /* Allocate IML */ - iml_img = dma_alloc_coherent(trans->dev, trans->iml_len, - &trans_pcie->iml_dma_addr, GFP_KERNEL); - if (!iml_img) { + trans_pcie->iml = dma_alloc_coherent(trans->dev, trans->iml_len, + &trans_pcie->iml_dma_addr, + GFP_KERNEL); + if (!trans_pcie->iml) { ret = -ENOMEM; goto err_free_ctxt_info; } - memcpy(iml_img, trans->iml, trans->iml_len); + memcpy(trans_pcie->iml, trans->iml, trans->iml_len); iwl_enable_fw_load_int_ctx_info(trans); @@ -244,6 +244,11 @@ void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans) trans_pcie->ctxt_info_dma_addr = 0; trans_pcie->ctxt_info_gen3 = NULL; + dma_free_coherent(trans->dev, trans->iml_len, trans_pcie->iml, + trans_pcie->iml_dma_addr); + trans_pcie->iml_dma_addr = 0; + trans_pcie->iml = NULL; + iwl_pcie_ctxt_info_free_fw_img(trans); dma_free_coherent(trans->dev, sizeof(*trans_pcie->prph_scratch), diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 292b972a25db..69289e9f8d7e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -271,6 +271,8 @@ struct cont_rec { * Context information addresses will be taken from here. * This is driver's local copy for keeping track of size and * count for allocating and freeing the memory. + * @iml: image loader image virtual address + * @iml_dma_addr: image loader image DMA address * @trans: pointer to the generic transport area * @scd_base_addr: scheduler sram base address in SRAM * @kw: keep warm address @@ -322,6 +324,7 @@ struct iwl_trans_pcie { }; struct iwl_prph_info *prph_info; struct iwl_prph_scratch *prph_scratch; + void *iml; dma_addr_t ctxt_info_dma_addr; dma_addr_t prph_info_dma_addr; dma_addr_t prph_scratch_dma_addr; From 26d18c75a7496c4c52b0b6789e713dc76ebfbc87 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 18 Jun 2021 11:01:17 +0300 Subject: [PATCH 134/170] iwlwifi: pcie: fix context info freeing After firmware alive, iwl_trans_pcie_gen2_fw_alive() is called to free the context info. However, on gen3 that will then free the context info with the wrong size. Since we free this allocation later, let it stick around until the device is stopped for now, freeing some of it earlier is a separate change. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210618105614.afb63fb8cbc1.If4968db8e09f4ce2a1d27a6d750bca3d132d7d70@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index 56162c4500d7..93b957866beb 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -323,7 +323,8 @@ void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr) /* now that we got alive we can free the fw image & the context info. * paging memory cannot be freed included since FW will still use it */ - iwl_pcie_ctxt_info_free(trans); + if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) + iwl_pcie_ctxt_info_free(trans); /* * Re-enable all the interrupts, including the RF-Kill one, now that From fa331068a591d9df5f345173c0c9c44234b61569 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 18 Jun 2021 11:01:18 +0300 Subject: [PATCH 135/170] iwlwifi: mvm: fill phy_data.d1 for no-data RX We don't fill in phy_data.d1 in no-data RX, and thus we pretend some data is actually filled in radiotap when it isn't or has default (zero) values. Fill in phy_data.d1 appropriately, and while at it also move the info_type initialization into the initializer. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210618105614.3d488885f77c.Ib97a2bc57c1e9fb98927dc6f802568db313abe3b@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 8e26422ca326..c0babb8d5b5c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -2001,8 +2001,10 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi, struct sk_buff *skb; u8 channel, energy_a, energy_b; struct iwl_mvm_rx_phy_data phy_data = { + .info_type = le32_get_bits(desc->phy_info[1], + IWL_RX_PHY_DATA1_INFO_TYPE_MASK), .d0 = desc->phy_info[0], - .info_type = IWL_RX_PHY_INFO_TYPE_NONE, + .d1 = desc->phy_info[1], }; if (unlikely(iwl_rx_packet_payload_len(pkt) < sizeof(*desc))) @@ -2015,10 +2017,6 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi, energy_b = (rssi & RX_NO_DATA_CHAIN_B_MSK) >> RX_NO_DATA_CHAIN_B_POS; channel = (rssi & RX_NO_DATA_CHANNEL_MSK) >> RX_NO_DATA_CHANNEL_POS; - phy_data.info_type = - le32_get_bits(desc->phy_info[1], - IWL_RX_PHY_DATA1_INFO_TYPE_MASK); - /* Dont use dev_alloc_skb(), we'll have enough headroom once * ieee80211_hdr pulled. */ From 947689756352af9bd0486c1a19fffc7837ae0335 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 18 Jun 2021 11:01:19 +0300 Subject: [PATCH 136/170] iwlwifi: pcie: free some DMA memory earlier In gen3, after firmware is alive, we no longer need the firmware and image loader images, only the context info itself and PRPH info/scratch need to remain. Call iwl_pcie_ctxt_info_gen3_free() appropriately in the alive callback (iwl_trans_pcie_gen2_fw_alive()) with a new argument indicating whether it can free everything or only partially. The context info and PRPH scratch are also not needed after PNVM load, but we don't have a good hook for freeing after that, so keep them for now. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210618105614.8230d91a46c1.Ia7db71e5e6265ca87363f1481eac1bc3bbebb15c@changeid Signed-off-by: Luca Coelho --- .../intel/iwlwifi/iwl-context-info-gen3.h | 4 ++-- .../intel/iwlwifi/pcie/ctxt-info-gen3.c | 23 ++++++++++++------- .../wireless/intel/iwlwifi/pcie/trans-gen2.c | 6 +++-- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h index 2be605cc6fbf..518a1bc79584 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2018, 2020 Intel Corporation + * Copyright (C) 2018, 2020-2021 Intel Corporation */ #ifndef __iwl_context_info_file_gen3_h__ #define __iwl_context_info_file_gen3_h__ @@ -245,7 +245,7 @@ struct iwl_context_info_gen3 { int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, const struct fw_img *fw); -void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans); +void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive); int iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans, const void *data, u32 len); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index c7b9ca264429..c69a1541e678 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -231,32 +231,39 @@ err_free_prph_scratch: } -void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans) +void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + if (trans_pcie->iml) { + dma_free_coherent(trans->dev, trans->iml_len, trans_pcie->iml, + trans_pcie->iml_dma_addr); + trans_pcie->iml_dma_addr = 0; + trans_pcie->iml = NULL; + } + + iwl_pcie_ctxt_info_free_fw_img(trans); + + if (alive) + return; + if (!trans_pcie->ctxt_info_gen3) return; + /* ctxt_info_gen3 and prph_scratch are still needed for PNVM load */ dma_free_coherent(trans->dev, sizeof(*trans_pcie->ctxt_info_gen3), trans_pcie->ctxt_info_gen3, trans_pcie->ctxt_info_dma_addr); trans_pcie->ctxt_info_dma_addr = 0; trans_pcie->ctxt_info_gen3 = NULL; - dma_free_coherent(trans->dev, trans->iml_len, trans_pcie->iml, - trans_pcie->iml_dma_addr); - trans_pcie->iml_dma_addr = 0; - trans_pcie->iml = NULL; - - iwl_pcie_ctxt_info_free_fw_img(trans); - dma_free_coherent(trans->dev, sizeof(*trans_pcie->prph_scratch), trans_pcie->prph_scratch, trans_pcie->prph_scratch_dma_addr); trans_pcie->prph_scratch_dma_addr = 0; trans_pcie->prph_scratch = NULL; + /* this is needed for the entire lifetime */ dma_free_coherent(trans->dev, PAGE_SIZE, trans_pcie->prph_info, trans_pcie->prph_info_dma_addr); trans_pcie->prph_info_dma_addr = 0; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index 93b957866beb..a34009357227 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -149,7 +149,7 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) iwl_pcie_ctxt_info_free_paging(trans); if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) - iwl_pcie_ctxt_info_gen3_free(trans); + iwl_pcie_ctxt_info_gen3_free(trans, false); else iwl_pcie_ctxt_info_free(trans); @@ -323,7 +323,9 @@ void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr) /* now that we got alive we can free the fw image & the context info. * paging memory cannot be freed included since FW will still use it */ - if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) + iwl_pcie_ctxt_info_gen3_free(trans, true); + else iwl_pcie_ctxt_info_free(trans); /* From 12236e9af903f7a36f24d24a9b70ba8f8e2859e4 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 18 Jun 2021 11:01:20 +0300 Subject: [PATCH 137/170] iwlwifi: fix NUM_IWL_UCODE_TLV_* definitions to avoid sparse errors We were assigning these macros manually when sparse is running, but with newer versions of sparse, it started causing other warnings. Fix it by making it a macro when sparse is running. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210618105614.dc658639e07f.I69ab6d59ff10c55c8517621eb20a52194dc4783a@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/file.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index d189e5de478b..ef1a24504c8b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -277,10 +277,11 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_BAND_IN_RX_DATA = (__force iwl_ucode_tlv_api_t)59, - NUM_IWL_UCODE_TLV_API #ifdef __CHECKER__ - /* sparse says it cannot increment the previous enum member */ - = 128 + /* sparse says it cannot increment the previous enum member */ +#define NUM_IWL_UCODE_TLV_API 128 +#else + NUM_IWL_UCODE_TLV_API #endif }; @@ -447,10 +448,11 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_BIGTK_SUPPORT = (__force iwl_ucode_tlv_capa_t)100, IWL_UCODE_TLV_CAPA_RFIM_SUPPORT = (__force iwl_ucode_tlv_capa_t)102, - NUM_IWL_UCODE_TLV_CAPA #ifdef __CHECKER__ - /* sparse says it cannot increment the previous enum member */ - = 128 + /* sparse says it cannot increment the previous enum member */ +#define NUM_IWL_UCODE_TLV_CAPA 128 +#else + NUM_IWL_UCODE_TLV_CAPA #endif }; From b60bc716ba26319205d570406187fd941a96bdf3 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Fri, 18 Jun 2021 11:01:21 +0300 Subject: [PATCH 138/170] iwlwifi: mvm: introduce iwl_proto_offload_cmd_v4 We need to pass the station id to tell the firmware on which station we want to configure the protocol offload. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210618105614.c25913d2c08c.Ic0fefac81afb9a2fe396d73528e30e09a8c5eae0@changeid Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/d3.h | 16 ++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 11 +++++--- .../wireless/intel/iwlwifi/mvm/offloading.c | 26 ++++++++++++++----- 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index 5373182c1364..a9e8f30ef91d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -159,6 +159,22 @@ struct iwl_proto_offload_cmd_v3_large { struct iwl_ns_config ns_config[IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L]; } __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_3 */ +/** + * struct iwl_proto_offload_cmd_v4 - ARP/NS offload configuration + * @sta_id: station id + * @common: common/IPv4 configuration + * @num_valid_ipv6_addrs: number of valid IPv6 addresses + * @targ_addrs: target IPv6 addresses + * @ns_config: NS offload configurations + */ +struct iwl_proto_offload_cmd_v4 { + __le32 sta_id; + struct iwl_proto_offload_cmd_common common; + __le32 num_valid_ipv6_addrs; + struct iwl_targ_addr targ_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L]; + struct iwl_ns_config ns_config[IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L]; +} __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_4 */ + /* * WOWLAN_PATTERNS */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 6617fe5a7ece..7b13c4fc1b58 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1693,10 +1693,13 @@ iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm) { int ret; - /* only for tracing for now */ - ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, 0, 0, NULL); - if (ret) - IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret); + if (!mvm->net_detect) { + /* only for tracing for now */ + int ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, 0, + 0, NULL); + if (ret) + IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret); + } return iwl_mvm_send_wowlan_get_status(mvm); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c index 1cc90e61367b..41880517e8bb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014 Intel Corporation + * Copyright (C) 2012-2014, 2021 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 Intel Deutschland GmbH */ @@ -36,7 +36,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct iwl_proto_offload_cmd_v1 v1; struct iwl_proto_offload_cmd_v2 v2; struct iwl_proto_offload_cmd_v3_small v3s; - struct iwl_proto_offload_cmd_v3_large v3l; + struct iwl_proto_offload_cmd_v4 v4; } cmd = {}; struct iwl_host_cmd hcmd = { .id = PROT_OFFLOAD_CONFIG_CMD, @@ -47,6 +47,9 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct iwl_proto_offload_cmd_common *common; u32 enabled = 0, size; u32 capa_flags = mvm->fw->ucode_capa.flags; + int ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, + PROT_OFFLOAD_CONFIG_CMD, 0); + #if IS_ENABLED(CONFIG_IPV6) struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int i; @@ -72,9 +75,9 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, addrs = cmd.v3s.targ_addrs; n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S; } else { - nsc = cmd.v3l.ns_config; + nsc = cmd.v4.ns_config; n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L; - addrs = cmd.v3l.targ_addrs; + addrs = cmd.v4.targ_addrs; n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L; } @@ -116,7 +119,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, cmd.v3s.num_valid_ipv6_addrs = cpu_to_le32(i - num_skipped); else - cmd.v3l.num_valid_ipv6_addrs = + cmd.v4.num_valid_ipv6_addrs = cpu_to_le32(i - num_skipped); } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { bool found = false; @@ -171,8 +174,17 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, common = &cmd.v3s.common; size = sizeof(cmd.v3s); } else if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) { - common = &cmd.v3l.common; - size = sizeof(cmd.v3l); + common = &cmd.v4.common; + size = sizeof(cmd.v4); + if (ver < 4) { + /* + * This basically uses iwl_proto_offload_cmd_v3_large + * which doesn't have the sta_id parameter before the + * common part. + */ + size -= sizeof(cmd.v4.sta_id); + hcmd.data[0] = common; + } } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { common = &cmd.v2.common; size = sizeof(cmd.v2); From 0b35991a80762773078aa8ba044baf485b293e45 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 21 Jun 2021 10:37:32 +0300 Subject: [PATCH 139/170] iwlwifi: mvm: update iwl_wowlan_patterns_cmd We need to pass the station id to tell the firmware on which station we want to configure the patterns. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210621103449.73eceb822890.I37347afbc01497a8a9e4d4afe4fa9a965abd31ac@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/d3.h | 14 ++++++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 13 ++++++++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index a9e8f30ef91d..4dbf24128a98 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -318,13 +318,23 @@ struct iwl_wowlan_patterns_cmd { /** * @n_patterns: number of patterns */ - __le32 n_patterns; + u8 n_patterns; + + /** + * @n_patterns: sta_id + */ + u8 sta_id; + + /** + * @reserved: reserved for alignment + */ + __le16 reserved; /** * @patterns: the patterns, array length in @n_patterns */ struct iwl_wowlan_pattern_v2 patterns[]; -} __packed; /* WOWLAN_PATTERN_ARRAY_API_S_VER_2 */ +} __packed; /* WOWLAN_PATTERN_ARRAY_API_S_VER_3 */ enum iwl_wowlan_wakeup_filters { IWL_WOWLAN_WAKEUP_MAGIC_PACKET = BIT(0), diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 7b13c4fc1b58..8e5814a3b178 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -393,14 +393,19 @@ static int iwl_mvm_send_patterns_v1(struct iwl_mvm *mvm, } static int iwl_mvm_send_patterns(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, struct cfg80211_wowlan *wowlan) { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_wowlan_patterns_cmd *pattern_cmd; struct iwl_host_cmd cmd = { .id = WOWLAN_PATTERNS, .dataflags[0] = IWL_HCMD_DFL_NOCOPY, }; int i, err; + int ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, + WOWLAN_PATTERNS, + IWL_FW_CMD_VER_UNKNOWN); if (!wowlan->n_patterns) return 0; @@ -408,11 +413,13 @@ static int iwl_mvm_send_patterns(struct iwl_mvm *mvm, cmd.len[0] = sizeof(*pattern_cmd) + wowlan->n_patterns * sizeof(struct iwl_wowlan_pattern_v2); - pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL); + pattern_cmd = kzalloc(cmd.len[0], GFP_KERNEL); if (!pattern_cmd) return -ENOMEM; - pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns); + pattern_cmd->n_patterns = wowlan->n_patterns; + if (ver >= 3) + pattern_cmd->sta_id = mvmvif->ap_sta_id; for (i = 0; i < wowlan->n_patterns; i++) { int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8); @@ -887,7 +894,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WOWLAN_TCP_SYN_WAKE)) - ret = iwl_mvm_send_patterns(mvm, wowlan); + ret = iwl_mvm_send_patterns(mvm, vif, wowlan); else ret = iwl_mvm_send_patterns_v1(mvm, wowlan); if (ret) From 80e6711919d4a13d00dfed185d850316b7f993ce Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 21 Jun 2021 10:37:33 +0300 Subject: [PATCH 140/170] iwlwifi: mvm: introduce iwl_wowlan_kek_kck_material_cmd_v4 We need to pass the station id to teach the firmware on which station id we want to configure the key material. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210621103449.13417410e9ea.I140c16e70f8ac91cec7e8189e182e2f672c39258@changeid Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/d3.h | 13 ++++++++ drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 30 +++++++++++++------ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index 4dbf24128a98..ea2bd34e32a3 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -483,6 +483,19 @@ struct iwl_wowlan_kek_kck_material_cmd_v3 { __le32 bigtk_cipher; } __packed; /* KEK_KCK_MATERIAL_API_S_VER_3 */ +struct iwl_wowlan_kek_kck_material_cmd_v4 { + __le32 sta_id; + u8 kck[IWL_KCK_MAX_SIZE]; + u8 kek[IWL_KEK_MAX_SIZE]; + __le16 kck_len; + __le16 kek_len; + __le64 replay_ctr; + __le32 akm; + __le32 gtk_cipher; + __le32 igtk_cipher; + __le32 bigtk_cipher; +} __packed; /* KEK_KCK_MATERIAL_API_S_VER_4 */ + #define RF_KILL_INDICATOR_FOR_WOWLAN 0x87 enum iwl_wowlan_rekey_status { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 8e5814a3b178..0777a709740b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -104,7 +104,7 @@ static const u8 *iwl_mvm_find_max_pn(struct ieee80211_key_conf *key, struct wowlan_key_data { struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc; struct iwl_wowlan_tkip_params_cmd *tkip; - struct iwl_wowlan_kek_kck_material_cmd_v3 *kek_kck_cmd; + struct iwl_wowlan_kek_kck_material_cmd_v4 *kek_kck_cmd; bool error, use_rsc_tsc, use_tkip, configure_keys; int wep_key_idx; }; @@ -716,7 +716,8 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u32 cmd_flags) { - struct iwl_wowlan_kek_kck_material_cmd_v3 kek_kck_cmd = {}; + struct iwl_wowlan_kek_kck_material_cmd_v4 kek_kck_cmd = {}; + struct iwl_wowlan_kek_kck_material_cmd_v4 *_kek_kck_cmd = &kek_kck_cmd; struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; bool unified = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); @@ -725,7 +726,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, .use_rsc_tsc = false, .tkip = &tkip_cmd, .use_tkip = false, - .kek_kck_cmd = &kek_kck_cmd, + .kek_kck_cmd = _kek_kck_cmd, }; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; @@ -819,13 +820,9 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, IWL_ALWAYS_LONG_GROUP, WOWLAN_KEK_KCK_MATERIAL, IWL_FW_CMD_VER_UNKNOWN); - if (WARN_ON(cmd_ver != 2 && cmd_ver != 3 && + if (WARN_ON(cmd_ver != 2 && cmd_ver != 3 && cmd_ver != 4 && cmd_ver != IWL_FW_CMD_VER_UNKNOWN)) return -EINVAL; - if (cmd_ver == 3) - cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v3); - else - cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v2); memcpy(kek_kck_cmd.kck, mvmvif->rekey_data.kck, mvmvif->rekey_data.kck_len); @@ -835,6 +832,21 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, kek_kck_cmd.kek_len = cpu_to_le16(mvmvif->rekey_data.kek_len); kek_kck_cmd.replay_ctr = mvmvif->rekey_data.replay_ctr; kek_kck_cmd.akm = cpu_to_le32(mvmvif->rekey_data.akm); + kek_kck_cmd.sta_id = cpu_to_le32(mvmvif->ap_sta_id); + + if (cmd_ver == 4) { + cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v4); + } else { + if (cmd_ver == 3) + cmd_size = + sizeof(struct iwl_wowlan_kek_kck_material_cmd_v3); + else + cmd_size = + sizeof(struct iwl_wowlan_kek_kck_material_cmd_v2); + /* skip the sta_id at the beginning */ + _kek_kck_cmd = (void *) + ((u8 *)_kek_kck_cmd) + sizeof(kek_kck_cmd.sta_id); + } IWL_DEBUG_WOWLAN(mvm, "setting akm %d\n", mvmvif->rekey_data.akm); @@ -842,7 +854,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_KEK_KCK_MATERIAL, cmd_flags, cmd_size, - &kek_kck_cmd); + _kek_kck_cmd); if (ret) goto out; } From 5c157941cda00e9a1127a7a909177900f9195e19 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 21 Jun 2021 10:37:34 +0300 Subject: [PATCH 141/170] iwlwifi: mvm: introduce iwl_wowlan_get_status_cmd We need to pass the station id to teach the firmware on which station id we want to get the status. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210621103449.45218d913d07.I61a086936508230d86b454636945ceb0b9ea09fd@changeid Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/d3.h | 4 +++ drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 31 ++++++++++++++----- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 - 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index ea2bd34e32a3..b2e7ef3ddc88 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -496,6 +496,10 @@ struct iwl_wowlan_kek_kck_material_cmd_v4 { __le32 bigtk_cipher; } __packed; /* KEK_KCK_MATERIAL_API_S_VER_4 */ +struct iwl_wowlan_get_status_cmd { + __le32 sta_id; +} __packed; /* WOWLAN_GET_STATUSES_CMD_API_S_VER_1 */ + #define RF_KILL_INDICATOR_FOR_WOWLAN 0x87 enum iwl_wowlan_rekey_status { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 0777a709740b..6a259d867d90 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1612,15 +1612,27 @@ iwl_mvm_parse_wowlan_status_common(v6) iwl_mvm_parse_wowlan_status_common(v7) iwl_mvm_parse_wowlan_status_common(v9) -struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm) +static struct iwl_wowlan_status * +iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) { struct iwl_wowlan_status *status; + struct iwl_wowlan_get_status_cmd get_status_cmd = { + .sta_id = cpu_to_le32(sta_id), + }; struct iwl_host_cmd cmd = { .id = WOWLAN_GET_STATUSES, .flags = CMD_WANT_SKB, + .data = { &get_status_cmd, }, + .len = { sizeof(get_status_cmd), }, }; int ret, len; u8 notif_ver; + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, + WOWLAN_GET_STATUSES, + IWL_FW_CMD_VER_UNKNOWN); + + if (cmd_ver == IWL_FW_CMD_VER_UNKNOWN) + cmd.len[0] = 0; lockdep_assert_held(&mvm->mutex); @@ -1708,32 +1720,37 @@ out_free_resp: } static struct iwl_wowlan_status * -iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm) +iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, u8 sta_id) { - int ret; + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, + OFFLOADS_QUERY_CMD, + IWL_FW_CMD_VER_UNKNOWN); + __le32 station_id = cpu_to_le32(sta_id); + u32 cmd_size = cmd_ver != IWL_FW_CMD_VER_UNKNOWN ? sizeof(station_id) : 0; if (!mvm->net_detect) { /* only for tracing for now */ int ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, 0, - 0, NULL); + cmd_size, &station_id); if (ret) IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret); } - return iwl_mvm_send_wowlan_get_status(mvm); + return iwl_mvm_send_wowlan_get_status(mvm, sta_id); } /* releases the MVM mutex */ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_wowlan_status_data status; struct iwl_wowlan_status *fw_status; int i; bool keep; struct iwl_mvm_sta *mvm_ap_sta; - fw_status = iwl_mvm_get_wakeup_status(mvm); + fw_status = iwl_mvm_get_wakeup_status(mvm, mvmvif->ap_sta_id); if (IS_ERR_OR_NULL(fw_status)) goto out_unlock; @@ -1911,7 +1928,7 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm, u32 reasons = 0; int i, n_matches, ret; - fw_status = iwl_mvm_get_wakeup_status(mvm); + fw_status = iwl_mvm_get_wakeup_status(mvm, IWL_MVM_INVALID_STA); if (!IS_ERR_OR_NULL(fw_status)) { reasons = le32_to_cpu(fw_status->wakeup_reasons); kfree(fw_status); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index d89c73ae2848..bf99eed23a9f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1775,7 +1775,6 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int idx); extern const struct file_operations iwl_dbgfs_d3_test_ops; -struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm); #ifdef CONFIG_PM void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif); From 84c3c9952afbf7df39937095aa0ad70b58703e91 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Mon, 21 Jun 2021 10:37:35 +0300 Subject: [PATCH 142/170] iwlwifi: move UEFI code to a separate file We are going to read more variables from UEFI, so it's cleaner to have all the code that handles UEFI variables in a separate file. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210621103449.c705ac86f2e9.Ia7421c17fe52929e4098b4f0cf070809ed3ef906@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/Makefile | 1 + drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 105 +++++-------------- drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 64 +++++++++++ drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 25 +++++ 4 files changed, 114 insertions(+), 81 deletions(-) create mode 100644 drivers/net/wireless/intel/iwlwifi/fw/uefi.c create mode 100644 drivers/net/wireless/intel/iwlwifi/fw/uefi.h diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index 14b0db28143b..a8428c27286c 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -19,6 +19,7 @@ iwlwifi-objs += fw/img.o fw/notif-wait.o iwlwifi-objs += fw/dbg.o fw/pnvm.o iwlwifi-$(CONFIG_IWLMVM) += fw/paging.o fw/smem.o fw/init.o iwlwifi-$(CONFIG_ACPI) += fw/acpi.o +iwlwifi-$(CONFIG_EFI) += fw/uefi.o iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += fw/debugfs.o iwlwifi-objs += $(iwlwifi-m) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 40f2109a097f..565c19475155 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -10,13 +10,22 @@ #include "fw/api/commands.h" #include "fw/api/nvm-reg.h" #include "fw/api/alive.h" -#include +#include "fw/uefi.h" struct iwl_pnvm_section { __le32 offset; const u8 data[]; } __packed; +struct pnvm_sku_package { + u8 rev; + u8 reserved1[3]; + u32 total_size; + u8 n_skus; + u8 reserved2[11]; + u8 data[]; +}; + static bool iwl_pnvm_complete_fn(struct iwl_notif_wait_data *notif_wait, struct iwl_rx_packet *pkt, void *data) { @@ -220,83 +229,6 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, return -ENOENT; } -#if defined(CONFIG_EFI) - -#define IWL_EFI_VAR_GUID EFI_GUID(0x92daaf2f, 0xc02b, 0x455b, \ - 0xb2, 0xec, 0xf5, 0xa3, \ - 0x59, 0x4f, 0x4a, 0xea) - -#define IWL_UEFI_OEM_PNVM_NAME L"UefiCnvWlanOemSignedPnvm" - -#define IWL_HARDCODED_PNVM_SIZE 4096 - -struct pnvm_sku_package { - u8 rev; - u8 reserved1[3]; - u32 total_size; - u8 n_skus; - u8 reserved2[11]; - u8 data[]; -}; - -static int iwl_pnvm_get_from_efi(struct iwl_trans *trans, - u8 **data, size_t *len) -{ - struct efivar_entry *pnvm_efivar; - struct pnvm_sku_package *package; - unsigned long package_size; - int err; - - pnvm_efivar = kzalloc(sizeof(*pnvm_efivar), GFP_KERNEL); - if (!pnvm_efivar) - return -ENOMEM; - - memcpy(&pnvm_efivar->var.VariableName, IWL_UEFI_OEM_PNVM_NAME, - sizeof(IWL_UEFI_OEM_PNVM_NAME)); - pnvm_efivar->var.VendorGuid = IWL_EFI_VAR_GUID; - - /* - * TODO: we hardcode a maximum length here, because reading - * from the UEFI is not working. To implement this properly, - * we have to call efivar_entry_size(). - */ - package_size = IWL_HARDCODED_PNVM_SIZE; - - package = kmalloc(package_size, GFP_KERNEL); - if (!package) { - err = -ENOMEM; - goto out; - } - - err = efivar_entry_get(pnvm_efivar, NULL, &package_size, package); - if (err) { - IWL_DEBUG_FW(trans, - "PNVM UEFI variable not found %d (len %lu)\n", - err, package_size); - goto out; - } - - IWL_DEBUG_FW(trans, "Read PNVM fro UEFI with size %lu\n", package_size); - - *data = kmemdup(package->data, *len, GFP_KERNEL); - if (!*data) - err = -ENOMEM; - *len = package_size - sizeof(*package); - -out: - kfree(package); - kfree(pnvm_efivar); - - return err; -} -#else /* CONFIG_EFI */ -static inline int iwl_pnvm_get_from_efi(struct iwl_trans *trans, - u8 **data, size_t *len) -{ - return -EOPNOTSUPP; -} -#endif /* CONFIG_EFI */ - static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len) { const struct firmware *pnvm; @@ -335,6 +267,7 @@ int iwl_pnvm_load(struct iwl_trans *trans, { u8 *data; size_t len; + struct pnvm_sku_package *package; struct iwl_notification_wait pnvm_wait; static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP, PNVM_INIT_COMPLETE_NTFY) }; @@ -356,9 +289,19 @@ int iwl_pnvm_load(struct iwl_trans *trans, } /* First attempt to get the PNVM from BIOS */ - ret = iwl_pnvm_get_from_efi(trans, &data, &len); - if (!ret) - goto parse; + package = iwl_uefi_get_pnvm(trans, &len); + if (!IS_ERR_OR_NULL(package)) { + data = kmemdup(package->data, len, GFP_KERNEL); + + /* free package regardless of whether kmemdup succeeded */ + kfree(package); + + if (data) { + /* we need only the data size */ + len -= sizeof(*package); + goto parse; + } + } /* If it's not available, try from the filesystem */ ret = iwl_pnvm_get_from_fs(trans, &data, &len); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c new file mode 100644 index 000000000000..bdcdca178eda --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright(c) 2021 Intel Corporation + */ + +#include "iwl-drv.h" +#include "pnvm.h" +#include "iwl-prph.h" +#include "iwl-io.h" + +#include "fw/uefi.h" +#include + +#define IWL_EFI_VAR_GUID EFI_GUID(0x92daaf2f, 0xc02b, 0x455b, \ + 0xb2, 0xec, 0xf5, 0xa3, \ + 0x59, 0x4f, 0x4a, 0xea) + +void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) +{ + struct efivar_entry *pnvm_efivar; + void *data; + unsigned long package_size; + int err; + + pnvm_efivar = kzalloc(sizeof(*pnvm_efivar), GFP_KERNEL); + if (!pnvm_efivar) + return ERR_PTR(-ENOMEM); + + memcpy(&pnvm_efivar->var.VariableName, IWL_UEFI_OEM_PNVM_NAME, + sizeof(IWL_UEFI_OEM_PNVM_NAME)); + pnvm_efivar->var.VendorGuid = IWL_EFI_VAR_GUID; + + /* + * TODO: we hardcode a maximum length here, because reading + * from the UEFI is not working. To implement this properly, + * we have to call efivar_entry_size(). + */ + package_size = IWL_HARDCODED_PNVM_SIZE; + + data = kmalloc(package_size, GFP_KERNEL); + if (!data) { + data = ERR_PTR(-ENOMEM); + *len = 0; + goto out; + } + + err = efivar_entry_get(pnvm_efivar, NULL, &package_size, data); + if (err) { + IWL_DEBUG_FW(trans, + "PNVM UEFI variable not found %d (len %zd)\n", + err, package_size); + kfree(data); + data = ERR_PTR(err); + goto out; + } + + IWL_DEBUG_FW(trans, "Read PNVM from UEFI with size %zd\n", package_size); + *len = package_size; + +out: + kfree(pnvm_efivar); + + return data; +} diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h new file mode 100644 index 000000000000..48f1b54e3e76 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright(c) 2021 Intel Corporation + */ + + +#define IWL_UEFI_OEM_PNVM_NAME L"UefiCnvWlanOemSignedPnvm" + +/* + * TODO: we have these hardcoded values that the caller must pass, + * because reading from the UEFI is not working. To implement this + * properly, we have to change iwl_pnvm_get_from_uefi() to call + * efivar_entry_size() and return the value to the caller instead. + */ +#define IWL_HARDCODED_PNVM_SIZE 4096 + +#ifdef CONFIG_EFI +void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len); +#else /* CONFIG_EFI */ +static inline +void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) +{ + return ERR_PTR(-EOPNOTSUPP); +} +#endif /* CONFIG_EFI */ From 9dad325f9d57508b154f0bebbc341a8528e5729c Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Mon, 21 Jun 2021 10:37:36 +0300 Subject: [PATCH 143/170] iwlwifi: support loading the reduced power table from UEFI This new feature allows OEMs to set a special reduced power table in a UEFI variable, which we use to tell the firmware to change the TX power tables. Read the variable and store it in a dram block to pass it to the firmware. We do this as part of the PNVM loading flow. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210621103449.259a33ba5074.I2e0bb142d2a9c412547cba89b62dd077b328fdc4@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/file.h | 3 +- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 33 ++- drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 200 +++++++++++++++++- drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 21 +- .../intel/iwlwifi/iwl-context-info-gen3.h | 16 +- .../net/wireless/intel/iwlwifi/iwl-trans.h | 17 ++ .../intel/iwlwifi/pcie/ctxt-info-gen3.c | 34 +++ .../wireless/intel/iwlwifi/pcie/internal.h | 1 + .../net/wireless/intel/iwlwifi/pcie/trans.c | 7 + 9 files changed, 318 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index ef1a24504c8b..74e25a6ecc3d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -52,7 +52,8 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_INIT_DATA = 4, IWL_UCODE_TLV_BOOT = 5, IWL_UCODE_TLV_PROBE_MAX_LEN = 6, /* a u32 value */ - IWL_UCODE_TLV_PAN = 7, + IWL_UCODE_TLV_PAN = 7, /* deprecated -- only used in DVM */ + IWL_UCODE_TLV_MEM_DESC = 7, /* replaces PAN in non-DVM */ IWL_UCODE_TLV_RUNT_EVTLOG_PTR = 8, IWL_UCODE_TLV_RUNT_EVTLOG_SIZE = 9, IWL_UCODE_TLV_RUNT_ERRLOG_PTR = 10, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 565c19475155..2403490cbc26 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -17,15 +17,6 @@ struct iwl_pnvm_section { const u8 data[]; } __packed; -struct pnvm_sku_package { - u8 rev; - u8 reserved1[3]; - u32 total_size; - u8 n_skus; - u8 reserved2[11]; - u8 data[]; -}; - static bool iwl_pnvm_complete_fn(struct iwl_notif_wait_data *notif_wait, struct iwl_rx_packet *pkt, void *data) { @@ -322,6 +313,30 @@ parse: kfree(data); skip_parse: + data = NULL; + /* now try to get the reduce power table, if not loaded yet */ + if (!trans->reduce_power_loaded) { + data = iwl_uefi_get_reduced_power(trans, &len); + if (IS_ERR_OR_NULL(data)) { + /* + * Pretend we've loaded it - at least we've tried and + * couldn't load it at all, so there's no point in + * trying again over and over. + */ + trans->reduce_power_loaded = true; + + goto skip_reduce_power; + } + } + + ret = iwl_trans_set_reduce_power(trans, data, len); + if (ret) + IWL_DEBUG_FW(trans, + "Failed to set reduce power table %d\n", + ret); + kfree(data); + +skip_reduce_power: iwl_init_notification_wait(notif_wait, &pnvm_wait, ntf_cmds, ARRAY_SIZE(ntf_cmds), iwl_pnvm_complete_fn, trans); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index bdcdca178eda..a7c79d814aa4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -9,6 +9,7 @@ #include "iwl-io.h" #include "fw/uefi.h" +#include "fw/api/alive.h" #include #define IWL_EFI_VAR_GUID EFI_GUID(0x92daaf2f, 0xc02b, 0x455b, \ @@ -22,6 +23,8 @@ void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) unsigned long package_size; int err; + *len = 0; + pnvm_efivar = kzalloc(sizeof(*pnvm_efivar), GFP_KERNEL); if (!pnvm_efivar) return ERR_PTR(-ENOMEM); @@ -40,7 +43,6 @@ void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) data = kmalloc(package_size, GFP_KERNEL); if (!data) { data = ERR_PTR(-ENOMEM); - *len = 0; goto out; } @@ -62,3 +64,199 @@ out: return data; } + +static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans, + const u8 *data, size_t len) +{ + struct iwl_ucode_tlv *tlv; + u8 *reduce_power_data = NULL, *tmp; + u32 size = 0; + + IWL_DEBUG_FW(trans, "Handling REDUCE_POWER section\n"); + + while (len >= sizeof(*tlv)) { + u32 tlv_len, tlv_type; + + len -= sizeof(*tlv); + tlv = (void *)data; + + tlv_len = le32_to_cpu(tlv->length); + tlv_type = le32_to_cpu(tlv->type); + + if (len < tlv_len) { + IWL_ERR(trans, "invalid TLV len: %zd/%u\n", + len, tlv_len); + reduce_power_data = ERR_PTR(-EINVAL); + goto out; + } + + data += sizeof(*tlv); + + switch (tlv_type) { + case IWL_UCODE_TLV_MEM_DESC: { + IWL_DEBUG_FW(trans, + "Got IWL_UCODE_TLV_MEM_DESC len %d\n", + tlv_len); + + IWL_DEBUG_FW(trans, "Adding data (size %d)\n", tlv_len); + + tmp = krealloc(reduce_power_data, size + tlv_len, GFP_KERNEL); + if (!tmp) { + IWL_DEBUG_FW(trans, + "Couldn't allocate (more) reduce_power_data\n"); + + reduce_power_data = ERR_PTR(-ENOMEM); + goto out; + } + + reduce_power_data = tmp; + + memcpy(reduce_power_data + size, data, tlv_len); + + size += tlv_len; + + break; + } + case IWL_UCODE_TLV_PNVM_SKU: + IWL_DEBUG_FW(trans, + "New REDUCE_POWER section started, stop parsing.\n"); + goto done; + default: + IWL_DEBUG_FW(trans, "Found TLV 0x%0x, len %d\n", + tlv_type, tlv_len); + break; + } + + len -= ALIGN(tlv_len, 4); + data += ALIGN(tlv_len, 4); + } + +done: + if (!size) { + IWL_DEBUG_FW(trans, "Empty REDUCE_POWER, skipping.\n"); + reduce_power_data = ERR_PTR(-ENOENT); + goto out; + } + + IWL_INFO(trans, "loaded REDUCE_POWER\n"); + +out: + return reduce_power_data; +} + +static void *iwl_uefi_reduce_power_parse(struct iwl_trans *trans, + const u8 *data, size_t len) +{ + struct iwl_ucode_tlv *tlv; + void *sec_data; + + IWL_DEBUG_FW(trans, "Parsing REDUCE_POWER data\n"); + + while (len >= sizeof(*tlv)) { + u32 tlv_len, tlv_type; + + len -= sizeof(*tlv); + tlv = (void *)data; + + tlv_len = le32_to_cpu(tlv->length); + tlv_type = le32_to_cpu(tlv->type); + + if (len < tlv_len) { + IWL_ERR(trans, "invalid TLV len: %zd/%u\n", + len, tlv_len); + return ERR_PTR(-EINVAL); + } + + if (tlv_type == IWL_UCODE_TLV_PNVM_SKU) { + struct iwl_sku_id *sku_id = + (void *)(data + sizeof(*tlv)); + + IWL_DEBUG_FW(trans, + "Got IWL_UCODE_TLV_PNVM_SKU len %d\n", + tlv_len); + IWL_DEBUG_FW(trans, "sku_id 0x%0x 0x%0x 0x%0x\n", + le32_to_cpu(sku_id->data[0]), + le32_to_cpu(sku_id->data[1]), + le32_to_cpu(sku_id->data[2])); + + data += sizeof(*tlv) + ALIGN(tlv_len, 4); + len -= ALIGN(tlv_len, 4); + + if (trans->sku_id[0] == le32_to_cpu(sku_id->data[0]) && + trans->sku_id[1] == le32_to_cpu(sku_id->data[1]) && + trans->sku_id[2] == le32_to_cpu(sku_id->data[2])) { + sec_data = iwl_uefi_reduce_power_section(trans, + data, + len); + if (!IS_ERR(sec_data)) + return sec_data; + } else { + IWL_DEBUG_FW(trans, "SKU ID didn't match!\n"); + } + } else { + data += sizeof(*tlv) + ALIGN(tlv_len, 4); + len -= ALIGN(tlv_len, 4); + } + } + + return ERR_PTR(-ENOENT); +} + +void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) +{ + struct efivar_entry *reduce_power_efivar; + struct pnvm_sku_package *package; + void *data = NULL; + unsigned long package_size; + int err; + + *len = 0; + + reduce_power_efivar = kzalloc(sizeof(*reduce_power_efivar), GFP_KERNEL); + if (!reduce_power_efivar) + return ERR_PTR(-ENOMEM); + + memcpy(&reduce_power_efivar->var.VariableName, IWL_UEFI_REDUCED_POWER_NAME, + sizeof(IWL_UEFI_REDUCED_POWER_NAME)); + reduce_power_efivar->var.VendorGuid = IWL_EFI_VAR_GUID; + + /* + * TODO: we hardcode a maximum length here, because reading + * from the UEFI is not working. To implement this properly, + * we have to call efivar_entry_size(). + */ + package_size = IWL_HARDCODED_REDUCE_POWER_SIZE; + + package = kmalloc(package_size, GFP_KERNEL); + if (!package) { + package = ERR_PTR(-ENOMEM); + goto out; + } + + err = efivar_entry_get(reduce_power_efivar, NULL, &package_size, package); + if (err) { + IWL_DEBUG_FW(trans, + "Reduced Power UEFI variable not found %d (len %lu)\n", + err, package_size); + kfree(package); + data = ERR_PTR(err); + goto out; + } + + IWL_DEBUG_FW(trans, "Read reduced power from UEFI with size %lu\n", + package_size); + *len = package_size; + + IWL_DEBUG_FW(trans, "rev %d, total_size %d, n_skus %d\n", + package->rev, package->total_size, package->n_skus); + + data = iwl_uefi_reduce_power_parse(trans, package->data, + *len - sizeof(*package)); + + kfree(package); + +out: + kfree(reduce_power_efivar); + + return data; +} diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index 48f1b54e3e76..45d0b36d79b5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -4,7 +4,8 @@ */ -#define IWL_UEFI_OEM_PNVM_NAME L"UefiCnvWlanOemSignedPnvm" +#define IWL_UEFI_OEM_PNVM_NAME L"UefiCnvWlanOemSignedPnvm" +#define IWL_UEFI_REDUCED_POWER_NAME L"UefiCnvWlanReducedPower" /* * TODO: we have these hardcoded values that the caller must pass, @@ -12,14 +13,30 @@ * properly, we have to change iwl_pnvm_get_from_uefi() to call * efivar_entry_size() and return the value to the caller instead. */ -#define IWL_HARDCODED_PNVM_SIZE 4096 +#define IWL_HARDCODED_PNVM_SIZE 4096 +#define IWL_HARDCODED_REDUCE_POWER_SIZE 32768 + +struct pnvm_sku_package { + u8 rev; + u32 total_size; + u8 n_skus; + u32 reserved[2]; + u8 data[]; +} __packed; #ifdef CONFIG_EFI void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len); +void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len); #else /* CONFIG_EFI */ static inline void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) { return ERR_PTR(-EOPNOTSUPP); } + +static inline +void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) +{ + return ERR_PTR(-EOPNOTSUPP); +} #endif /* CONFIG_EFI */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h index 518a1bc79584..e1fec23ac07f 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h @@ -127,6 +127,17 @@ struct iwl_prph_scratch_rbd_cfg { __le32 reserved; } __packed; /* PERIPH_SCRATCH_RBD_CFG_S */ +/* + * struct iwl_prph_scratch_uefi_cfg - prph scratch reduce power table + * @base_addr: reduce power table address + * @size: table size in dwords + */ +struct iwl_prph_scratch_uefi_cfg { + __le64 base_addr; + __le32 size; + __le32 reserved; +} __packed; /* PERIPH_SCRATCH_UEFI_CFG_S */ + /* * struct iwl_prph_scratch_ctrl_cfg - prph scratch ctrl and config * @version: version information of context info and HW @@ -141,6 +152,7 @@ struct iwl_prph_scratch_ctrl_cfg { struct iwl_prph_scratch_pnvm_cfg pnvm_cfg; struct iwl_prph_scratch_hwm_cfg hwm_cfg; struct iwl_prph_scratch_rbd_cfg rbd_cfg; + struct iwl_prph_scratch_uefi_cfg reduce_power_cfg; } __packed; /* PERIPH_SCRATCH_CTRL_CFG_S */ /* @@ -151,7 +163,7 @@ struct iwl_prph_scratch_ctrl_cfg { */ struct iwl_prph_scratch { struct iwl_prph_scratch_ctrl_cfg ctrl_cfg; - __le32 reserved[16]; + __le32 reserved[12]; struct iwl_context_info_dram dram; } __packed; /* PERIPH_SCRATCH_S */ @@ -249,5 +261,7 @@ void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive); int iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans, const void *data, u32 len); +int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans, + const void *data, u32 len); #endif /* __iwl_context_info_file_gen3_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index bf569f856ad8..8d745e0c0394 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -589,6 +589,8 @@ struct iwl_trans_ops { void (*debugfs_cleanup)(struct iwl_trans *trans); void (*sync_nmi)(struct iwl_trans *trans); int (*set_pnvm)(struct iwl_trans *trans, const void *data, u32 len); + int (*set_reduce_power)(struct iwl_trans *trans, + const void *data, u32 len); void (*interrupts)(struct iwl_trans *trans, bool enable); }; @@ -957,6 +959,7 @@ struct iwl_trans { bool pm_support; bool ltr_enabled; u8 pnvm_loaded:1; + u8 reduce_power_loaded:1; const struct iwl_hcmd_arr *command_groups; int command_groups_size; @@ -1420,6 +1423,20 @@ static inline int iwl_trans_set_pnvm(struct iwl_trans *trans, return 0; } +static inline int iwl_trans_set_reduce_power(struct iwl_trans *trans, + const void *data, u32 len) +{ + if (trans->ops->set_reduce_power) { + int ret = trans->ops->set_reduce_power(trans, data, len); + + if (ret) + return ret; + } + + trans->reduce_power_loaded = true; + return 0; +} + static inline bool iwl_trans_dbg_ini_valid(struct iwl_trans *trans) { return trans->dbg.internal_ini_cfg != IWL_INI_CFG_STATE_NOT_LOADED || diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index c69a1541e678..239a722cd79d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -302,3 +302,37 @@ int iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans, return 0; } + +int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans, + const void *data, u32 len) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl = + &trans_pcie->prph_scratch->ctrl_cfg; + int ret; + + if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) + return 0; + + /* only allocate the DRAM if not allocated yet */ + if (!trans->reduce_power_loaded) { + if (WARN_ON(prph_sc_ctrl->reduce_power_cfg.size)) + return -EBUSY; + + ret = iwl_pcie_ctxt_info_alloc_dma(trans, data, len, + &trans_pcie->reduce_power_dram); + if (ret < 0) { + IWL_DEBUG_FW(trans, + "Failed to allocate reduce power DMA %d.\n", + ret); + return ret; + } + } + + prph_sc_ctrl->reduce_power_cfg.base_addr = + cpu_to_le64(trans_pcie->reduce_power_dram.physical); + prph_sc_ctrl->reduce_power_cfg.size = + cpu_to_le32(trans_pcie->reduce_power_dram.size); + + return 0; +} diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 69289e9f8d7e..cc550f6ef957 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -349,6 +349,7 @@ struct iwl_trans_pcie { struct iwl_dma_ptr kw; struct iwl_dram_data pnvm_dram; + struct iwl_dram_data reduce_power_dram; struct iwl_txq *txq_memory; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 1331a6bfd767..bee6b4574226 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1943,6 +1943,12 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) trans_pcie->pnvm_dram.block, trans_pcie->pnvm_dram.physical); + if (trans_pcie->reduce_power_dram.size) + dma_free_coherent(trans->dev, + trans_pcie->reduce_power_dram.size, + trans_pcie->reduce_power_dram.block, + trans_pcie->reduce_power_dram.physical); + mutex_destroy(&trans_pcie->mutex); iwl_trans_free(trans); } @@ -3418,6 +3424,7 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = { .wait_txq_empty = iwl_trans_pcie_wait_txq_empty, .rxq_dma_data = iwl_trans_pcie_rxq_dma_data, .set_pnvm = iwl_trans_pcie_ctx_info_gen3_set_pnvm, + .set_reduce_power = iwl_trans_pcie_ctx_info_gen3_set_reduce_power, #ifdef CONFIG_IWLWIFI_DEBUGFS .debugfs_cleanup = iwl_trans_pcie_debugfs_cleanup, #endif From 4db7cf1e0108ce4376e111ac23693be12128e2f3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 21 Jun 2021 10:37:37 +0300 Subject: [PATCH 144/170] iwlwifi: move error dump to fw utils Conceptually, this belongs more into the firmware utils rather than the mvm opmode, so move the collection and output there. Note that this slightly changes the format of the Status line. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210621103449.b82b60d81346.Ide3b688107f6a59c7fc7eb1d8f2002b0a5c1f2d2@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/Makefile | 2 +- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 38 -- drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 4 +- drivers/net/wireless/intel/iwlwifi/fw/dump.c | 358 ++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 7 +- .../net/wireless/intel/iwlwifi/mvm/utils.c | 310 --------------- 6 files changed, 368 insertions(+), 351 deletions(-) create mode 100644 drivers/net/wireless/intel/iwlwifi/fw/dump.c diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index a8428c27286c..d86918d162aa 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -16,7 +16,7 @@ iwlwifi-objs += iwl-trans.o iwlwifi-objs += queue/tx.o iwlwifi-objs += fw/img.o fw/notif-wait.o -iwlwifi-objs += fw/dbg.o fw/pnvm.o +iwlwifi-objs += fw/dbg.o fw/pnvm.o fw/dump.o iwlwifi-$(CONFIG_IWLMVM) += fw/paging.o fw/smem.o fw/init.o iwlwifi-$(CONFIG_ACPI) += fw/acpi.o iwlwifi-$(CONFIG_EFI) += fw/uefi.o diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 5a534d70f253..df7c55e06f54 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -2759,44 +2759,6 @@ void iwl_fw_dbg_stop_sync(struct iwl_fw_runtime *fwrt) } IWL_EXPORT_SYMBOL(iwl_fw_dbg_stop_sync); -#define FSEQ_REG(x) { .addr = (x), .str = #x, } - -void iwl_fw_error_print_fseq_regs(struct iwl_fw_runtime *fwrt) -{ - struct iwl_trans *trans = fwrt->trans; - int i; - struct { - u32 addr; - const char *str; - } fseq_regs[] = { - FSEQ_REG(FSEQ_ERROR_CODE), - FSEQ_REG(FSEQ_TOP_INIT_VERSION), - FSEQ_REG(FSEQ_CNVIO_INIT_VERSION), - FSEQ_REG(FSEQ_OTP_VERSION), - FSEQ_REG(FSEQ_TOP_CONTENT_VERSION), - FSEQ_REG(FSEQ_ALIVE_TOKEN), - FSEQ_REG(FSEQ_CNVI_ID), - FSEQ_REG(FSEQ_CNVR_ID), - FSEQ_REG(CNVI_AUX_MISC_CHIP), - FSEQ_REG(CNVR_AUX_MISC_CHIP), - FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM), - FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR), - }; - - if (!iwl_trans_grab_nic_access(trans)) - return; - - IWL_ERR(fwrt, "Fseq Registers:\n"); - - for (i = 0; i < ARRAY_SIZE(fseq_regs); i++) - IWL_ERR(fwrt, "0x%08X | %s\n", - iwl_read_prph_no_grab(trans, fseq_regs[i].addr), - fseq_regs[i].str); - - iwl_trans_release_nic_access(trans); -} -IWL_EXPORT_SYMBOL(iwl_fw_error_print_fseq_regs); - static int iwl_fw_dbg_suspend_resume_hcmd(struct iwl_trans *trans, bool suspend) { struct iwl_dbg_suspend_resume_cmd cmd = { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 49fa2f5f8c7e..c0e84ef84f5d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2019 Intel Corporation + * Copyright (C) 2005-2014, 2018-2019, 2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -321,4 +321,6 @@ static inline void iwl_fwrt_update_fw_versions(struct iwl_fw_runtime *fwrt, fwrt->dump.fw_ver.umac_minor = le32_to_cpu(umac->umac_minor); } } + +void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt); #endif /* __iwl_fw_dbg_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c new file mode 100644 index 000000000000..66f86d2a7cca --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c @@ -0,0 +1,358 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation + * Copyright (C) 2013-2014 Intel Mobile Communications GmbH + * Copyright (C) 2015-2017 Intel Deutschland GmbH + */ +#include +#include "iwl-drv.h" +#include "runtime.h" +#include "dbg.h" +#include "debugfs.h" +#include "iwl-io.h" +#include "iwl-prph.h" +#include "iwl-csr.h" + +/* + * Note: This structure is read from the device with IO accesses, + * and the reading already does the endian conversion. As it is + * read with u32-sized accesses, any members with a different size + * need to be ordered correctly though! + */ +struct iwl_error_event_table_v1 { + u32 valid; /* (nonzero) valid, (0) log is empty */ + u32 error_id; /* type of error */ + u32 pc; /* program counter */ + u32 blink1; /* branch link */ + u32 blink2; /* branch link */ + u32 ilink1; /* interrupt link */ + u32 ilink2; /* interrupt link */ + u32 data1; /* error-specific data */ + u32 data2; /* error-specific data */ + u32 data3; /* error-specific data */ + u32 bcon_time; /* beacon timer */ + u32 tsf_low; /* network timestamp function timer */ + u32 tsf_hi; /* network timestamp function timer */ + u32 gp1; /* GP1 timer register */ + u32 gp2; /* GP2 timer register */ + u32 gp3; /* GP3 timer register */ + u32 ucode_ver; /* uCode version */ + u32 hw_ver; /* HW Silicon version */ + u32 brd_ver; /* HW board version */ + u32 log_pc; /* log program counter */ + u32 frame_ptr; /* frame pointer */ + u32 stack_ptr; /* stack pointer */ + u32 hcmd; /* last host command header */ + u32 isr0; /* isr status register LMPM_NIC_ISR0: + * rxtx_flag */ + u32 isr1; /* isr status register LMPM_NIC_ISR1: + * host_flag */ + u32 isr2; /* isr status register LMPM_NIC_ISR2: + * enc_flag */ + u32 isr3; /* isr status register LMPM_NIC_ISR3: + * time_flag */ + u32 isr4; /* isr status register LMPM_NIC_ISR4: + * wico interrupt */ + u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */ + u32 wait_event; /* wait event() caller address */ + u32 l2p_control; /* L2pControlField */ + u32 l2p_duration; /* L2pDurationField */ + u32 l2p_mhvalid; /* L2pMhValidBits */ + u32 l2p_addr_match; /* L2pAddrMatchStat */ + u32 lmpm_pmg_sel; /* indicate which clocks are turned on + * (LMPM_PMG_SEL) */ + u32 u_timestamp; /* indicate when the date and time of the + * compilation */ + u32 flow_handler; /* FH read/write pointers, RX credit */ +} __packed /* LOG_ERROR_TABLE_API_S_VER_1 */; + +struct iwl_error_event_table { + u32 valid; /* (nonzero) valid, (0) log is empty */ + u32 error_id; /* type of error */ + u32 trm_hw_status0; /* TRM HW status */ + u32 trm_hw_status1; /* TRM HW status */ + u32 blink2; /* branch link */ + u32 ilink1; /* interrupt link */ + u32 ilink2; /* interrupt link */ + u32 data1; /* error-specific data */ + u32 data2; /* error-specific data */ + u32 data3; /* error-specific data */ + u32 bcon_time; /* beacon timer */ + u32 tsf_low; /* network timestamp function timer */ + u32 tsf_hi; /* network timestamp function timer */ + u32 gp1; /* GP1 timer register */ + u32 gp2; /* GP2 timer register */ + u32 fw_rev_type; /* firmware revision type */ + u32 major; /* uCode version major */ + u32 minor; /* uCode version minor */ + u32 hw_ver; /* HW Silicon version */ + u32 brd_ver; /* HW board version */ + u32 log_pc; /* log program counter */ + u32 frame_ptr; /* frame pointer */ + u32 stack_ptr; /* stack pointer */ + u32 hcmd; /* last host command header */ + u32 isr0; /* isr status register LMPM_NIC_ISR0: + * rxtx_flag */ + u32 isr1; /* isr status register LMPM_NIC_ISR1: + * host_flag */ + u32 isr2; /* isr status register LMPM_NIC_ISR2: + * enc_flag */ + u32 isr3; /* isr status register LMPM_NIC_ISR3: + * time_flag */ + u32 isr4; /* isr status register LMPM_NIC_ISR4: + * wico interrupt */ + u32 last_cmd_id; /* last HCMD id handled by the firmware */ + u32 wait_event; /* wait event() caller address */ + u32 l2p_control; /* L2pControlField */ + u32 l2p_duration; /* L2pDurationField */ + u32 l2p_mhvalid; /* L2pMhValidBits */ + u32 l2p_addr_match; /* L2pAddrMatchStat */ + u32 lmpm_pmg_sel; /* indicate which clocks are turned on + * (LMPM_PMG_SEL) */ + u32 u_timestamp; /* indicate when the date and time of the + * compilation */ + u32 flow_handler; /* FH read/write pointers, RX credit */ +} __packed /* LOG_ERROR_TABLE_API_S_VER_3 */; + +/* + * UMAC error struct - relevant starting from family 8000 chip. + * Note: This structure is read from the device with IO accesses, + * and the reading already does the endian conversion. As it is + * read with u32-sized accesses, any members with a different size + * need to be ordered correctly though! + */ +struct iwl_umac_error_event_table { + u32 valid; /* (nonzero) valid, (0) log is empty */ + u32 error_id; /* type of error */ + u32 blink1; /* branch link */ + u32 blink2; /* branch link */ + u32 ilink1; /* interrupt link */ + u32 ilink2; /* interrupt link */ + u32 data1; /* error-specific data */ + u32 data2; /* error-specific data */ + u32 data3; /* error-specific data */ + u32 umac_major; + u32 umac_minor; + u32 frame_pointer; /* core register 27*/ + u32 stack_pointer; /* core register 28 */ + u32 cmd_header; /* latest host cmd sent to UMAC */ + u32 nic_isr_pref; /* ISR status register */ +} __packed; + +#define ERROR_START_OFFSET (1 * sizeof(u32)) +#define ERROR_ELEM_SIZE (7 * sizeof(u32)) + +static void iwl_fwrt_dump_umac_error_log(struct iwl_fw_runtime *fwrt) +{ + struct iwl_trans *trans = fwrt->trans; + struct iwl_umac_error_event_table table = {}; + u32 base = fwrt->trans->dbg.umac_error_event_table; + + if (!base && + !(fwrt->trans->dbg.error_event_table_tlv_status & + IWL_ERROR_EVENT_TABLE_UMAC)) + return; + + iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); + + if (table.valid) + fwrt->dump.umac_err_id = table.error_id; + + if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { + IWL_ERR(trans, "Start IWL Error Log Dump:\n"); + IWL_ERR(trans, "Transport status: 0x%08lX, valid: %d\n", + fwrt->trans->status, table.valid); + } + + IWL_ERR(fwrt, "0x%08X | %s\n", table.error_id, + iwl_fw_lookup_assert_desc(table.error_id)); + IWL_ERR(fwrt, "0x%08X | umac branchlink1\n", table.blink1); + IWL_ERR(fwrt, "0x%08X | umac branchlink2\n", table.blink2); + IWL_ERR(fwrt, "0x%08X | umac interruptlink1\n", table.ilink1); + IWL_ERR(fwrt, "0x%08X | umac interruptlink2\n", table.ilink2); + IWL_ERR(fwrt, "0x%08X | umac data1\n", table.data1); + IWL_ERR(fwrt, "0x%08X | umac data2\n", table.data2); + IWL_ERR(fwrt, "0x%08X | umac data3\n", table.data3); + IWL_ERR(fwrt, "0x%08X | umac major\n", table.umac_major); + IWL_ERR(fwrt, "0x%08X | umac minor\n", table.umac_minor); + IWL_ERR(fwrt, "0x%08X | frame pointer\n", table.frame_pointer); + IWL_ERR(fwrt, "0x%08X | stack pointer\n", table.stack_pointer); + IWL_ERR(fwrt, "0x%08X | last host cmd\n", table.cmd_header); + IWL_ERR(fwrt, "0x%08X | isr status reg\n", table.nic_isr_pref); +} + +static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_num) +{ + struct iwl_trans *trans = fwrt->trans; + struct iwl_error_event_table table = {}; + u32 val, base = fwrt->trans->dbg.lmac_error_event_table[lmac_num]; + + if (fwrt->cur_fw_img == IWL_UCODE_INIT) { + if (!base) + base = fwrt->fw->init_errlog_ptr; + } else { + if (!base) + base = fwrt->fw->inst_errlog_ptr; + } + + if (base < 0x400000) { + IWL_ERR(fwrt, + "Not valid error log pointer 0x%08X for %s uCode\n", + base, + (fwrt->cur_fw_img == IWL_UCODE_INIT) + ? "Init" : "RT"); + return; + } + + /* check if there is a HW error */ + val = iwl_trans_read_mem32(trans, base); + if (((val & ~0xf) == 0xa5a5a5a0) || ((val & ~0xf) == 0x5a5a5a50)) { + int err; + + IWL_ERR(trans, "HW error, resetting before reading\n"); + + /* reset the device */ + iwl_trans_sw_reset(trans); + + err = iwl_finish_nic_init(trans, trans->trans_cfg); + if (err) + return; + } + + iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); + + if (table.valid) + fwrt->dump.lmac_err_id[lmac_num] = table.error_id; + + if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { + IWL_ERR(trans, "Start IWL Error Log Dump:\n"); + IWL_ERR(trans, "Transport status: 0x%08lX, valid: %d\n", + fwrt->trans->status, table.valid); + } + + /* Do not change this output - scripts rely on it */ + + IWL_ERR(fwrt, "Loaded firmware version: %s\n", fwrt->fw->fw_version); + + IWL_ERR(fwrt, "0x%08X | %-28s\n", table.error_id, + iwl_fw_lookup_assert_desc(table.error_id)); + IWL_ERR(fwrt, "0x%08X | trm_hw_status0\n", table.trm_hw_status0); + IWL_ERR(fwrt, "0x%08X | trm_hw_status1\n", table.trm_hw_status1); + IWL_ERR(fwrt, "0x%08X | branchlink2\n", table.blink2); + IWL_ERR(fwrt, "0x%08X | interruptlink1\n", table.ilink1); + IWL_ERR(fwrt, "0x%08X | interruptlink2\n", table.ilink2); + IWL_ERR(fwrt, "0x%08X | data1\n", table.data1); + IWL_ERR(fwrt, "0x%08X | data2\n", table.data2); + IWL_ERR(fwrt, "0x%08X | data3\n", table.data3); + IWL_ERR(fwrt, "0x%08X | beacon time\n", table.bcon_time); + IWL_ERR(fwrt, "0x%08X | tsf low\n", table.tsf_low); + IWL_ERR(fwrt, "0x%08X | tsf hi\n", table.tsf_hi); + IWL_ERR(fwrt, "0x%08X | time gp1\n", table.gp1); + IWL_ERR(fwrt, "0x%08X | time gp2\n", table.gp2); + IWL_ERR(fwrt, "0x%08X | uCode revision type\n", table.fw_rev_type); + IWL_ERR(fwrt, "0x%08X | uCode version major\n", table.major); + IWL_ERR(fwrt, "0x%08X | uCode version minor\n", table.minor); + IWL_ERR(fwrt, "0x%08X | hw version\n", table.hw_ver); + IWL_ERR(fwrt, "0x%08X | board version\n", table.brd_ver); + IWL_ERR(fwrt, "0x%08X | hcmd\n", table.hcmd); + IWL_ERR(fwrt, "0x%08X | isr0\n", table.isr0); + IWL_ERR(fwrt, "0x%08X | isr1\n", table.isr1); + IWL_ERR(fwrt, "0x%08X | isr2\n", table.isr2); + IWL_ERR(fwrt, "0x%08X | isr3\n", table.isr3); + IWL_ERR(fwrt, "0x%08X | isr4\n", table.isr4); + IWL_ERR(fwrt, "0x%08X | last cmd Id\n", table.last_cmd_id); + IWL_ERR(fwrt, "0x%08X | wait_event\n", table.wait_event); + IWL_ERR(fwrt, "0x%08X | l2p_control\n", table.l2p_control); + IWL_ERR(fwrt, "0x%08X | l2p_duration\n", table.l2p_duration); + IWL_ERR(fwrt, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid); + IWL_ERR(fwrt, "0x%08X | l2p_addr_match\n", table.l2p_addr_match); + IWL_ERR(fwrt, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel); + IWL_ERR(fwrt, "0x%08X | timestamp\n", table.u_timestamp); + IWL_ERR(fwrt, "0x%08X | flow_handler\n", table.flow_handler); +} + +static void iwl_fwrt_dump_iml_error_log(struct iwl_fw_runtime *fwrt) +{ + struct iwl_trans *trans = fwrt->trans; + u32 error, data1; + + if (fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) { + error = UMAG_SB_CPU_2_STATUS; + data1 = UMAG_SB_CPU_1_STATUS; + } else if (fwrt->trans->trans_cfg->device_family >= + IWL_DEVICE_FAMILY_8000) { + error = SB_CPU_2_STATUS; + data1 = SB_CPU_1_STATUS; + } else { + return; + } + + error = iwl_read_umac_prph(trans, UMAG_SB_CPU_2_STATUS); + + IWL_ERR(trans, "IML/ROM dump:\n"); + + if (error & 0xFFFF0000) + IWL_ERR(trans, "0x%04X | IML/ROM SYSASSERT\n", error >> 16); + + IWL_ERR(fwrt, "0x%08X | IML/ROM error/state\n", error); + IWL_ERR(fwrt, "0x%08X | IML/ROM data1\n", + iwl_read_umac_prph(trans, data1)); + + if (fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) + IWL_ERR(fwrt, "0x%08X | IML/ROM WFPM_AUTH_KEY_0\n", + iwl_read_umac_prph(trans, SB_MODIFY_CFG_FLAG)); +} + +#define FSEQ_REG(x) { .addr = (x), .str = #x, } + +static void iwl_fwrt_dump_fseq_regs(struct iwl_fw_runtime *fwrt) +{ + struct iwl_trans *trans = fwrt->trans; + int i; + struct { + u32 addr; + const char *str; + } fseq_regs[] = { + FSEQ_REG(FSEQ_ERROR_CODE), + FSEQ_REG(FSEQ_TOP_INIT_VERSION), + FSEQ_REG(FSEQ_CNVIO_INIT_VERSION), + FSEQ_REG(FSEQ_OTP_VERSION), + FSEQ_REG(FSEQ_TOP_CONTENT_VERSION), + FSEQ_REG(FSEQ_ALIVE_TOKEN), + FSEQ_REG(FSEQ_CNVI_ID), + FSEQ_REG(FSEQ_CNVR_ID), + FSEQ_REG(CNVI_AUX_MISC_CHIP), + FSEQ_REG(CNVR_AUX_MISC_CHIP), + FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM), + FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR), + }; + + if (!iwl_trans_grab_nic_access(trans)) + return; + + IWL_ERR(fwrt, "Fseq Registers:\n"); + + for (i = 0; i < ARRAY_SIZE(fseq_regs); i++) + IWL_ERR(fwrt, "0x%08X | %s\n", + iwl_read_prph_no_grab(trans, fseq_regs[i].addr), + fseq_regs[i].str); + + iwl_trans_release_nic_access(trans); +} + +void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt) +{ + if (!test_bit(STATUS_DEVICE_ENABLED, &fwrt->trans->status)) { + IWL_ERR(fwrt, + "DEVICE_ENABLED bit is not set. Aborting dump.\n"); + return; + } + + iwl_fwrt_dump_lmac_error_log(fwrt, 0); + if (fwrt->trans->dbg.lmac_error_event_table[1]) + iwl_fwrt_dump_lmac_error_log(fwrt, 1); + iwl_fwrt_dump_umac_error_log(fwrt); + iwl_fwrt_dump_iml_error_log(fwrt); + iwl_fwrt_dump_fseq_regs(fwrt); +} +IWL_EXPORT_SYMBOL(iwl_fwrt_dump_error_logs); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index bf99eed23a9f..b50942f28bb7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1452,7 +1452,12 @@ void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags, struct ieee80211_tx_rate *r); u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx); u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac); -void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); + +static inline void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) +{ + iwl_fwrt_dump_error_logs(&mvm->fwrt); +} + u8 first_antenna(u8 mask); u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, int clock_type, u32 *gp2, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 0e8ad798ab57..4a3d2971a98b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -238,316 +238,6 @@ u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx) return last_idx; } -/* - * Note: This structure is read from the device with IO accesses, - * and the reading already does the endian conversion. As it is - * read with u32-sized accesses, any members with a different size - * need to be ordered correctly though! - */ -struct iwl_error_event_table_v1 { - u32 valid; /* (nonzero) valid, (0) log is empty */ - u32 error_id; /* type of error */ - u32 pc; /* program counter */ - u32 blink1; /* branch link */ - u32 blink2; /* branch link */ - u32 ilink1; /* interrupt link */ - u32 ilink2; /* interrupt link */ - u32 data1; /* error-specific data */ - u32 data2; /* error-specific data */ - u32 data3; /* error-specific data */ - u32 bcon_time; /* beacon timer */ - u32 tsf_low; /* network timestamp function timer */ - u32 tsf_hi; /* network timestamp function timer */ - u32 gp1; /* GP1 timer register */ - u32 gp2; /* GP2 timer register */ - u32 gp3; /* GP3 timer register */ - u32 ucode_ver; /* uCode version */ - u32 hw_ver; /* HW Silicon version */ - u32 brd_ver; /* HW board version */ - u32 log_pc; /* log program counter */ - u32 frame_ptr; /* frame pointer */ - u32 stack_ptr; /* stack pointer */ - u32 hcmd; /* last host command header */ - u32 isr0; /* isr status register LMPM_NIC_ISR0: - * rxtx_flag */ - u32 isr1; /* isr status register LMPM_NIC_ISR1: - * host_flag */ - u32 isr2; /* isr status register LMPM_NIC_ISR2: - * enc_flag */ - u32 isr3; /* isr status register LMPM_NIC_ISR3: - * time_flag */ - u32 isr4; /* isr status register LMPM_NIC_ISR4: - * wico interrupt */ - u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */ - u32 wait_event; /* wait event() caller address */ - u32 l2p_control; /* L2pControlField */ - u32 l2p_duration; /* L2pDurationField */ - u32 l2p_mhvalid; /* L2pMhValidBits */ - u32 l2p_addr_match; /* L2pAddrMatchStat */ - u32 lmpm_pmg_sel; /* indicate which clocks are turned on - * (LMPM_PMG_SEL) */ - u32 u_timestamp; /* indicate when the date and time of the - * compilation */ - u32 flow_handler; /* FH read/write pointers, RX credit */ -} __packed /* LOG_ERROR_TABLE_API_S_VER_1 */; - -struct iwl_error_event_table { - u32 valid; /* (nonzero) valid, (0) log is empty */ - u32 error_id; /* type of error */ - u32 trm_hw_status0; /* TRM HW status */ - u32 trm_hw_status1; /* TRM HW status */ - u32 blink2; /* branch link */ - u32 ilink1; /* interrupt link */ - u32 ilink2; /* interrupt link */ - u32 data1; /* error-specific data */ - u32 data2; /* error-specific data */ - u32 data3; /* error-specific data */ - u32 bcon_time; /* beacon timer */ - u32 tsf_low; /* network timestamp function timer */ - u32 tsf_hi; /* network timestamp function timer */ - u32 gp1; /* GP1 timer register */ - u32 gp2; /* GP2 timer register */ - u32 fw_rev_type; /* firmware revision type */ - u32 major; /* uCode version major */ - u32 minor; /* uCode version minor */ - u32 hw_ver; /* HW Silicon version */ - u32 brd_ver; /* HW board version */ - u32 log_pc; /* log program counter */ - u32 frame_ptr; /* frame pointer */ - u32 stack_ptr; /* stack pointer */ - u32 hcmd; /* last host command header */ - u32 isr0; /* isr status register LMPM_NIC_ISR0: - * rxtx_flag */ - u32 isr1; /* isr status register LMPM_NIC_ISR1: - * host_flag */ - u32 isr2; /* isr status register LMPM_NIC_ISR2: - * enc_flag */ - u32 isr3; /* isr status register LMPM_NIC_ISR3: - * time_flag */ - u32 isr4; /* isr status register LMPM_NIC_ISR4: - * wico interrupt */ - u32 last_cmd_id; /* last HCMD id handled by the firmware */ - u32 wait_event; /* wait event() caller address */ - u32 l2p_control; /* L2pControlField */ - u32 l2p_duration; /* L2pDurationField */ - u32 l2p_mhvalid; /* L2pMhValidBits */ - u32 l2p_addr_match; /* L2pAddrMatchStat */ - u32 lmpm_pmg_sel; /* indicate which clocks are turned on - * (LMPM_PMG_SEL) */ - u32 u_timestamp; /* indicate when the date and time of the - * compilation */ - u32 flow_handler; /* FH read/write pointers, RX credit */ -} __packed /* LOG_ERROR_TABLE_API_S_VER_3 */; - -/* - * UMAC error struct - relevant starting from family 8000 chip. - * Note: This structure is read from the device with IO accesses, - * and the reading already does the endian conversion. As it is - * read with u32-sized accesses, any members with a different size - * need to be ordered correctly though! - */ -struct iwl_umac_error_event_table { - u32 valid; /* (nonzero) valid, (0) log is empty */ - u32 error_id; /* type of error */ - u32 blink1; /* branch link */ - u32 blink2; /* branch link */ - u32 ilink1; /* interrupt link */ - u32 ilink2; /* interrupt link */ - u32 data1; /* error-specific data */ - u32 data2; /* error-specific data */ - u32 data3; /* error-specific data */ - u32 umac_major; - u32 umac_minor; - u32 frame_pointer; /* core register 27*/ - u32 stack_pointer; /* core register 28 */ - u32 cmd_header; /* latest host cmd sent to UMAC */ - u32 nic_isr_pref; /* ISR status register */ -} __packed; - -#define ERROR_START_OFFSET (1 * sizeof(u32)) -#define ERROR_ELEM_SIZE (7 * sizeof(u32)) - -static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm) -{ - struct iwl_trans *trans = mvm->trans; - struct iwl_umac_error_event_table table = {}; - u32 base = mvm->trans->dbg.umac_error_event_table; - - if (!base && - !(mvm->trans->dbg.error_event_table_tlv_status & - IWL_ERROR_EVENT_TABLE_UMAC)) - return; - - iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); - - if (table.valid) - mvm->fwrt.dump.umac_err_id = table.error_id; - - if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { - IWL_ERR(trans, "Start IWL Error Log Dump:\n"); - IWL_ERR(trans, "Status: 0x%08lX, count: %d\n", - mvm->status, table.valid); - } - - IWL_ERR(mvm, "0x%08X | %s\n", table.error_id, - iwl_fw_lookup_assert_desc(table.error_id)); - IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1); - IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2); - IWL_ERR(mvm, "0x%08X | umac interruptlink1\n", table.ilink1); - IWL_ERR(mvm, "0x%08X | umac interruptlink2\n", table.ilink2); - IWL_ERR(mvm, "0x%08X | umac data1\n", table.data1); - IWL_ERR(mvm, "0x%08X | umac data2\n", table.data2); - IWL_ERR(mvm, "0x%08X | umac data3\n", table.data3); - IWL_ERR(mvm, "0x%08X | umac major\n", table.umac_major); - IWL_ERR(mvm, "0x%08X | umac minor\n", table.umac_minor); - IWL_ERR(mvm, "0x%08X | frame pointer\n", table.frame_pointer); - IWL_ERR(mvm, "0x%08X | stack pointer\n", table.stack_pointer); - IWL_ERR(mvm, "0x%08X | last host cmd\n", table.cmd_header); - IWL_ERR(mvm, "0x%08X | isr status reg\n", table.nic_isr_pref); -} - -static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u8 lmac_num) -{ - struct iwl_trans *trans = mvm->trans; - struct iwl_error_event_table table = {}; - u32 val, base = mvm->trans->dbg.lmac_error_event_table[lmac_num]; - - if (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) { - if (!base) - base = mvm->fw->init_errlog_ptr; - } else { - if (!base) - base = mvm->fw->inst_errlog_ptr; - } - - if (base < 0x400000) { - IWL_ERR(mvm, - "Not valid error log pointer 0x%08X for %s uCode\n", - base, - (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) - ? "Init" : "RT"); - return; - } - - /* check if there is a HW error */ - val = iwl_trans_read_mem32(trans, base); - if (((val & ~0xf) == 0xa5a5a5a0) || ((val & ~0xf) == 0x5a5a5a50)) { - int err; - - IWL_ERR(trans, "HW error, resetting before reading\n"); - - /* reset the device */ - iwl_trans_sw_reset(trans); - - err = iwl_finish_nic_init(trans, trans->trans_cfg); - if (err) - return; - } - - iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); - - if (table.valid) - mvm->fwrt.dump.lmac_err_id[lmac_num] = table.error_id; - - if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { - IWL_ERR(trans, "Start IWL Error Log Dump:\n"); - IWL_ERR(trans, "Status: 0x%08lX, count: %d\n", - mvm->status, table.valid); - } - - /* Do not change this output - scripts rely on it */ - - IWL_ERR(mvm, "Loaded firmware version: %s\n", mvm->fw->fw_version); - - IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id, - iwl_fw_lookup_assert_desc(table.error_id)); - IWL_ERR(mvm, "0x%08X | trm_hw_status0\n", table.trm_hw_status0); - IWL_ERR(mvm, "0x%08X | trm_hw_status1\n", table.trm_hw_status1); - IWL_ERR(mvm, "0x%08X | branchlink2\n", table.blink2); - IWL_ERR(mvm, "0x%08X | interruptlink1\n", table.ilink1); - IWL_ERR(mvm, "0x%08X | interruptlink2\n", table.ilink2); - IWL_ERR(mvm, "0x%08X | data1\n", table.data1); - IWL_ERR(mvm, "0x%08X | data2\n", table.data2); - IWL_ERR(mvm, "0x%08X | data3\n", table.data3); - IWL_ERR(mvm, "0x%08X | beacon time\n", table.bcon_time); - IWL_ERR(mvm, "0x%08X | tsf low\n", table.tsf_low); - IWL_ERR(mvm, "0x%08X | tsf hi\n", table.tsf_hi); - IWL_ERR(mvm, "0x%08X | time gp1\n", table.gp1); - IWL_ERR(mvm, "0x%08X | time gp2\n", table.gp2); - IWL_ERR(mvm, "0x%08X | uCode revision type\n", table.fw_rev_type); - IWL_ERR(mvm, "0x%08X | uCode version major\n", table.major); - IWL_ERR(mvm, "0x%08X | uCode version minor\n", table.minor); - IWL_ERR(mvm, "0x%08X | hw version\n", table.hw_ver); - IWL_ERR(mvm, "0x%08X | board version\n", table.brd_ver); - IWL_ERR(mvm, "0x%08X | hcmd\n", table.hcmd); - IWL_ERR(mvm, "0x%08X | isr0\n", table.isr0); - IWL_ERR(mvm, "0x%08X | isr1\n", table.isr1); - IWL_ERR(mvm, "0x%08X | isr2\n", table.isr2); - IWL_ERR(mvm, "0x%08X | isr3\n", table.isr3); - IWL_ERR(mvm, "0x%08X | isr4\n", table.isr4); - IWL_ERR(mvm, "0x%08X | last cmd Id\n", table.last_cmd_id); - IWL_ERR(mvm, "0x%08X | wait_event\n", table.wait_event); - IWL_ERR(mvm, "0x%08X | l2p_control\n", table.l2p_control); - IWL_ERR(mvm, "0x%08X | l2p_duration\n", table.l2p_duration); - IWL_ERR(mvm, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid); - IWL_ERR(mvm, "0x%08X | l2p_addr_match\n", table.l2p_addr_match); - IWL_ERR(mvm, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel); - IWL_ERR(mvm, "0x%08X | timestamp\n", table.u_timestamp); - IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler); -} - -static void iwl_mvm_dump_iml_error_log(struct iwl_mvm *mvm) -{ - struct iwl_trans *trans = mvm->trans; - u32 error, data1; - - if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) { - error = UMAG_SB_CPU_2_STATUS; - data1 = UMAG_SB_CPU_1_STATUS; - } else if (mvm->trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_8000) { - error = SB_CPU_2_STATUS; - data1 = SB_CPU_1_STATUS; - } else { - return; - } - - error = iwl_read_umac_prph(trans, UMAG_SB_CPU_2_STATUS); - - IWL_ERR(trans, "IML/ROM dump:\n"); - - if (error & 0xFFFF0000) - IWL_ERR(trans, "0x%04X | IML/ROM SYSASSERT\n", error >> 16); - - IWL_ERR(mvm, "0x%08X | IML/ROM error/state\n", error); - IWL_ERR(mvm, "0x%08X | IML/ROM data1\n", - iwl_read_umac_prph(trans, data1)); - - if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) - IWL_ERR(mvm, "0x%08X | IML/ROM WFPM_AUTH_KEY_0\n", - iwl_read_umac_prph(trans, SB_MODIFY_CFG_FLAG)); -} - -void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) -{ - if (!test_bit(STATUS_DEVICE_ENABLED, &mvm->trans->status)) { - IWL_ERR(mvm, - "DEVICE_ENABLED bit is not set. Aborting dump.\n"); - return; - } - - iwl_mvm_dump_lmac_error_log(mvm, 0); - - if (mvm->trans->dbg.lmac_error_event_table[1]) - iwl_mvm_dump_lmac_error_log(mvm, 1); - - iwl_mvm_dump_umac_error_log(mvm); - - iwl_mvm_dump_iml_error_log(mvm); - - iwl_fw_error_print_fseq_regs(&mvm->fwrt); -} - int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id, int tid, int frame_limit, u16 ssn) { From c863797b8198e1b34516023198708ddb0f9fd2b9 Mon Sep 17 00:00:00 2001 From: ybaruch Date: Mon, 21 Jun 2021 10:37:38 +0300 Subject: [PATCH 145/170] iwlwifi: add 9560 killer device add new killer devices configurations. Signed-off-by: ybaruch Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210621103449.4179f7191531.I3d5ed6b2b39fcd42863a679e21bda23a6c14253e@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/cfg/9000.c | 6 +++++- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 2 ++ drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index df1297358379..871533beff30 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2021 Intel Corporation */ #include #include @@ -171,8 +171,12 @@ const char iwl9260_killer_1550_name[] = "Killer (R) Wireless-AC 1550 Wireless Network Adapter (9260NGW) 160MHz"; const char iwl9560_killer_1550i_name[] = "Killer (R) Wireless-AC 1550i Wireless Network Adapter (9560NGW)"; +const char iwl9560_killer_1550i_160_name[] = + "Killer(R) Wireless-AC 1550i Wireless Network Adapter (9560NGW) 160MHz"; const char iwl9560_killer_1550s_name[] = "Killer (R) Wireless-AC 1550s Wireless Network Adapter (9560NGW)"; +const char iwl9560_killer_1550s_160_name[] = + "Killer(R) Wireless-AC 1550s Wireless Network Adapter (9560D2W) 160MHz"; const struct iwl_cfg iwl9260_2ac_cfg = { .fw_name_pre = IWL9260_FW_PRE, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 3e4c6a809595..bf6ee56d4d96 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -506,6 +506,8 @@ extern const char iwl_ax201_killer_1650s_name[]; extern const char iwl_ax201_killer_1650i_name[]; extern const char iwl_ax210_killer_1675w_name[]; extern const char iwl_ax210_killer_1675x_name[]; +extern const char iwl9560_killer_1550i_160_name[]; +extern const char iwl9560_killer_1550s_160_name[]; extern const char iwl_ax211_name[]; extern const char iwl_ax221_name[]; extern const char iwl_ax231_name[]; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index a92c5f0044cd..16baee3d52ae 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -532,6 +532,8 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_DEV_INFO(0x31DC, 0x1552, iwl9560_2ac_cfg_soc, iwl9560_killer_1550i_name), IWL_DEV_INFO(0xA370, 0x1551, iwl9560_2ac_cfg_soc, iwl9560_killer_1550s_name), IWL_DEV_INFO(0xA370, 0x1552, iwl9560_2ac_cfg_soc, iwl9560_killer_1550i_name), + IWL_DEV_INFO(0x51F0, 0x1552, iwl9560_2ac_cfg_soc, iwl9560_killer_1550s_160_name), + IWL_DEV_INFO(0x51F0, 0x1551, iwl9560_2ac_cfg_soc, iwl9560_killer_1550i_160_name), IWL_DEV_INFO(0x271C, 0x0214, iwl9260_2ac_cfg, iwl9260_1_name), From 48d0c8d5a0b9999f4111efc6a1afa85199f039ea Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 21 Jun 2021 10:37:39 +0300 Subject: [PATCH 146/170] iwlwifi: fw: dump TCM error table if present If the TCM is present in the hardware (as advertised in the firmware file TLV data), dump its error log table during firmware error dumps. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210621103449.2d2149f6654f.Id831f8fbca59900ba7efc623ffca0ca938b664d3@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dump.c | 60 +++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/file.h | 5 ++ drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 11 ++++ .../net/wireless/intel/iwlwifi/iwl-trans.h | 3 + 4 files changed, 79 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c index 66f86d2a7cca..a1842205e86a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dump.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c @@ -271,6 +271,65 @@ static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_nu IWL_ERR(fwrt, "0x%08X | flow_handler\n", table.flow_handler); } +/* + * TCM error struct. + * Note: This structure is read from the device with IO accesses, + * and the reading already does the endian conversion. As it is + * read with u32-sized accesses, any members with a different size + * need to be ordered correctly though! + */ +struct iwl_tcm_error_event_table { + u32 valid; + u32 error_id; + u32 blink2; + u32 ilink1; + u32 ilink2; + u32 data1, data2, data3; + u32 logpc; + u32 frame_pointer; + u32 stack_pointer; + u32 msgid; + u32 isr; + u32 hw_status[5]; + u32 sw_status[1]; + u32 reserved[4]; +} __packed; /* TCM_LOG_ERROR_TABLE_API_S_VER_1 */ + +static void iwl_fwrt_dump_tcm_error_log(struct iwl_fw_runtime *fwrt) +{ + struct iwl_trans *trans = fwrt->trans; + struct iwl_tcm_error_event_table table = {}; + u32 base = fwrt->trans->dbg.tcm_error_event_table; + int i; + + if (!base || + !(fwrt->trans->dbg.error_event_table_tlv_status & + IWL_ERROR_EVENT_TABLE_TCM)) + return; + + iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); + + IWL_ERR(fwrt, "TCM status:\n"); + IWL_ERR(fwrt, "0x%08X | error ID\n", table.error_id); + IWL_ERR(fwrt, "0x%08X | tcm branchlink2\n", table.blink2); + IWL_ERR(fwrt, "0x%08X | tcm interruptlink1\n", table.ilink1); + IWL_ERR(fwrt, "0x%08X | tcm interruptlink2\n", table.ilink2); + IWL_ERR(fwrt, "0x%08X | tcm data1\n", table.data1); + IWL_ERR(fwrt, "0x%08X | tcm data2\n", table.data2); + IWL_ERR(fwrt, "0x%08X | tcm data3\n", table.data3); + IWL_ERR(fwrt, "0x%08X | tcm log PC\n", table.logpc); + IWL_ERR(fwrt, "0x%08X | tcm frame pointer\n", table.frame_pointer); + IWL_ERR(fwrt, "0x%08X | tcm stack pointer\n", table.stack_pointer); + IWL_ERR(fwrt, "0x%08X | tcm msg ID\n", table.msgid); + IWL_ERR(fwrt, "0x%08X | tcm ISR status\n", table.isr); + for (i = 0; i < ARRAY_SIZE(table.hw_status); i++) + IWL_ERR(fwrt, "0x%08X | tcm HW status[%d]\n", + table.hw_status[i], i); + for (i = 0; i < ARRAY_SIZE(table.sw_status); i++) + IWL_ERR(fwrt, "0x%08X | tcm SW status[%d]\n", + table.sw_status[i], i); +} + static void iwl_fwrt_dump_iml_error_log(struct iwl_fw_runtime *fwrt) { struct iwl_trans *trans = fwrt->trans; @@ -352,6 +411,7 @@ void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt) if (fwrt->trans->dbg.lmac_error_event_table[1]) iwl_fwrt_dump_lmac_error_log(fwrt, 1); iwl_fwrt_dump_umac_error_log(fwrt); + iwl_fwrt_dump_tcm_error_log(fwrt); iwl_fwrt_dump_iml_error_log(fwrt); iwl_fwrt_dump_fseq_regs(fwrt); } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 74e25a6ecc3d..9a8c7b7a0816 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -98,6 +98,7 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_PNVM_VERSION = 62, IWL_UCODE_TLV_PNVM_SKU = 64, + IWL_UCODE_TLV_TCM_DEBUG_ADDRS = 65, IWL_UCODE_TLV_FW_NUM_STATIONS = IWL_UCODE_TLV_CONST_BASE + 0, @@ -950,6 +951,10 @@ struct iwl_fw_cmd_version { u8 notif_ver; } __packed; +struct iwl_fw_tcm_error_addr { + __le32 addr; +}; /* FW_TLV_TCM_ERROR_INFO_ADDRS_S */ + static inline size_t _iwl_tlv_array_len(const struct iwl_ucode_tlv *tlv, size_t fixed_size, size_t var_size) { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 884750bf7840..977dce686bdb 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1117,6 +1117,17 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, IWL_ERROR_EVENT_TABLE_LMAC1; break; } + case IWL_UCODE_TLV_TCM_DEBUG_ADDRS: { + struct iwl_fw_tcm_error_addr *ptr = (void *)tlv_data; + + if (tlv_len != sizeof(*ptr)) + goto invalid_tlv_len; + drv->trans->dbg.tcm_error_event_table = + le32_to_cpu(ptr->addr) & ~FW_ADDR_CACHE_CONTROL; + drv->trans->dbg.error_event_table_tlv_status |= + IWL_ERROR_EVENT_TABLE_TCM; + break; + } case IWL_UCODE_TLV_TYPE_DEBUG_INFO: case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION: case IWL_UCODE_TLV_TYPE_HCMD: diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 8d745e0c0394..0199d7a5a648 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -193,6 +193,7 @@ enum iwl_error_event_table_status { IWL_ERROR_EVENT_TABLE_LMAC1 = BIT(0), IWL_ERROR_EVENT_TABLE_LMAC2 = BIT(1), IWL_ERROR_EVENT_TABLE_UMAC = BIT(2), + IWL_ERROR_EVENT_TABLE_TCM = BIT(3), }; /** @@ -708,6 +709,7 @@ struct iwl_self_init_dram { * @trigger_tlv: array of pointers to triggers TLVs for debug * @lmac_error_event_table: addrs of lmacs error tables * @umac_error_event_table: addr of umac error table + * @tcm_error_event_table: address of TCM error table * @error_event_table_tlv_status: bitmap that indicates what error table * pointers was recevied via TLV. uses enum &iwl_error_event_table_status * @internal_ini_cfg: internal debug cfg state. Uses &enum iwl_ini_cfg_state @@ -734,6 +736,7 @@ struct iwl_trans_debug { u32 lmac_error_event_table[2]; u32 umac_error_event_table; + u32 tcm_error_event_table; unsigned int error_event_table_tlv_status; enum iwl_ini_cfg_state internal_ini_cfg; From 4c59eac6ac434e08b65edd3d4bef41adfa90f58e Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Mon, 21 Jun 2021 10:37:40 +0300 Subject: [PATCH 147/170] iwlwifi: bump FW API to 64 for AX devices Start supporting API version 64 for AX devices. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20210621103449.8144a5b7d9a7.Ibf77fd7daa7d22f7c46d1c4a572ab9441a761299@changeid Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 0256d0042f71..7f1faa9d97b4 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2021 Intel Corporation */ #include #include @@ -9,7 +9,7 @@ #include "iwl-prph.h" /* Highest firmware API version supported */ -#define IWL_22000_UCODE_API_MAX 63 +#define IWL_22000_UCODE_API_MAX 64 /* Lowest firmware API version supported */ #define IWL_22000_UCODE_API_MIN 39 From cd96e22bc1da0a7ddbe0769f6e393022aa8be1f1 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Mon, 26 Apr 2021 09:32:50 +0800 Subject: [PATCH 148/170] rtw88: add beacon filter support Adding this supports beacon filter and CQM. Let firmware perform connection quality monitor and beacon processing. This make host CPU wakeup less under power save mode. To make mechanisms work as usual, fw will notify driver events such as signal change and beacon loss. This feature needs firmware 9.9.8 or newer to support it, and driver is compatible with older firmware. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210426013252.5665-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/fw.c | 91 +++++++++++++++++++ drivers/net/wireless/realtek/rtw88/fw.h | 39 ++++++++ drivers/net/wireless/realtek/rtw88/mac80211.c | 7 ++ drivers/net/wireless/realtek/rtw88/main.c | 4 +- drivers/net/wireless/realtek/rtw88/main.h | 1 + 5 files changed, 141 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index ea2cd4db1d3c..797b08b2a494 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -127,6 +127,51 @@ static void rtw_fw_ra_report_handle(struct rtw_dev *rtwdev, u8 *payload, rtw_iterate_stas_atomic(rtwdev, rtw_fw_ra_report_iter, &ra_data); } +struct rtw_beacon_filter_iter_data { + struct rtw_dev *rtwdev; + u8 *payload; +}; + +static void rtw_fw_bcn_filter_notify_vif_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct rtw_beacon_filter_iter_data *iter_data = data; + struct rtw_dev *rtwdev = iter_data->rtwdev; + u8 *payload = iter_data->payload; + u8 type = GET_BCN_FILTER_NOTIFY_TYPE(payload); + u8 event = GET_BCN_FILTER_NOTIFY_EVENT(payload); + s8 sig = (s8)GET_BCN_FILTER_NOTIFY_RSSI(payload); + + switch (type) { + case BCN_FILTER_NOTIFY_SIGNAL_CHANGE: + event = event ? NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH : + NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; + ieee80211_cqm_rssi_notify(vif, event, sig, GFP_KERNEL); + break; + case BCN_FILTER_CONNECTION_LOSS: + ieee80211_connection_loss(vif); + break; + case BCN_FILTER_CONNECTED: + rtwdev->beacon_loss = false; + break; + case BCN_FILTER_NOTIFY_BEACON_LOSS: + rtwdev->beacon_loss = true; + rtw_leave_lps(rtwdev); + break; + } +} + +static void rtw_fw_bcn_filter_notify(struct rtw_dev *rtwdev, u8 *payload, + u8 length) +{ + struct rtw_beacon_filter_iter_data dev_iter_data; + + dev_iter_data.rtwdev = rtwdev; + dev_iter_data.payload = payload; + rtw_iterate_vifs(rtwdev, rtw_fw_bcn_filter_notify_vif_iter, + &dev_iter_data); +} + void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb) { struct rtw_c2h_cmd *c2h; @@ -152,6 +197,9 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb) case C2H_WLAN_INFO: rtw_coex_wl_fwdbginfo_notify(rtwdev, c2h->payload, len); break; + case C2H_BCN_FILTER_NOTIFY: + rtw_fw_bcn_filter_notify(rtwdev, c2h->payload, len); + break; case C2H_HALMAC: rtw_fw_c2h_cmd_handle_ext(rtwdev, skb); break; @@ -527,6 +575,49 @@ void rtw_fw_update_wl_phy_info(struct rtw_dev *rtwdev) rtw_fw_send_h2c_command(rtwdev, h2c_pkt); } +void rtw_fw_beacon_filter_config(struct rtw_dev *rtwdev, bool connect, + struct ieee80211_vif *vif) +{ + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid); + static const u8 rssi_min = 0, rssi_max = 100, rssi_offset = 100; + struct rtw_sta_info *si = + sta ? (struct rtw_sta_info *)sta->drv_priv : NULL; + s32 threshold = bss_conf->cqm_rssi_thold + rssi_offset; + struct rtw_fw_state *fw = &rtwdev->fw; + u8 h2c_pkt[H2C_PKT_SIZE] = {0}; + + if (!(fw->feature & FW_FEATURE_BCN_FILTER)) + return; + + if (!connect) { + SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_BCN_FILTER_OFFLOAD_P1); + SET_BCN_FILTER_OFFLOAD_P1_ENABLE(h2c_pkt, connect); + rtw_fw_send_h2c_command(rtwdev, h2c_pkt); + + return; + } + SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_BCN_FILTER_OFFLOAD_P0); + ether_addr_copy(&h2c_pkt[1], bss_conf->bssid); + rtw_fw_send_h2c_command(rtwdev, h2c_pkt); + + memset(h2c_pkt, 0, sizeof(h2c_pkt)); + threshold = clamp_t(s32, threshold, rssi_min, rssi_max); + SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_BCN_FILTER_OFFLOAD_P1); + SET_BCN_FILTER_OFFLOAD_P1_ENABLE(h2c_pkt, connect); + SET_BCN_FILTER_OFFLOAD_P1_OFFLOAD_MODE(h2c_pkt, + BCN_FILTER_OFFLOAD_MODE_DEFAULT); + SET_BCN_FILTER_OFFLOAD_P1_THRESHOLD(h2c_pkt, (u8)threshold); + SET_BCN_FILTER_OFFLOAD_P1_BCN_LOSS_CNT(h2c_pkt, BCN_LOSS_CNT); + if (si) + SET_BCN_FILTER_OFFLOAD_P1_MACID(h2c_pkt, si->mac_id); + else + rtw_warn(rtwdev, "CQM config with station not found\n"); + SET_BCN_FILTER_OFFLOAD_P1_HYST(h2c_pkt, bss_conf->cqm_rssi_hyst); + SET_BCN_FILTER_OFFLOAD_P1_BCN_INTERVAL(h2c_pkt, bss_conf->beacon_int); + rtw_fw_send_h2c_command(rtwdev, h2c_pkt); +} + void rtw_fw_set_pwr_mode(struct rtw_dev *rtwdev) { struct rtw_lps_conf *conf = &rtwdev->lps_conf; diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h index 7c5b1d75e26f..3bfee27b1e1a 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.h +++ b/drivers/net/wireless/realtek/rtw88/fw.h @@ -24,6 +24,12 @@ #define DLFW_BLK_SIZE_LEGACY 4 #define FW_START_ADDR_LEGACY 0x1000 +#define BCN_LOSS_CNT 10 +#define BCN_FILTER_NOTIFY_SIGNAL_CHANGE 0 +#define BCN_FILTER_CONNECTION_LOSS 1 +#define BCN_FILTER_CONNECTED 2 +#define BCN_FILTER_NOTIFY_BEACON_LOSS 3 + enum rtw_c2h_cmd_id { C2H_CCX_TX_RPT = 0x03, C2H_BT_INFO = 0x09, @@ -32,6 +38,7 @@ enum rtw_c2h_cmd_id { C2H_HW_FEATURE_REPORT = 0x19, C2H_WLAN_INFO = 0x27, C2H_WLAN_RFON = 0x32, + C2H_BCN_FILTER_NOTIFY = 0x36, C2H_HW_FEATURE_DUMP = 0xfd, C2H_HALMAC = 0xff, }; @@ -78,9 +85,19 @@ enum rtw_fw_feature { FW_FEATURE_LPS_C2H = BIT(1), FW_FEATURE_LCLK = BIT(2), FW_FEATURE_PG = BIT(3), + FW_FEATURE_BCN_FILTER = BIT(5), FW_FEATURE_MAX = BIT(31), }; +enum rtw_beacon_filter_offload_mode { + BCN_FILTER_OFFLOAD_MODE_0 = 0, + BCN_FILTER_OFFLOAD_MODE_1, + BCN_FILTER_OFFLOAD_MODE_2, + BCN_FILTER_OFFLOAD_MODE_3, + + BCN_FILTER_OFFLOAD_MODE_DEFAULT = BCN_FILTER_OFFLOAD_MODE_1, +}; + struct rtw_coex_info_req { u8 seq; u8 op_code; @@ -237,6 +254,10 @@ struct rtw_fw_hdr_legacy { #define GET_RA_REPORT_BW(c2h_payload) (c2h_payload[6]) #define GET_RA_REPORT_MACID(c2h_payload) (c2h_payload[1]) +#define GET_BCN_FILTER_NOTIFY_TYPE(c2h_payload) (c2h_payload[1] & 0xf) +#define GET_BCN_FILTER_NOTIFY_EVENT(c2h_payload) (c2h_payload[1] & 0x10) +#define GET_BCN_FILTER_NOTIFY_RSSI(c2h_payload) (c2h_payload[2] - 100) + /* PKT H2C */ #define H2C_PKT_CMD_ID 0xFF #define H2C_PKT_CATEGORY 0x01 @@ -345,6 +366,8 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id) #define H2C_CMD_LPS_PG_INFO 0x2b #define H2C_CMD_RA_INFO 0x40 #define H2C_CMD_RSSI_MONITOR 0x42 +#define H2C_CMD_BCN_FILTER_OFFLOAD_P0 0x56 +#define H2C_CMD_BCN_FILTER_OFFLOAD_P1 0x57 #define H2C_CMD_WL_PHY_INFO 0x58 #define H2C_CMD_COEX_TDMA_TYPE 0x60 @@ -381,6 +404,20 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id) le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(15, 8)) #define SET_WL_PHY_INFO_RX_EVM(h2c_pkt, value) \ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(23, 16)) +#define SET_BCN_FILTER_OFFLOAD_P1_MACID(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8)) +#define SET_BCN_FILTER_OFFLOAD_P1_ENABLE(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(16)) +#define SET_BCN_FILTER_OFFLOAD_P1_HYST(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(20, 17)) +#define SET_BCN_FILTER_OFFLOAD_P1_OFFLOAD_MODE(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 21)) +#define SET_BCN_FILTER_OFFLOAD_P1_THRESHOLD(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24)) +#define SET_BCN_FILTER_OFFLOAD_P1_BCN_LOSS_CNT(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(3, 0)) +#define SET_BCN_FILTER_OFFLOAD_P1_BCN_INTERVAL(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(13, 4)) #define SET_PWR_MODE_SET_MODE(h2c_pkt, value) \ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(14, 8)) @@ -577,6 +614,8 @@ void rtw_fw_send_rssi_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si); void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si); void rtw_fw_media_status_report(struct rtw_dev *rtwdev, u8 mac_id, bool conn); void rtw_fw_update_wl_phy_info(struct rtw_dev *rtwdev); +void rtw_fw_beacon_filter_config(struct rtw_dev *rtwdev, bool connect, + struct ieee80211_vif *vif); int rtw_fw_write_data_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr, u8 *buf, u32 size); void rtw_remove_rsvd_page(struct rtw_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 333df6b38113..9087c5b1ea80 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -148,11 +148,15 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw, { struct rtw_dev *rtwdev = hw->priv; struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; + struct rtw_fw_state *fw = &rtwdev->fw; enum rtw_net_type net_type; u32 config = 0; u8 port = 0; u8 bcn_ctrl = 0; + if (fw->feature & FW_FEATURE_BCN_FILTER) + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | + IEEE80211_VIF_SUPPORTS_CQM_RSSI; rtwvif->port = port; rtwvif->stats.tx_unicast = 0; rtwvif->stats.rx_unicast = 0; @@ -399,6 +403,8 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, rtw_write32_clr(rtwdev, REG_FWHW_TXQ_CTRL, BIT_EN_BCNQ_DL); } + if (changed & BSS_CHANGED_CQM) + rtw_fw_beacon_filter_config(rtwdev, true, vif); if (changed & BSS_CHANGED_MU_GROUPS) rtw_chip_set_gid_table(rtwdev, vif, conf); @@ -450,6 +456,7 @@ static int rtw_ops_sta_remove(struct ieee80211_hw *hw, { struct rtw_dev *rtwdev = hw->priv; + rtw_fw_beacon_filter_config(rtwdev, false, vif); mutex_lock(&rtwdev->mutex); rtw_sta_remove(rtwdev, sta, true); mutex_unlock(&rtwdev->mutex); diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index f3a3a86fa9b5..94fadef5c131 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -239,7 +239,8 @@ static void rtw_watch_dog_work(struct work_struct *work) * get that vif and check if device is having traffic more than the * threshold. */ - if (rtwdev->ps_enabled && data.rtwvif && !ps_active) + if (rtwdev->ps_enabled && data.rtwvif && !ps_active && + !rtwdev->beacon_loss) rtw_enter_lps(rtwdev, data.rtwvif->port); rtwdev->watch_dog_cnt++; @@ -292,6 +293,7 @@ int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, rtw_fw_media_status_report(rtwdev, si->mac_id, true); rtwdev->sta_cnt++; + rtwdev->beacon_loss = false; rtw_info(rtwdev, "sta %pM joined with macid %d\n", sta->addr, si->mac_id); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index dc3744847ba9..321667c03b16 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -1837,6 +1837,7 @@ struct rtw_dev { /* lps power state & handler work */ struct rtw_lps_conf lps_conf; bool ps_enabled; + bool beacon_loss; struct completion lps_leave_check; struct dentry *debugfs; From 1188301fd8ef370ef344a98fbbf04b8b07148294 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Mon, 26 Apr 2021 09:32:51 +0800 Subject: [PATCH 149/170] rtw88: add path diversity This feature chooses to transmit with antenna that has better signal strength periodically under 1ss rate. It can benefit connection quality in the following cases: 1. User is far away from the AP. 2. The far-field pattern of the antenna showed significant signal strength difference. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210426013252.5665-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/debug.h | 1 + drivers/net/wireless/realtek/rtw88/main.h | 15 ++++ drivers/net/wireless/realtek/rtw88/phy.c | 81 +++++++++++++++++++ drivers/net/wireless/realtek/rtw88/phy.h | 1 + drivers/net/wireless/realtek/rtw88/rtw8822c.c | 39 +++++++-- 5 files changed, 131 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/debug.h b/drivers/net/wireless/realtek/rtw88/debug.h index c8efd1900a34..0dd3f9a88c8d 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.h +++ b/drivers/net/wireless/realtek/rtw88/debug.h @@ -20,6 +20,7 @@ enum rtw_debug_mask { RTW_DBG_BF = 0x00000800, RTW_DBG_WOW = 0x00001000, RTW_DBG_CFO = 0x00002000, + RTW_DBG_PATH_DIV = 0x00004000, RTW_DBG_ALL = 0xffffffff }; diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 321667c03b16..02ad175055cb 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -841,6 +841,10 @@ struct rtw_chip_ops { u8 fixrate_en, u8 *new_rate); void (*cfo_init)(struct rtw_dev *rtwdev); void (*cfo_track)(struct rtw_dev *rtwdev); + void (*config_tx_path)(struct rtw_dev *rtwdev, u8 tx_path, + enum rtw_bb_path tx_path_1ss, + enum rtw_bb_path tx_path_cck, + bool is_tx2_path); /* for coex */ void (*coex_set_init)(struct rtw_dev *rtwdev); @@ -1136,7 +1140,9 @@ struct rtw_chip_info { u8 max_power_index; u16 fw_fifo_addr[RTW_FW_FIFO_MAX]; + u8 default_1ss_tx_path; + bool path_div_supported; bool ht_supported; bool vht_supported; u8 lps_deep_mode_supported; @@ -1781,6 +1787,14 @@ struct rtw_hal { [DESC_RATE_MAX]; }; +struct rtw_path_div { + enum rtw_bb_path current_tx_path; + u32 path_a_sum; + u32 path_b_sum; + u16 path_a_cnt; + u16 path_b_cnt; +}; + struct rtw_dev { struct ieee80211_hw *hw; struct device *dev; @@ -1849,6 +1863,7 @@ struct rtw_dev { DECLARE_BITMAP(flags, NUM_OF_RTW_FLAGS); u8 mp_mode; + struct rtw_path_div dm_path_div; struct rtw_fw_state wow_fw; struct rtw_wow_param wow; diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index 8146acaf1893..569dd3cfde35 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -127,6 +127,17 @@ static void rtw_phy_cfo_init(struct rtw_dev *rtwdev) chip->ops->cfo_init(rtwdev); } +static void rtw_phy_tx_path_div_init(struct rtw_dev *rtwdev) +{ + struct rtw_path_div *path_div = &rtwdev->dm_path_div; + + path_div->current_tx_path = rtwdev->chip->default_1ss_tx_path; + path_div->path_a_cnt = 0; + path_div->path_a_sum = 0; + path_div->path_b_cnt = 0; + path_div->path_b_sum = 0; +} + void rtw_phy_init(struct rtw_dev *rtwdev) { struct rtw_chip_info *chip = rtwdev->chip; @@ -149,6 +160,7 @@ void rtw_phy_init(struct rtw_dev *rtwdev) dm_info->iqk.done = false; rtw_phy_cfo_init(rtwdev); + rtw_phy_tx_path_div_init(rtwdev); } EXPORT_SYMBOL(rtw_phy_init); @@ -695,6 +707,7 @@ void rtw_phy_dynamic_mechanism(struct rtw_dev *rtwdev) rtw_phy_dig(rtwdev); rtw_phy_cck_pd(rtwdev); rtw_phy_ra_track(rtwdev); + rtw_phy_tx_path_diversity(rtwdev); rtw_phy_cfo_track(rtwdev); rtw_phy_dpk_track(rtwdev); rtw_phy_pwr_track(rtwdev); @@ -2315,3 +2328,71 @@ bool rtw_phy_pwrtrack_need_iqk(struct rtw_dev *rtwdev) return false; } EXPORT_SYMBOL(rtw_phy_pwrtrack_need_iqk); + +static void rtw_phy_set_tx_path_by_reg(struct rtw_dev *rtwdev, + enum rtw_bb_path tx_path_sel_1ss) +{ + struct rtw_path_div *path_div = &rtwdev->dm_path_div; + enum rtw_bb_path tx_path_sel_cck = tx_path_sel_1ss; + struct rtw_chip_info *chip = rtwdev->chip; + + if (tx_path_sel_1ss == path_div->current_tx_path) + return; + + path_div->current_tx_path = tx_path_sel_1ss; + rtw_dbg(rtwdev, RTW_DBG_PATH_DIV, "Switch TX path=%s\n", + tx_path_sel_1ss == BB_PATH_A ? "A" : "B"); + chip->ops->config_tx_path(rtwdev, rtwdev->hal.antenna_tx, + tx_path_sel_1ss, tx_path_sel_cck, false); +} + +static void rtw_phy_tx_path_div_select(struct rtw_dev *rtwdev) +{ + struct rtw_path_div *path_div = &rtwdev->dm_path_div; + enum rtw_bb_path path = path_div->current_tx_path; + s32 rssi_a = 0, rssi_b = 0; + + if (path_div->path_a_cnt) + rssi_a = path_div->path_a_sum / path_div->path_a_cnt; + else + rssi_a = 0; + if (path_div->path_b_cnt) + rssi_b = path_div->path_b_sum / path_div->path_b_cnt; + else + rssi_b = 0; + + if (rssi_a != rssi_b) + path = (rssi_a > rssi_b) ? BB_PATH_A : BB_PATH_B; + + path_div->path_a_cnt = 0; + path_div->path_a_sum = 0; + path_div->path_b_cnt = 0; + path_div->path_b_sum = 0; + rtw_phy_set_tx_path_by_reg(rtwdev, path); +} + +static void rtw_phy_tx_path_diversity_2ss(struct rtw_dev *rtwdev) +{ + if (rtwdev->hal.antenna_rx != BB_PATH_AB) { + rtw_dbg(rtwdev, RTW_DBG_PATH_DIV, + "[Return] tx_Path_en=%d, rx_Path_en=%d\n", + rtwdev->hal.antenna_tx, rtwdev->hal.antenna_rx); + return; + } + if (rtwdev->sta_cnt == 0) { + rtw_dbg(rtwdev, RTW_DBG_PATH_DIV, "No Link\n"); + return; + } + + rtw_phy_tx_path_div_select(rtwdev); +} + +void rtw_phy_tx_path_diversity(struct rtw_dev *rtwdev) +{ + struct rtw_chip_info *chip = rtwdev->chip; + + if (!chip->path_div_supported) + return; + + rtw_phy_tx_path_diversity_2ss(rtwdev); +} diff --git a/drivers/net/wireless/realtek/rtw88/phy.h b/drivers/net/wireless/realtek/rtw88/phy.h index 0b6f2fc8193c..112ed125970a 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.h +++ b/drivers/net/wireless/realtek/rtw88/phy.h @@ -61,6 +61,7 @@ void rtw_phy_config_swing_table(struct rtw_dev *rtwdev, struct rtw_swing_table *swing_table); void rtw_phy_parsing_cfo(struct rtw_dev *rtwdev, struct rtw_rx_pkt_stat *pkt_stat); +void rtw_phy_tx_path_diversity(struct rtw_dev *rtwdev); struct rtw_txpwr_lmt_cfg_pair { u8 regd; diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 6cb593cc33c2..b6b43654e5c6 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -80,6 +80,13 @@ static void rtw8822c_header_file_init(struct rtw_dev *rtwdev, bool pre) rtw_write32_set(rtwdev, REG_ENCCK, BIT_CCK_OFDM_BLK_EN); } +static void rtw8822c_bb_reset(struct rtw_dev *rtwdev) +{ + rtw_write16_set(rtwdev, REG_SYS_FUNC_EN, BIT_FEN_BB_RSTB); + rtw_write16_clr(rtwdev, REG_SYS_FUNC_EN, BIT_FEN_BB_RSTB); + rtw_write16_set(rtwdev, REG_SYS_FUNC_EN, BIT_FEN_BB_RSTB); +} + static void rtw8822c_dac_backup_reg(struct rtw_dev *rtwdev, struct rtw_backup_info *backup, struct rtw_backup_info *backup_rf) @@ -2424,10 +2431,11 @@ static void rtw8822c_config_cck_tx_path(struct rtw_dev *rtwdev, u8 tx_path, else rtw_write32_mask(rtwdev, REG_RXCCKSEL, 0xf0000000, 0x8); } + rtw8822c_bb_reset(rtwdev); } static void rtw8822c_config_ofdm_tx_path(struct rtw_dev *rtwdev, u8 tx_path, - bool is_tx2_path) + enum rtw_bb_path tx_path_sel_1ss) { if (tx_path == BB_PATH_A) { rtw_write32_mask(rtwdev, REG_ANTMAP0, 0xff, 0x11); @@ -2436,21 +2444,28 @@ static void rtw8822c_config_ofdm_tx_path(struct rtw_dev *rtwdev, u8 tx_path, rtw_write32_mask(rtwdev, REG_ANTMAP0, 0xff, 0x12); rtw_write32_mask(rtwdev, REG_TXLGMAP, 0xff, 0x0); } else { - if (is_tx2_path) { + if (tx_path_sel_1ss == BB_PATH_AB) { rtw_write32_mask(rtwdev, REG_ANTMAP0, 0xff, 0x33); rtw_write32_mask(rtwdev, REG_TXLGMAP, 0xffff, 0x0404); - } else { + } else if (tx_path_sel_1ss == BB_PATH_B) { + rtw_write32_mask(rtwdev, REG_ANTMAP0, 0xff, 0x32); + rtw_write32_mask(rtwdev, REG_TXLGMAP, 0xffff, 0x0400); + } else if (tx_path_sel_1ss == BB_PATH_A) { rtw_write32_mask(rtwdev, REG_ANTMAP0, 0xff, 0x31); rtw_write32_mask(rtwdev, REG_TXLGMAP, 0xffff, 0x0400); } } + rtw8822c_bb_reset(rtwdev); } static void rtw8822c_config_tx_path(struct rtw_dev *rtwdev, u8 tx_path, + enum rtw_bb_path tx_path_sel_1ss, + enum rtw_bb_path tx_path_cck, bool is_tx2_path) { - rtw8822c_config_cck_tx_path(rtwdev, tx_path, is_tx2_path); - rtw8822c_config_ofdm_tx_path(rtwdev, tx_path, is_tx2_path); + rtw8822c_config_cck_tx_path(rtwdev, tx_path_cck, is_tx2_path); + rtw8822c_config_ofdm_tx_path(rtwdev, tx_path, tx_path_sel_1ss); + rtw8822c_bb_reset(rtwdev); } static void rtw8822c_config_trx_mode(struct rtw_dev *rtwdev, u8 tx_path, @@ -2466,7 +2481,8 @@ static void rtw8822c_config_trx_mode(struct rtw_dev *rtwdev, u8 tx_path, rtw_write32_mask(rtwdev, REG_ORITXCODE2, MASK20BITS, 0x11111); rtw8822c_config_rx_path(rtwdev, rx_path); - rtw8822c_config_tx_path(rtwdev, tx_path, is_tx2_path); + rtw8822c_config_tx_path(rtwdev, tx_path, BB_PATH_A, BB_PATH_A, + is_tx2_path); rtw8822c_toggle_igi(rtwdev); } @@ -2517,6 +2533,7 @@ static void query_phy_status_page0(struct rtw_dev *rtwdev, u8 *phy_status, static void query_phy_status_page1(struct rtw_dev *rtwdev, u8 *phy_status, struct rtw_rx_pkt_stat *pkt_stat) { + struct rtw_path_div *p_div = &rtwdev->dm_path_div; struct rtw_dm_info *dm_info = &rtwdev->dm_info; u8 rxsc, bw; s8 min_rx_power = -120; @@ -2559,6 +2576,13 @@ static void query_phy_status_page1(struct rtw_dev *rtwdev, u8 *phy_status, for (path = 0; path <= rtwdev->hal.rf_path_num; path++) { rssi = rtw_phy_rf_power_2_rssi(&pkt_stat->rx_power[path], 1); dm_info->rssi[path] = rssi; + if (path == RF_PATH_A) { + p_div->path_a_sum += rssi; + p_div->path_a_cnt++; + } else if (path == RF_PATH_B) { + p_div->path_b_sum += rssi; + p_div->path_b_cnt++; + } dm_info->rx_snr[path] = pkt_stat->rx_snr[path] >> 1; dm_info->cfo_tail[path] = (pkt_stat->cfo_tail[path] * 5) >> 1; @@ -4851,6 +4875,7 @@ static struct rtw_chip_ops rtw8822c_ops = { .cfg_csi_rate = rtw_bf_cfg_csi_rate, .cfo_init = rtw8822c_cfo_init, .cfo_track = rtw8822c_cfo_track, + .config_tx_path = rtw8822c_config_tx_path, .coex_set_init = rtw8822c_coex_cfg_init, .coex_set_ant_switch = NULL, @@ -5192,6 +5217,8 @@ struct rtw_chip_info rtw8822c_hw_spec = { .band = RTW_BAND_2G | RTW_BAND_5G, .page_size = 128, .dig_min = 0x20, + .default_1ss_tx_path = BB_PATH_A, + .path_div_supported = true, .ht_supported = true, .vht_supported = true, .lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK) | BIT(LPS_DEEP_MODE_PG), From 05684fd583e1acc34dddea283838fbfbed4904a0 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Mon, 26 Apr 2021 09:32:52 +0800 Subject: [PATCH 150/170] rtw88: 8822c: fix lc calibration timing Before this patch, we use value from 2 seconds ago to decide whether we should do lc calibration. Although this don't happen frequently, fix flow to the way it should be. Fixes: 7ae7784ec2a8 ("rtw88: 8822c: add LC calibration for RTL8822C") Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210426013252.5665-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/rtw8822c.c | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index b6b43654e5c6..436347f3b60f 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -4395,26 +4395,28 @@ static void rtw8822c_pwrtrack_set(struct rtw_dev *rtwdev, u8 rf_path) } } -static void rtw8822c_pwr_track_path(struct rtw_dev *rtwdev, - struct rtw_swing_table *swing_table, - u8 path) +static void rtw8822c_pwr_track_stats(struct rtw_dev *rtwdev, u8 path) { - struct rtw_dm_info *dm_info = &rtwdev->dm_info; - u8 thermal_value, delta; + u8 thermal_value; if (rtwdev->efuse.thermal_meter[path] == 0xff) return; thermal_value = rtw_read_rf(rtwdev, path, RF_T_METER, 0x7e); - rtw_phy_pwrtrack_avg(rtwdev, thermal_value, path); +} + +static void rtw8822c_pwr_track_path(struct rtw_dev *rtwdev, + struct rtw_swing_table *swing_table, + u8 path) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 delta; delta = rtw_phy_pwrtrack_get_delta(rtwdev, path); - dm_info->delta_power_index[path] = rtw_phy_pwrtrack_get_pwridx(rtwdev, swing_table, path, path, delta); - rtw8822c_pwrtrack_set(rtwdev, path); } @@ -4425,12 +4427,12 @@ static void __rtw8822c_pwr_track(struct rtw_dev *rtwdev) rtw_phy_config_swing_table(rtwdev, &swing_table); + for (i = 0; i < rtwdev->hal.rf_path_num; i++) + rtw8822c_pwr_track_stats(rtwdev, i); if (rtw_phy_pwrtrack_need_lck(rtwdev)) rtw8822c_do_lck(rtwdev); - for (i = 0; i < rtwdev->hal.rf_path_num; i++) rtw8822c_pwr_track_path(rtwdev, &swing_table, i); - } static void rtw8822c_pwr_track(struct rtw_dev *rtwdev) From 3eab8ca6b1756d551da42e958c6f48f68cf470d3 Mon Sep 17 00:00:00 2001 From: Wan Jiabing Date: Fri, 30 Apr 2021 10:49:50 +0800 Subject: [PATCH 151/170] rtw88: Remove duplicate include of coex.h In commit fb8517f4fade4 ("rtw88: 8822c: add CFO tracking"), "coex.h" was added here which caused the duplicate include. Remove the later duplicate include. Signed-off-by: Wan Jiabing Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210430024951.33406-1-wanjiabing@vivo.com --- drivers/net/wireless/realtek/rtw88/rtw8822c.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 436347f3b60f..1a6721611dc1 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -17,7 +17,6 @@ #include "util.h" #include "bf.h" #include "efuse.h" -#include "coex.h" #define IQK_DONE_8822C 0xaa From 7a1baaaee6c866455c9c77bf9b0405941a3678c7 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Thu, 6 May 2021 16:36:43 +0800 Subject: [PATCH 152/170] rtw88: 8822c: update RF parameter tables to v62 Update RTL8822C devices' RF tables to v62. This fixes higher than expected spur in 2400 MHz under CCK mask. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210506083643.18317-1-pkshih@realtek.com --- .../wireless/realtek/rtw88/rtw8822c_table.c | 1008 ++++++++--------- 1 file changed, 504 insertions(+), 504 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c b/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c index 822f3da91f1b..f9e3d0779c59 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c @@ -16812,53 +16812,53 @@ static const u32 rtw8822c_rf_a[] = { 0x92000002, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x00010E46, 0x93000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x93000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x93000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x93000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x93000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x93000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x93000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x93000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x94000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x94000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x94000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x94000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x94000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x94000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x94000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x94000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x95000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x95000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x95000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x95000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x95000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x95000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x95000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x95000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0xA0000000, 0x00000000, 0x03F, 0x00002A46, 0xB0000000, 0x00000000, @@ -18762,53 +18762,53 @@ static const u32 rtw8822c_rf_a[] = { 0x92000002, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x0000EA46, 0x93000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0xA0000000, 0x00000000, 0x03F, 0x00002A46, 0xB0000000, 0x00000000, @@ -18957,53 +18957,53 @@ static const u32 rtw8822c_rf_a[] = { 0x92000002, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x0000EA46, 0x93000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0xA0000000, 0x00000000, 0x03F, 0x00002A46, 0xB0000000, 0x00000000, @@ -19152,53 +19152,53 @@ static const u32 rtw8822c_rf_a[] = { 0x92000002, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x0000EA46, 0x93000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0xA0000000, 0x00000000, 0x03F, 0x00002A46, 0xB0000000, 0x00000000, @@ -19347,53 +19347,53 @@ static const u32 rtw8822c_rf_a[] = { 0x92000002, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x0000EA46, 0x93000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0xA0000000, 0x00000000, 0x03F, 0x00002A46, 0xB0000000, 0x00000000, @@ -19610,21 +19610,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000002, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19633,21 +19633,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000003, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19656,21 +19656,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000004, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19679,21 +19679,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000005, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19702,21 +19702,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000006, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19725,21 +19725,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000015, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19748,21 +19748,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000016, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19771,21 +19771,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000001, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19794,21 +19794,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000002, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19817,21 +19817,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000003, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19840,21 +19840,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000004, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19863,21 +19863,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000005, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19886,21 +19886,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000006, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19909,21 +19909,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000015, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19932,21 +19932,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000016, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19955,21 +19955,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000001, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19978,21 +19978,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000002, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -20001,21 +20001,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000003, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -20024,21 +20024,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000004, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -20047,21 +20047,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000005, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -20070,21 +20070,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000006, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -20093,21 +20093,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000015, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -20116,21 +20116,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000016, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -20139,21 +20139,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0xA0000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000487, @@ -38484,21 +38484,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000002, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38507,21 +38507,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000003, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38530,21 +38530,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000004, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38553,21 +38553,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000005, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38576,21 +38576,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000006, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38599,21 +38599,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000015, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38622,21 +38622,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000016, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38645,21 +38645,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000001, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38668,21 +38668,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000002, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38691,21 +38691,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000003, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38714,21 +38714,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000004, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38737,21 +38737,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000005, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38760,21 +38760,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000006, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38783,21 +38783,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000015, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38806,21 +38806,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000016, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38829,21 +38829,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000001, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38852,21 +38852,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000002, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38875,21 +38875,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000003, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38898,21 +38898,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000004, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38921,21 +38921,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000005, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38944,21 +38944,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000006, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38967,21 +38967,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000015, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38990,21 +38990,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000016, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -39013,21 +39013,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0xA0000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000487, From 9a711831c4e71f29897b3489c3097081aea580c4 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Fri, 14 May 2021 15:55:16 +0800 Subject: [PATCH 153/170] rtw88: add rtw_fw_feature_check api add api to check if a certain feature is supported. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210514075517.14216-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/fw.c | 3 +-- drivers/net/wireless/realtek/rtw88/fw.h | 6 ++++++ drivers/net/wireless/realtek/rtw88/mac80211.c | 3 +-- drivers/net/wireless/realtek/rtw88/main.c | 4 ++-- drivers/net/wireless/realtek/rtw88/ps.c | 4 ++-- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 797b08b2a494..00c56ab6306b 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -584,10 +584,9 @@ void rtw_fw_beacon_filter_config(struct rtw_dev *rtwdev, bool connect, struct rtw_sta_info *si = sta ? (struct rtw_sta_info *)sta->drv_priv : NULL; s32 threshold = bss_conf->cqm_rssi_thold + rssi_offset; - struct rtw_fw_state *fw = &rtwdev->fw; u8 h2c_pkt[H2C_PKT_SIZE] = {0}; - if (!(fw->feature & FW_FEATURE_BCN_FILTER)) + if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_BCN_FILTER)) return; if (!connect) { diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h index 3bfee27b1e1a..832ef2bfe5f9 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.h +++ b/drivers/net/wireless/realtek/rtw88/fw.h @@ -591,6 +591,12 @@ static inline struct rtw_c2h_cmd *get_c2h_from_skb(struct sk_buff *skb) return (struct rtw_c2h_cmd *)(skb->data + pkt_offset); } +static inline bool rtw_fw_feature_check(struct rtw_fw_state *fw, + enum rtw_fw_feature feature) +{ + return !!(fw->feature & feature); +} + void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset, struct sk_buff *skb); void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb); diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 9087c5b1ea80..8f46b16c8d5d 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -148,13 +148,12 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw, { struct rtw_dev *rtwdev = hw->priv; struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; - struct rtw_fw_state *fw = &rtwdev->fw; enum rtw_net_type net_type; u32 config = 0; u8 port = 0; u8 bcn_ctrl = 0; - if (fw->feature & FW_FEATURE_BCN_FILTER) + if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_BCN_FILTER)) vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | IEEE80211_VIF_SUPPORTS_CQM_RSSI; rtwvif->port = port; diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 94fadef5c131..df115bb7fdf7 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1111,11 +1111,11 @@ static enum rtw_lps_deep_mode rtw_update_lps_deep_mode(struct rtw_dev *rtwdev, return LPS_DEEP_MODE_NONE; if ((chip->lps_deep_mode_supported & BIT(LPS_DEEP_MODE_PG)) && - (fw->feature & FW_FEATURE_PG)) + rtw_fw_feature_check(fw, FW_FEATURE_PG)) return LPS_DEEP_MODE_PG; if ((chip->lps_deep_mode_supported & BIT(LPS_DEEP_MODE_LCLK)) && - (fw->feature & FW_FEATURE_LCLK)) + rtw_fw_feature_check(fw, FW_FEATURE_LCLK)) return LPS_DEEP_MODE_LCLK; return LPS_DEEP_MODE_NONE; diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index 3bead34c3d10..3f0ac33156d6 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -152,7 +152,7 @@ static void rtw_fw_leave_lps_check(struct rtw_dev *rtwdev) else fw = &rtwdev->fw; - if (fw->feature & FW_FEATURE_LPS_C2H) + if (rtw_fw_feature_check(fw, FW_FEATURE_LPS_C2H)) ret = __rtw_fw_leave_lps_check_c2h(rtwdev); else ret = __rtw_fw_leave_lps_check_reg(rtwdev); @@ -172,7 +172,7 @@ static void rtw_fw_leave_lps_check_prepare(struct rtw_dev *rtwdev) else fw = &rtwdev->fw; - if (fw->feature & FW_FEATURE_LPS_C2H) + if (rtw_fw_feature_check(fw, FW_FEATURE_LPS_C2H)) reinit_completion(&rtwdev->lps_leave_check); } From a853d234e179086040912a8bbb3341829c079495 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Fri, 14 May 2021 15:55:17 +0800 Subject: [PATCH 154/170] rtw88: notify fw when driver in scan-period to avoid potential problem It is found that driver scan could be affected by dynamic mechanism of firmware, so we notify firmware to stop it in the scan period. Another, firmware will detect the background noise and report to driver for further use. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210514075517.14216-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/fw.c | 25 +++++++++++++++++++ drivers/net/wireless/realtek/rtw88/fw.h | 10 +++++++- drivers/net/wireless/realtek/rtw88/mac80211.c | 3 +++ drivers/net/wireless/realtek/rtw88/main.c | 17 +++++++++++++ drivers/net/wireless/realtek/rtw88/main.h | 4 +++ 5 files changed, 58 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 00c56ab6306b..58f4e47aa96a 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -172,6 +172,17 @@ static void rtw_fw_bcn_filter_notify(struct rtw_dev *rtwdev, u8 *payload, &dev_iter_data); } +static void rtw_fw_scan_result(struct rtw_dev *rtwdev, u8 *payload, + u8 length) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + dm_info->scan_density = payload[0]; + + rtw_dbg(rtwdev, RTW_DBG_FW, "scan.density = %x\n", + dm_info->scan_density); +} + void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb) { struct rtw_c2h_cmd *c2h; @@ -235,6 +246,10 @@ void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset, case C2H_WLAN_RFON: complete(&rtwdev->lps_leave_check); break; + case C2H_SCAN_RESULT: + complete(&rtwdev->fw_scan_density); + rtw_fw_scan_result(rtwdev, c2h->payload, len); + break; default: /* pass offset for further operation */ *((u32 *)skb->cb) = pkt_offset; @@ -1703,3 +1718,13 @@ void rtw_fw_channel_switch(struct rtw_dev *rtwdev, bool enable) rtw_fw_send_h2c_packet(rtwdev, h2c_pkt); } + +void rtw_fw_scan_notify(struct rtw_dev *rtwdev, bool start) +{ + u8 h2c_pkt[H2C_PKT_SIZE] = {0}; + + SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_SCAN); + SET_SCAN_START(h2c_pkt, start); + + rtw_fw_send_h2c_command(rtwdev, h2c_pkt); +} diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h index 832ef2bfe5f9..a8a7162fbe64 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.h +++ b/drivers/net/wireless/realtek/rtw88/fw.h @@ -30,6 +30,8 @@ #define BCN_FILTER_CONNECTED 2 #define BCN_FILTER_NOTIFY_BEACON_LOSS 3 +#define SCAN_NOTIFY_TIMEOUT msecs_to_jiffies(10) + enum rtw_c2h_cmd_id { C2H_CCX_TX_RPT = 0x03, C2H_BT_INFO = 0x09, @@ -39,6 +41,7 @@ enum rtw_c2h_cmd_id { C2H_WLAN_INFO = 0x27, C2H_WLAN_RFON = 0x32, C2H_BCN_FILTER_NOTIFY = 0x36, + C2H_SCAN_RESULT = 0x38, C2H_HW_FEATURE_DUMP = 0xfd, C2H_HALMAC = 0xff, }; @@ -86,6 +89,7 @@ enum rtw_fw_feature { FW_FEATURE_LCLK = BIT(2), FW_FEATURE_PG = BIT(3), FW_FEATURE_BCN_FILTER = BIT(5), + FW_FEATURE_NOTIFY_SCAN = BIT(6), FW_FEATURE_MAX = BIT(31), }; @@ -369,6 +373,7 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id) #define H2C_CMD_BCN_FILTER_OFFLOAD_P0 0x56 #define H2C_CMD_BCN_FILTER_OFFLOAD_P1 0x57 #define H2C_CMD_WL_PHY_INFO 0x58 +#define H2C_CMD_SCAN 0x59 #define H2C_CMD_COEX_TDMA_TYPE 0x60 #define H2C_CMD_QUERY_BT_INFO 0x61 @@ -419,6 +424,9 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id) #define SET_BCN_FILTER_OFFLOAD_P1_BCN_INTERVAL(h2c_pkt, value) \ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(13, 4)) +#define SET_SCAN_START(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8)) + #define SET_PWR_MODE_SET_MODE(h2c_pkt, value) \ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(14, 8)) #define SET_PWR_MODE_SET_RLBM(h2c_pkt, value) \ @@ -652,5 +660,5 @@ void rtw_fw_h2c_cmd_dbg(struct rtw_dev *rtwdev, u8 *h2c); void rtw_fw_c2h_cmd_isr(struct rtw_dev *rtwdev); int rtw_fw_dump_fifo(struct rtw_dev *rtwdev, u8 fifo_sel, u32 addr, u32 size, u32 *buffer); - +void rtw_fw_scan_notify(struct rtw_dev *rtwdev, bool start); #endif diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 8f46b16c8d5d..8a180c95e7e6 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -605,6 +605,7 @@ static void rtw_ops_sw_scan_start(struct ieee80211_hw *hw, rtw_vif_port_config(rtwdev, rtwvif, config); rtw_coex_scan_notify(rtwdev, COEX_SCAN_START); + rtw_core_fw_scan_notify(rtwdev, true); set_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags); set_bit(RTW_FLAG_SCANNING, rtwdev->flags); @@ -624,6 +625,8 @@ static void rtw_ops_sw_scan_complete(struct ieee80211_hw *hw, clear_bit(RTW_FLAG_SCANNING, rtwdev->flags); clear_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags); + rtw_core_fw_scan_notify(rtwdev, false); + ether_addr_copy(rtwvif->mac_addr, vif->addr); config |= PORT_SET_MAC_ADDR; rtw_vif_port_config(rtwdev, rtwvif, config); diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index df115bb7fdf7..47f4838d0c58 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1185,6 +1185,22 @@ err: return ret; } +void rtw_core_fw_scan_notify(struct rtw_dev *rtwdev, bool start) +{ + if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_NOTIFY_SCAN)) + return; + + if (start) { + rtw_fw_scan_notify(rtwdev, true); + } else { + reinit_completion(&rtwdev->fw_scan_density); + rtw_fw_scan_notify(rtwdev, false); + if (!wait_for_completion_timeout(&rtwdev->fw_scan_density, + SCAN_NOTIFY_TIMEOUT)) + rtw_warn(rtwdev, "firmware failed to report density after scan\n"); + } +} + int rtw_core_start(struct rtw_dev *rtwdev) { int ret; @@ -1763,6 +1779,7 @@ int rtw_core_init(struct rtw_dev *rtwdev) init_waitqueue_head(&rtwdev->coex.wait); init_completion(&rtwdev->lps_leave_check); + init_completion(&rtwdev->fw_scan_density); rtwdev->sec.total_cam_num = 32; rtwdev->hal.current_channel = 1; diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 02ad175055cb..20b20a6db9cc 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -1620,6 +1620,8 @@ struct rtw_dm_info { struct rtw_iqk_info iqk; struct rtw_gapk_info gapk; bool is_bt_iqk_timeout; + + u8 scan_density; }; struct rtw_efuse { @@ -1869,6 +1871,7 @@ struct rtw_dev { struct rtw_wow_param wow; bool need_rfk; + struct completion fw_scan_density; /* hci related data, must be last */ u8 priv[] __aligned(sizeof(void *)); @@ -1974,6 +1977,7 @@ int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, void rtw_sta_remove(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, bool fw_exist); void rtw_fw_recovery(struct rtw_dev *rtwdev); +void rtw_core_fw_scan_notify(struct rtw_dev *rtwdev, bool start); int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size, const char *prefix_str); int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size, From 7b80f3e48c4b0ff85ff91945a2537d0bbc3e3cc4 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 28 May 2021 11:29:00 +0800 Subject: [PATCH 155/170] rtw88: dump FW crash via devcoredump Use device coredump framework instead of print_hex_dump to support FW crash dump. Pass data to the framework if preparing and dumping are successful. The framework will take the ownership of the data. The data will be freed after the framework determines its lifetime is over. A new coredump will not work if the previous one still exists. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210528032901.12927-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/debug.c | 7 + drivers/net/wireless/realtek/rtw88/main.c | 170 ++++++++++++------ drivers/net/wireless/realtek/rtw88/main.h | 37 +++- drivers/net/wireless/realtek/rtw88/rtw8822c.c | 51 +++++- 4 files changed, 201 insertions(+), 64 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c index 18ab472ea46c..dfd52cff5d02 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.c +++ b/drivers/net/wireless/realtek/rtw88/debug.c @@ -11,6 +11,7 @@ #include "debug.h" #include "phy.h" #include "reg.h" +#include "ps.h" #ifdef CONFIG_RTW88_DEBUGFS @@ -847,7 +848,13 @@ static ssize_t rtw_debugfs_set_fw_crash(struct file *filp, if (!input) return -EINVAL; + if (test_bit(RTW_FLAG_RESTARTING, rtwdev->flags)) + return -EINPROGRESS; + + mutex_lock(&rtwdev->mutex); + rtw_leave_lps_deep(rtwdev); rtw_write8(rtwdev, REG_HRCV_MSG, 1); + mutex_unlock(&rtwdev->mutex); return count; } diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 47f4838d0c58..4a9a8544e8ca 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -2,6 +2,8 @@ /* Copyright(c) 2018-2019 Realtek Corporation */ +#include + #include "main.h" #include "regd.h" #include "fw.h" @@ -320,59 +322,131 @@ void rtw_sta_remove(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, sta->addr, si->mac_id); } -static bool rtw_fw_dump_crash_log(struct rtw_dev *rtwdev) +struct rtw_fwcd_hdr { + u32 item; + u32 size; + u32 padding1; + u32 padding2; +} __packed; + +static int rtw_fwcd_prep(struct rtw_dev *rtwdev) +{ + struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc; + const struct rtw_fwcd_segs *segs = chip->fwcd_segs; + u32 prep_size = chip->fw_rxff_size + sizeof(struct rtw_fwcd_hdr); + u8 i; + + if (segs) { + prep_size += segs->num * sizeof(struct rtw_fwcd_hdr); + + for (i = 0; i < segs->num; i++) + prep_size += segs->segs[i]; + } + + desc->data = vmalloc(prep_size); + if (!desc->data) + return -ENOMEM; + + desc->size = prep_size; + desc->next = desc->data; + + return 0; +} + +static u8 *rtw_fwcd_next(struct rtw_dev *rtwdev, u32 item, u32 size) +{ + struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc; + struct rtw_fwcd_hdr *hdr; + u8 *next; + + if (!desc->data) { + rtw_dbg(rtwdev, RTW_DBG_FW, "fwcd isn't prepared successfully\n"); + return NULL; + } + + next = desc->next + sizeof(struct rtw_fwcd_hdr); + if (next - desc->data + size > desc->size) { + rtw_dbg(rtwdev, RTW_DBG_FW, "fwcd isn't prepared enough\n"); + return NULL; + } + + hdr = (struct rtw_fwcd_hdr *)(desc->next); + hdr->item = item; + hdr->size = size; + hdr->padding1 = 0x01234567; + hdr->padding2 = 0x89abcdef; + desc->next = next + size; + + return next; +} + +static void rtw_fwcd_dump(struct rtw_dev *rtwdev) +{ + struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc; + + rtw_dbg(rtwdev, RTW_DBG_FW, "dump fwcd\n"); + + /* Data will be freed after lifetime of device coredump. After calling + * dev_coredump, data is supposed to be handled by the device coredump + * framework. Note that a new dump will be discarded if a previous one + * hasn't been released yet. + */ + dev_coredumpv(rtwdev->dev, desc->data, desc->size, GFP_KERNEL); +} + +static void rtw_fwcd_free(struct rtw_dev *rtwdev, bool free_self) +{ + struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc; + + if (free_self) { + rtw_dbg(rtwdev, RTW_DBG_FW, "free fwcd by self\n"); + vfree(desc->data); + } + + desc->data = NULL; + desc->next = NULL; +} + +static int rtw_fw_dump_crash_log(struct rtw_dev *rtwdev) { u32 size = rtwdev->chip->fw_rxff_size; u32 *buf; u8 seq; - bool ret = true; - buf = vmalloc(size); + buf = (u32 *)rtw_fwcd_next(rtwdev, RTW_FWCD_TLV, size); if (!buf) - goto exit; + return -ENOMEM; if (rtw_fw_dump_fifo(rtwdev, RTW_FW_FIFO_SEL_RXBUF_FW, 0, size, buf)) { rtw_dbg(rtwdev, RTW_DBG_FW, "dump fw fifo fail\n"); - goto free_buf; + return -EINVAL; } if (GET_FW_DUMP_LEN(buf) == 0) { rtw_dbg(rtwdev, RTW_DBG_FW, "fw crash dump's length is 0\n"); - goto free_buf; + return -EINVAL; } seq = GET_FW_DUMP_SEQ(buf); - if (seq > 0 && seq != (rtwdev->fw.prev_dump_seq + 1)) { + if (seq > 0) { rtw_dbg(rtwdev, RTW_DBG_FW, "fw crash dump's seq is wrong: %d\n", seq); - goto free_buf; + return -EINVAL; } - print_hex_dump(KERN_ERR, "rtw88 fw dump: ", DUMP_PREFIX_OFFSET, 16, 1, - buf, size, true); - - if (GET_FW_DUMP_MORE(buf) == 1) { - rtwdev->fw.prev_dump_seq = seq; - ret = false; - } - -free_buf: - vfree(buf); -exit: - rtw_write8(rtwdev, REG_MCU_TST_CFG, 0); - - return ret; + return 0; } int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size, - const char *prefix_str) + u32 fwcd_item) { u32 rxff = rtwdev->chip->fw_rxff_size; u32 dump_size, done_size = 0; u8 *buf; int ret; - buf = vzalloc(size); + buf = rtw_fwcd_next(rtwdev, fwcd_item, size); if (!buf) return -ENOMEM; @@ -385,7 +459,7 @@ int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size, rtw_err(rtwdev, "ddma fw 0x%x [+0x%x] to fw fifo fail\n", ocp_src, done_size); - goto exit; + return ret; } ret = rtw_fw_dump_fifo(rtwdev, RTW_FW_FIFO_SEL_RXBUF_FW, 0, @@ -394,24 +468,18 @@ int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size, rtw_err(rtwdev, "dump fw 0x%x [+0x%x] from fw fifo fail\n", ocp_src, done_size); - goto exit; + return ret; } size -= dump_size; done_size += dump_size; } - print_hex_dump(KERN_ERR, prefix_str, DUMP_PREFIX_OFFSET, 16, 1, - buf, done_size, true); - -exit: - vfree(buf); - return ret; + return 0; } EXPORT_SYMBOL(rtw_dump_fw); -int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size, - const char *prefix_str) +int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size) { u8 *buf; u32 i; @@ -421,17 +489,13 @@ int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size, return -EINVAL; } - buf = vzalloc(size); + buf = rtw_fwcd_next(rtwdev, RTW_FWCD_REG, size); if (!buf) return -ENOMEM; for (i = 0; i < size; i += 4) *(u32 *)(buf + i) = rtw_read32(rtwdev, addr + i); - print_hex_dump(KERN_ERR, prefix_str, DUMP_PREFIX_OFFSET, 16, 4, buf, - size, true); - - vfree(buf); return 0; } EXPORT_SYMBOL(rtw_dump_reg); @@ -489,20 +553,24 @@ void rtw_fw_recovery(struct rtw_dev *rtwdev) static void __fw_recovery_work(struct rtw_dev *rtwdev) { - - /* rtw_fw_dump_crash_log() returns false indicates that there are - * still more log to dump. Driver set 0x1cf[7:0] = 0x1 to tell firmware - * to dump the remaining part of the log, and firmware will trigger an - * IMR_C2HCMD interrupt to inform driver the log is ready. - */ - if (!rtw_fw_dump_crash_log(rtwdev)) { - rtw_write8(rtwdev, REG_HRCV_MSG, 1); - return; - } - rtwdev->fw.prev_dump_seq = 0; + int ret = 0; set_bit(RTW_FLAG_RESTARTING, rtwdev->flags); - rtw_chip_dump_fw_crash(rtwdev); + + ret = rtw_fwcd_prep(rtwdev); + if (ret) + goto free; + ret = rtw_fw_dump_crash_log(rtwdev); + if (ret) + goto free; + ret = rtw_chip_dump_fw_crash(rtwdev); + if (ret) + goto free; + + rtw_fwcd_dump(rtwdev); +free: + rtw_fwcd_free(rtwdev, !!ret); + rtw_write8(rtwdev, REG_MCU_TST_CFG, 0); WARN(1, "firmware crash, start reset and recover\n"); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 20b20a6db9cc..e5af375b3dd0 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -806,7 +806,7 @@ struct rtw_regulatory { struct rtw_chip_ops { int (*mac_init)(struct rtw_dev *rtwdev); - void (*dump_fw_crash)(struct rtw_dev *rtwdev); + int (*dump_fw_crash)(struct rtw_dev *rtwdev); void (*shutdown)(struct rtw_dev *rtwdev); int (*read_efuse)(struct rtw_dev *rtwdev, u8 *map); void (*phy_set_param)(struct rtw_dev *rtwdev); @@ -1112,6 +1112,15 @@ enum rtw_fw_fifo_sel { RTW_FW_FIFO_MAX, }; +enum rtw_fwcd_item { + RTW_FWCD_TLV, + RTW_FWCD_REG, + RTW_FWCD_ROM, + RTW_FWCD_IMEM, + RTW_FWCD_DMEM, + RTW_FWCD_EMEM, +}; + /* hardware configuration for each IC */ struct rtw_chip_info { struct rtw_chip_ops *ops; @@ -1140,6 +1149,8 @@ struct rtw_chip_info { u8 max_power_index; u16 fw_fifo_addr[RTW_FW_FIFO_MAX]; + const struct rtw_fwcd_segs *fwcd_segs; + u8 default_1ss_tx_path; bool path_div_supported; @@ -1725,6 +1736,17 @@ struct rtw_fifo_conf { const struct rtw_rqpn *rqpn; }; +struct rtw_fwcd_desc { + u32 size; + u8 *next; + u8 *data; +}; + +struct rtw_fwcd_segs { + const u32 *segs; + u8 num; +}; + #define FW_CD_TYPE 0xffff #define FW_CD_LEN 4 #define FW_CD_VAL 0xaabbccdd @@ -1732,11 +1754,11 @@ struct rtw_fw_state { const struct firmware *firmware; struct rtw_dev *rtwdev; struct completion completion; + struct rtw_fwcd_desc fwcd_desc; u16 version; u8 sub_version; u8 sub_index; u16 h2c_version; - u8 prev_dump_seq; u32 feature; }; @@ -1942,10 +1964,12 @@ static inline void rtw_release_macid(struct rtw_dev *rtwdev, u8 mac_id) clear_bit(mac_id, rtwdev->mac_id_map); } -static inline void rtw_chip_dump_fw_crash(struct rtw_dev *rtwdev) +static inline int rtw_chip_dump_fw_crash(struct rtw_dev *rtwdev) { if (rtwdev->chip->ops->dump_fw_crash) - rtwdev->chip->ops->dump_fw_crash(rtwdev); + return rtwdev->chip->ops->dump_fw_crash(rtwdev); + + return 0; } void rtw_get_channel_params(struct cfg80211_chan_def *chandef, @@ -1979,8 +2003,7 @@ void rtw_sta_remove(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, void rtw_fw_recovery(struct rtw_dev *rtwdev); void rtw_core_fw_scan_notify(struct rtw_dev *rtwdev, bool start); int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size, - const char *prefix_str); -int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size, - const char *prefix_str); + u32 fwcd_item); +int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size); #endif diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 1a6721611dc1..8bf3cd3a3678 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -2109,13 +2109,51 @@ static int rtw8822c_mac_init(struct rtw_dev *rtwdev) return 0; } -static void rtw8822c_dump_fw_crash(struct rtw_dev *rtwdev) +#define FWCD_SIZE_REG_8822C 0x2000 +#define FWCD_SIZE_DMEM_8822C 0x10000 +#define FWCD_SIZE_IMEM_8822C 0x10000 +#define FWCD_SIZE_EMEM_8822C 0x20000 +#define FWCD_SIZE_ROM_8822C 0x10000 + +static const u32 __fwcd_segs_8822c[] = { + FWCD_SIZE_REG_8822C, + FWCD_SIZE_DMEM_8822C, + FWCD_SIZE_IMEM_8822C, + FWCD_SIZE_EMEM_8822C, + FWCD_SIZE_ROM_8822C, +}; + +static const struct rtw_fwcd_segs rtw8822c_fwcd_segs = { + .segs = __fwcd_segs_8822c, + .num = ARRAY_SIZE(__fwcd_segs_8822c), +}; + +static int rtw8822c_dump_fw_crash(struct rtw_dev *rtwdev) { - rtw_dump_reg(rtwdev, 0x0, 0x2000, "rtw8822c reg_"); - rtw_dump_fw(rtwdev, OCPBASE_DMEM_88XX, 0x10000, "rtw8822c DMEM_"); - rtw_dump_fw(rtwdev, OCPBASE_IMEM_88XX, 0x10000, "rtw8822c IMEM_"); - rtw_dump_fw(rtwdev, OCPBASE_EMEM_88XX, 0x20000, "rtw8822c EMEM_"); - rtw_dump_fw(rtwdev, OCPBASE_ROM_88XX, 0x10000, "rtw8822c ROM_"); +#define __dump_fw_8822c(_dev, _mem) \ + rtw_dump_fw(_dev, OCPBASE_ ## _mem ## _88XX, \ + FWCD_SIZE_ ## _mem ## _8822C, RTW_FWCD_ ## _mem) + int ret; + + ret = rtw_dump_reg(rtwdev, 0x0, FWCD_SIZE_REG_8822C); + if (ret) + return ret; + ret = __dump_fw_8822c(rtwdev, DMEM); + if (ret) + return ret; + ret = __dump_fw_8822c(rtwdev, IMEM); + if (ret) + return ret; + ret = __dump_fw_8822c(rtwdev, EMEM); + if (ret) + return ret; + ret = __dump_fw_8822c(rtwdev, ROM); + if (ret) + return ret; + + return 0; + +#undef __dump_fw_8822c } static void rtw8822c_rstb_3wire(struct rtw_dev *rtwdev, bool enable) @@ -5287,6 +5325,7 @@ struct rtw_chip_info rtw8822c_hw_spec = { .coex_info_hw_regs = coex_info_hw_regs_8822c, .fw_fifo_addr = {0x780, 0x700, 0x780, 0x660, 0x650, 0x680}, + .fwcd_segs = &rtw8822c_fwcd_segs, }; EXPORT_SYMBOL(rtw8822c_hw_spec); From ae04f15b1a83e813f5c270f44692766dc3c5a6ce Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 28 May 2021 11:29:01 +0800 Subject: [PATCH 156/170] rtw88: refine unwanted h2c command Don't send beacon filter h2c when there is no valid context. Return early instead of printing out warning messages, so others won't get confused. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210528032901.12927-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/fw.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 58f4e47aa96a..176e8b67530e 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -601,7 +601,7 @@ void rtw_fw_beacon_filter_config(struct rtw_dev *rtwdev, bool connect, s32 threshold = bss_conf->cqm_rssi_thold + rssi_offset; u8 h2c_pkt[H2C_PKT_SIZE] = {0}; - if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_BCN_FILTER)) + if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_BCN_FILTER) || !si) return; if (!connect) { @@ -623,10 +623,7 @@ void rtw_fw_beacon_filter_config(struct rtw_dev *rtwdev, bool connect, BCN_FILTER_OFFLOAD_MODE_DEFAULT); SET_BCN_FILTER_OFFLOAD_P1_THRESHOLD(h2c_pkt, (u8)threshold); SET_BCN_FILTER_OFFLOAD_P1_BCN_LOSS_CNT(h2c_pkt, BCN_LOSS_CNT); - if (si) - SET_BCN_FILTER_OFFLOAD_P1_MACID(h2c_pkt, si->mac_id); - else - rtw_warn(rtwdev, "CQM config with station not found\n"); + SET_BCN_FILTER_OFFLOAD_P1_MACID(h2c_pkt, si->mac_id); SET_BCN_FILTER_OFFLOAD_P1_HYST(h2c_pkt, bss_conf->cqm_rssi_hyst); SET_BCN_FILTER_OFFLOAD_P1_BCN_INTERVAL(h2c_pkt, bss_conf->beacon_int); rtw_fw_send_h2c_command(rtwdev, h2c_pkt); From 956c6d4f20c5446727e0c912dd8f527f2dc7b779 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 7 Jun 2021 09:22:54 +0800 Subject: [PATCH 157/170] rtw88: add quirks to disable pci capabilities 8821CE with ASPM cannot work properly on Protempo Ltd L116HTN6SPW. Add a quirk to disable the cap. The reporter describes the symptom is that this module (driver) causes frequent freezes, randomly but usually within a few minutes of running (thus very soon after boot): screen display remains frozen, no response to either keyboard or mouse input. All I can do is to hold the power button to power off, then reboot. Reported-by: Paul Szabo Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210607012254.6306-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/pci.c | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index f59a4c462e3b..e7d17ab8f113 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -2,6 +2,7 @@ /* Copyright(c) 2018-2019 Realtek Corporation */ +#include #include #include #include "main.h" @@ -1673,6 +1674,36 @@ static void rtw_pci_napi_deinit(struct rtw_dev *rtwdev) netif_napi_del(&rtwpci->napi); } +enum rtw88_quirk_dis_pci_caps { + QUIRK_DIS_PCI_CAP_MSI, + QUIRK_DIS_PCI_CAP_ASPM, +}; + +static int disable_pci_caps(const struct dmi_system_id *dmi) +{ + uintptr_t dis_caps = (uintptr_t)dmi->driver_data; + + if (dis_caps & BIT(QUIRK_DIS_PCI_CAP_MSI)) + rtw_disable_msi = true; + if (dis_caps & BIT(QUIRK_DIS_PCI_CAP_ASPM)) + rtw_pci_disable_aspm = true; + + return 1; +} + +static const struct dmi_system_id rtw88_pci_quirks[] = { + { + .callback = disable_pci_caps, + .ident = "Protempo Ltd L116HTN6SPW", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Protempo Ltd"), + DMI_MATCH(DMI_PRODUCT_NAME, "L116HTN6SPW"), + }, + .driver_data = (void *)BIT(QUIRK_DIS_PCI_CAP_ASPM), + }, + {} +}; + int rtw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -1723,6 +1754,7 @@ int rtw_pci_probe(struct pci_dev *pdev, goto err_destroy_pci; } + dmi_check_system(rtw88_pci_quirks); rtw_pci_phy_cfg(rtwdev); ret = rtw_register_hw(rtwdev, hw); From b38678a73c4d8a3616ca14713154e062b4c4db63 Mon Sep 17 00:00:00 2001 From: wengjianfeng Date: Thu, 20 May 2021 08:55:45 +0800 Subject: [PATCH 158/170] rtw88: coex: remove unnecessary variable and label In some funciton, the variable ret just used as return value,and out label just return ret,so ret and out label are unnecessary, we should delete these and use return true/false to replace. Signed-off-by: wengjianfeng Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210520005545.31272-1-samirweng1979@163.com --- drivers/net/wireless/realtek/rtw88/coex.c | 40 ++++++----------------- 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c index cedbf3825848..103e87745be6 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.c +++ b/drivers/net/wireless/realtek/rtw88/coex.c @@ -630,20 +630,16 @@ static bool rtw_coex_get_bt_scan_type(struct rtw_dev *rtwdev, u8 *scan_type) struct rtw_coex_info_req req = {0}; struct sk_buff *skb; u8 *payload; - bool ret = false; req.op_code = BT_MP_INFO_OP_SCAN_TYPE; skb = rtw_coex_info_request(rtwdev, &req); if (!skb) - goto out; + return false; payload = get_payload_from_coex_resp(skb); *scan_type = GET_COEX_RESP_BT_SCAN_TYPE(payload); dev_kfree_skb_any(skb); - ret = true; - -out: - return ret; + return true; } static bool rtw_coex_set_lna_constrain_level(struct rtw_dev *rtwdev, @@ -651,19 +647,15 @@ static bool rtw_coex_set_lna_constrain_level(struct rtw_dev *rtwdev, { struct rtw_coex_info_req req = {0}; struct sk_buff *skb; - bool ret = false; req.op_code = BT_MP_INFO_OP_LNA_CONSTRAINT; req.para1 = lna_constrain_level; skb = rtw_coex_info_request(rtwdev, &req); if (!skb) - goto out; + return false; dev_kfree_skb_any(skb); - ret = true; - -out: - return ret; + return true; } #define case_BTSTATUS(src) \ @@ -3533,19 +3525,15 @@ static bool rtw_coex_get_bt_patch_version(struct rtw_dev *rtwdev, struct rtw_coex_info_req req = {0}; struct sk_buff *skb; u8 *payload; - bool ret = false; req.op_code = BT_MP_INFO_OP_PATCH_VER; skb = rtw_coex_info_request(rtwdev, &req); if (!skb) - goto out; + return false; payload = get_payload_from_coex_resp(skb); *patch_version = GET_COEX_RESP_BT_PATCH_VER(payload); - ret = true; - -out: - return ret; + return true; } static bool rtw_coex_get_bt_supported_version(struct rtw_dev *rtwdev, @@ -3554,19 +3542,15 @@ static bool rtw_coex_get_bt_supported_version(struct rtw_dev *rtwdev, struct rtw_coex_info_req req = {0}; struct sk_buff *skb; u8 *payload; - bool ret = false; req.op_code = BT_MP_INFO_OP_SUPP_VER; skb = rtw_coex_info_request(rtwdev, &req); if (!skb) - goto out; + return false; payload = get_payload_from_coex_resp(skb); *supported_version = GET_COEX_RESP_BT_SUPP_VER(payload); - ret = true; - -out: - return ret; + return true; } static bool rtw_coex_get_bt_supported_feature(struct rtw_dev *rtwdev, @@ -3575,19 +3559,15 @@ static bool rtw_coex_get_bt_supported_feature(struct rtw_dev *rtwdev, struct rtw_coex_info_req req = {0}; struct sk_buff *skb; u8 *payload; - bool ret = false; req.op_code = BT_MP_INFO_OP_SUPP_FEAT; skb = rtw_coex_info_request(rtwdev, &req); if (!skb) - goto out; + return false; payload = get_payload_from_coex_resp(skb); *supported_feature = GET_COEX_RESP_BT_SUPP_FEAT(payload); - ret = true; - -out: - return ret; + return true; } struct rtw_coex_sta_stat_iter_data { From 70ca8441ebfc4412dc9d3c56409e73dba959ab34 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 16 Jun 2021 13:39:51 -0700 Subject: [PATCH 159/170] orinoco: Avoid field-overflowing memcpy() In preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring array fields. Validate the expected key size and introduce a wrapping structure to use as the multi-field memcpy() destination so that overflows can be correctly detected. Signed-off-by: Kees Cook Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210616203952.1248910-1-keescook@chromium.org --- drivers/net/wireless/intersil/orinoco/hw.c | 18 +++++++++++------- drivers/net/wireless/intersil/orinoco/hw.h | 5 +++-- drivers/net/wireless/intersil/orinoco/wext.c | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/intersil/orinoco/hw.c b/drivers/net/wireless/intersil/orinoco/hw.c index 2c7adb4be100..0aea35c9c11c 100644 --- a/drivers/net/wireless/intersil/orinoco/hw.c +++ b/drivers/net/wireless/intersil/orinoco/hw.c @@ -988,15 +988,18 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) * tsc must be NULL or up to 8 bytes */ int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, - int set_tx, const u8 *key, const u8 *rsc, - size_t rsc_len, const u8 *tsc, size_t tsc_len) + int set_tx, const u8 *key, size_t key_len, + const u8 *rsc, size_t rsc_len, + const u8 *tsc, size_t tsc_len) { struct { __le16 idx; u8 rsc[ORINOCO_SEQ_LEN]; - u8 key[TKIP_KEYLEN]; - u8 tx_mic[MIC_KEYLEN]; - u8 rx_mic[MIC_KEYLEN]; + struct { + u8 key[TKIP_KEYLEN]; + u8 tx_mic[MIC_KEYLEN]; + u8 rx_mic[MIC_KEYLEN]; + } tkip; u8 tsc[ORINOCO_SEQ_LEN]; } __packed buf; struct hermes *hw = &priv->hw; @@ -1011,8 +1014,9 @@ int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, key_idx |= 0x8000; buf.idx = cpu_to_le16(key_idx); - memcpy(buf.key, key, - sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic)); + if (key_len != sizeof(buf.tkip)) + return -EINVAL; + memcpy(&buf.tkip, key, sizeof(buf.tkip)); if (rsc_len > sizeof(buf.rsc)) rsc_len = sizeof(buf.rsc); diff --git a/drivers/net/wireless/intersil/orinoco/hw.h b/drivers/net/wireless/intersil/orinoco/hw.h index 466d1ede76f1..da5804dbdf34 100644 --- a/drivers/net/wireless/intersil/orinoco/hw.h +++ b/drivers/net/wireless/intersil/orinoco/hw.h @@ -38,8 +38,9 @@ int __orinoco_hw_set_wap(struct orinoco_private *priv); int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv); int __orinoco_hw_setup_enc(struct orinoco_private *priv); int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, - int set_tx, const u8 *key, const u8 *rsc, - size_t rsc_len, const u8 *tsc, size_t tsc_len); + int set_tx, const u8 *key, size_t key_len, + const u8 *rsc, size_t rsc_len, + const u8 *tsc, size_t tsc_len); int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx); int __orinoco_hw_set_multicast_list(struct orinoco_private *priv, struct net_device *dev, diff --git a/drivers/net/wireless/intersil/orinoco/wext.c b/drivers/net/wireless/intersil/orinoco/wext.c index 7b6c4ae8ddb3..4a01260027bc 100644 --- a/drivers/net/wireless/intersil/orinoco/wext.c +++ b/drivers/net/wireless/intersil/orinoco/wext.c @@ -791,7 +791,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, err = __orinoco_hw_set_tkip_key(priv, idx, ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, - priv->keys[idx].key, + priv->keys[idx].key, priv->keys[idx].key_len, tkip_iv, ORINOCO_SEQ_LEN, NULL, 0); if (err) printk(KERN_ERR "%s: Error %d setting TKIP key" From 3f26f7665c5ddc880444e3daaecb3a46794ba3a4 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 16 Jun 2021 21:14:31 -0700 Subject: [PATCH 160/170] mwl8k: Avoid memcpy() over-reading of mcs.rx_mask In preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally reading across neighboring array fields. Use the sub-structure address directly. Signed-off-by: Kees Cook Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210617041431.2168953-1-keescook@chromium.org --- drivers/net/wireless/marvell/mwl8k.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c index 84b32a5f01ee..3bf6571f4149 100644 --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c @@ -4552,7 +4552,7 @@ static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw, else rates = sta->supp_rates[NL80211_BAND_5GHZ] << 5; legacy_rate_mask_to_array(p->legacy_rates, rates); - memcpy(p->ht_rates, sta->ht_cap.mcs.rx_mask, 16); + memcpy(p->ht_rates, &sta->ht_cap.mcs, 16); p->interop = 1; p->amsdu_enabled = 0; @@ -5034,7 +5034,7 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ap_legacy_rates = ap->supp_rates[NL80211_BAND_5GHZ] << 5; } - memcpy(ap_mcs_rates, ap->ht_cap.mcs.rx_mask, 16); + memcpy(ap_mcs_rates, &ap->ht_cap.mcs, 16); rcu_read_unlock(); From 0d5e743db480642818401fb34bbc3f0da28abdfb Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 17 Jun 2021 10:13:17 -0700 Subject: [PATCH 161/170] rtlwifi: rtl8192de: Fully initialize curvecount_val In preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring array fields. The size argument to memset() is bytes, but the array element size of curvecount_val is u32, so "CV_CURVE_CNT * 2" was only 1/4th of the contents of curvecount_val. Adjust memset() to wipe full buffer size. Signed-off-by: Kees Cook Reviewed-by: Larry Finger Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210617171317.3410722-1-keescook@chromium.org --- drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c index 68ec009ea157..76dd881ef9bb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c @@ -2574,7 +2574,7 @@ static void _rtl92d_phy_lc_calibrate_sw(struct ieee80211_hw *hw, bool is2t) RTPRINT(rtlpriv, FINIT, INIT_IQK, "path-B / 2.4G LCK\n"); } - memset(&curvecount_val[0], 0, CV_CURVE_CNT * 2); + memset(curvecount_val, 0, sizeof(curvecount_val)); /* Set LC calibration off */ rtl_set_rfreg(hw, (enum radio_path)index, RF_CHNLBW, 0x08000, 0x0); From 59c668d700be72bdf76932f5a7db0af947ee0539 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 17 Jun 2021 10:15:22 -0700 Subject: [PATCH 162/170] mwifiex: Avoid memset() over-write of WEP key_material In preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring array fields. When preparing to call mwifiex_set_keyparamset_wep(), key_material is treated very differently from its structure layout (which has only a single struct mwifiex_ie_type_key_param_set). Instead, add a new type to the union so memset() can correctly reason about the size of the structure. Note that the union ("params", 196 bytes) containing key_material was not large enough to hold the target of this memset(): sizeof(struct mwifiex_ie_type_key_param_set) == 60, NUM_WEP_KEYS = 4, so 240 bytes, or 44 bytes past the end of "params". The good news is that it appears that the command buffer, as allocated, is 2048 bytes (MWIFIEX_SIZE_OF_CMD_BUFFER), so no neighboring memory appears to be getting clobbered. Signed-off-by: Kees Cook Reviewed-by: Brian Norris Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210617171522.3410951-1-keescook@chromium.org --- drivers/net/wireless/marvell/mwifiex/fw.h | 6 ++++++ drivers/net/wireless/marvell/mwifiex/sta_cmd.c | 11 ++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index 470d669c7f14..2ff23ab259ab 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -995,6 +995,11 @@ struct host_cmd_ds_802_11_key_material { struct mwifiex_ie_type_key_param_set key_param_set; } __packed; +struct host_cmd_ds_802_11_key_material_wep { + __le16 action; + struct mwifiex_ie_type_key_param_set key_param_set[NUM_WEP_KEYS]; +} __packed; + struct host_cmd_ds_gen { __le16 command; __le16 size; @@ -2347,6 +2352,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_wmm_get_status get_wmm_status; struct host_cmd_ds_802_11_key_material key_material; struct host_cmd_ds_802_11_key_material_v2 key_material_v2; + struct host_cmd_ds_802_11_key_material_wep key_material_wep; struct host_cmd_ds_version_ext verext; struct host_cmd_ds_mgmt_frame_reg reg_mask; struct host_cmd_ds_remain_on_chan roc_cfg; diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c index d3a968ef21ef..48ea00da1fc9 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c @@ -840,14 +840,15 @@ mwifiex_cmd_802_11_key_material_v1(struct mwifiex_private *priv, } if (!enc_key) { - memset(&key_material->key_param_set, 0, - (NUM_WEP_KEYS * - sizeof(struct mwifiex_ie_type_key_param_set))); + struct host_cmd_ds_802_11_key_material_wep *key_material_wep = + (struct host_cmd_ds_802_11_key_material_wep *)key_material; + memset(key_material_wep->key_param_set, 0, + sizeof(key_material_wep->key_param_set)); ret = mwifiex_set_keyparamset_wep(priv, - &key_material->key_param_set, + &key_material_wep->key_param_set[0], &key_param_len); cmd->size = cpu_to_le16(key_param_len + - sizeof(key_material->action) + S_DS_GEN); + sizeof(key_material_wep->action) + S_DS_GEN); return ret; } else memset(&key_material->key_param_set, 0, From 829eea7c94e0bac804e65975639a2f2e5f147033 Mon Sep 17 00:00:00 2001 From: Wei Mingzhi Date: Sat, 19 Jun 2021 00:08:40 +0800 Subject: [PATCH 163/170] mt7601u: add USB device ID for some versions of XiaoDu WiFi Dongle. USB device ID of some versions of XiaoDu WiFi Dongle is 2955:1003 instead of 2955:1001. Both are the same mt7601u hardware. Signed-off-by: Wei Mingzhi Acked-by: Jakub Kicinski Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210618160840.305024-1-whistler@member.fsf.org --- drivers/net/wireless/mediatek/mt7601u/usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.c b/drivers/net/wireless/mediatek/mt7601u/usb.c index 6bcc4a13ae6c..cc772045d526 100644 --- a/drivers/net/wireless/mediatek/mt7601u/usb.c +++ b/drivers/net/wireless/mediatek/mt7601u/usb.c @@ -26,6 +26,7 @@ static const struct usb_device_id mt7601u_device_table[] = { { USB_DEVICE(0x2717, 0x4106) }, { USB_DEVICE(0x2955, 0x0001) }, { USB_DEVICE(0x2955, 0x1001) }, + { USB_DEVICE(0x2955, 0x1003) }, { USB_DEVICE(0x2a5f, 0x1000) }, { USB_DEVICE(0x7392, 0x7710) }, { 0, } From c8bcd82a4efd053cdd5ce515a8b0003011a5f756 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 16 Jun 2021 12:54:10 -0700 Subject: [PATCH 164/170] ath11k: Avoid memcpy() over-reading of he_cap In preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memcpy(), memmove(), and memset(), avoid intentionally writing across neighboring array fields. Since peer_he_cap_{mac,phy}info and he_cap_elem.{mac,phy}_cap_info are not the same sizes, memcpy() was reading beyond field boundaries. Instead, correctly cap the copy length and pad out any difference in size (peer_he_cap_macinfo is 8 bytes whereas mac_cap_info is 6, and peer_he_cap_phyinfo is 12 bytes whereas phy_cap_info is 11). Signed-off-by: Kees Cook Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210616195410.1232119-1-keescook@chromium.org --- drivers/net/wireless/ath/ath11k/mac.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index eb52332dbe3f..e9b3689331ec 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1314,10 +1314,16 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, arg->he_flag = true; - memcpy(&arg->peer_he_cap_macinfo, he_cap->he_cap_elem.mac_cap_info, - sizeof(arg->peer_he_cap_macinfo)); - memcpy(&arg->peer_he_cap_phyinfo, he_cap->he_cap_elem.phy_cap_info, - sizeof(arg->peer_he_cap_phyinfo)); + memcpy_and_pad(&arg->peer_he_cap_macinfo, + sizeof(arg->peer_he_cap_macinfo), + he_cap->he_cap_elem.mac_cap_info, + sizeof(he_cap->he_cap_elem.mac_cap_info), + 0); + memcpy_and_pad(&arg->peer_he_cap_phyinfo, + sizeof(arg->peer_he_cap_phyinfo), + he_cap->he_cap_elem.phy_cap_info, + sizeof(he_cap->he_cap_elem.phy_cap_info), + 0); arg->peer_he_ops = vif->bss_conf.he_oper.params; /* the top most byte is used to indicate BSS color info */ From d3a1a18ab034fcbec575d10f016b4ae02358cbde Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 17 Jun 2021 10:10:58 -0700 Subject: [PATCH 165/170] wcn36xx: Avoid memset() beyond end of struct field In preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring array fields. Instead of writing past the end of the header to reach the rest of the body, replace the redundant function with existing macro to wipe struct contents and set field values. Additionally adjusts macro to add missing parens. Signed-off-by: Kees Cook Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210617171058.3410494-1-keescook@chromium.org --- drivers/net/wireless/ath/wcn36xx/smd.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index cf8e52cbdd9b..0e3be17d8cea 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -445,22 +445,12 @@ out: return ret; } -static void init_hal_msg(struct wcn36xx_hal_msg_header *hdr, - enum wcn36xx_hal_host_msg_type msg_type, - size_t msg_size) -{ - memset(hdr, 0, msg_size + sizeof(*hdr)); - hdr->msg_type = msg_type; - hdr->msg_version = WCN36XX_HAL_MSG_VERSION0; - hdr->len = msg_size + sizeof(*hdr); -} - #define __INIT_HAL_MSG(msg_body, type, version) \ do { \ - memset(&msg_body, 0, sizeof(msg_body)); \ - msg_body.header.msg_type = type; \ - msg_body.header.msg_version = version; \ - msg_body.header.len = sizeof(msg_body); \ + memset(&(msg_body), 0, sizeof(msg_body)); \ + (msg_body).header.msg_type = type; \ + (msg_body).header.msg_version = version; \ + (msg_body).header.len = sizeof(msg_body); \ } while (0) \ #define INIT_HAL_MSG(msg_body, type) \ @@ -2729,8 +2719,7 @@ int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn, msg_body = (struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg *) wcn->hal_buf; - init_hal_msg(&msg_body->header, WCN36XX_HAL_8023_MULTICAST_LIST_REQ, - sizeof(msg_body->mc_addr_list)); + INIT_HAL_MSG(*msg_body, WCN36XX_HAL_8023_MULTICAST_LIST_REQ); /* An empty list means all mc traffic will be received */ if (fp) From 761025b51c540ae1fc9516b5dafa55cd109e4871 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 May 2021 00:15:48 +0300 Subject: [PATCH 166/170] cfg80211: Add wiphy_info_once() Add wiphy_info_once() helper that prints info message only once. Signed-off-by: Dmitry Osipenko Acked-by: Johannes Berg Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210511211549.30571-1-digetx@gmail.com --- include/net/cfg80211.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 58c2cd417e89..1e0bf249b601 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -8154,6 +8154,8 @@ bool cfg80211_iftype_allowed(struct wiphy *wiphy, enum nl80211_iftype iftype, dev_notice(&(wiphy)->dev, format, ##args) #define wiphy_info(wiphy, format, args...) \ dev_info(&(wiphy)->dev, format, ##args) +#define wiphy_info_once(wiphy, format, args...) \ + dev_info_once(&(wiphy)->dev, format, ##args) #define wiphy_err_ratelimited(wiphy, format, args...) \ dev_err_ratelimited(&(wiphy)->dev, format, ##args) From 78f0a64f66d4f582987bbe45433374b61c21500f Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 May 2021 00:15:49 +0300 Subject: [PATCH 167/170] brcmfmac: Silence error messages about unsupported firmware features KMSG is flooded with error messages about unsupported firmware features of BCM4329 chip. The GET_ASSOCLIST error became especially noisy with a newer NetworkManager version of Ubuntu 21.04. Turn the noisy error messages into info messages and print them out only once. Signed-off-by: Dmitry Osipenko Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210511211549.30571-2-digetx@gmail.com --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 16 +++++++++++++--- .../wireless/broadcom/brcm80211/brcmfmac/core.c | 11 ++++++++--- .../wireless/broadcom/brcm80211/brcmfmac/debug.h | 4 ++++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 65fb038d88e7..cedba56fc448 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -2895,8 +2895,13 @@ brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev, &cfg->assoclist, sizeof(cfg->assoclist)); if (err) { - bphy_err(drvr, "BRCMF_C_GET_ASSOCLIST unsupported, err=%d\n", - err); + /* GET_ASSOCLIST unsupported by firmware of older chips */ + if (err == -EBADE) + bphy_info_once(drvr, "BRCMF_C_GET_ASSOCLIST unsupported\n"); + else + bphy_err(drvr, "BRCMF_C_GET_ASSOCLIST failed, err=%d\n", + err); + cfg->assoclist.count = 0; return -EOPNOTSUPP; } @@ -6851,7 +6856,12 @@ static int brcmf_setup_wiphybands(struct brcmf_cfg80211_info *cfg) err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain); if (err) { - bphy_err(drvr, "rxchain error (%d)\n", err); + /* rxchain unsupported by firmware of older chips */ + if (err == -EBADE) + bphy_info_once(drvr, "rxchain unsupported\n"); + else + bphy_err(drvr, "rxchain error (%d)\n", err); + nchain = 1; } else { for (nchain = 0; rxchain; nchain++) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index cee1682d2333..db5f8535fdb5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -188,9 +188,14 @@ static void _brcmf_set_multicast_list(struct work_struct *work) /*Finally, pick up the PROMISC flag */ cmd_value = (ndev->flags & IFF_PROMISC) ? true : false; err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PROMISC, cmd_value); - if (err < 0) - bphy_err(drvr, "Setting BRCMF_C_SET_PROMISC failed, %d\n", - err); + if (err < 0) { + /* PROMISC unsupported by firmware of older chips */ + if (err == -EBADE) + bphy_info_once(drvr, "BRCMF_C_SET_PROMISC unsupported\n"); + else + bphy_err(drvr, "Setting BRCMF_C_SET_PROMISC failed, err=%d\n", + err); + } brcmf_configure_arp_nd_offload(ifp, !cmd_value); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h index 44ba6f389fa9..9bb5f709d41a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h @@ -60,6 +60,10 @@ void __brcmf_err(struct brcmf_bus *bus, const char *func, const char *fmt, ...); ##__VA_ARGS__); \ } while (0) +#define bphy_info_once(drvr, fmt, ...) \ + wiphy_info_once((drvr)->wiphy, "%s: " fmt, __func__, \ + ##__VA_ARGS__) + #if defined(DEBUG) || defined(CONFIG_BRCM_TRACING) /* For debug/tracing purposes treat info messages as errors */ From 1a3ac5c651a0c859bdea64ed964fc93c2ba980d3 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 17 Apr 2021 15:54:28 +0800 Subject: [PATCH 168/170] brcmfmac: support parse country code map from DT With any regulatory domain requests coming from either user space or 802.11 IE (Information Element), the country is coded in ISO3166 standard. It needs to be translated to firmware country code and revision with the mapping info in settings->country_codes table. Support populate country_codes table by parsing the mapping from DT. The BRCMF_BUSTYPE_SDIO bus_type check gets separated from general DT validation, so that country code can be handled as general part rather than SDIO bus specific one. Signed-off-by: Shawn Guo Reviewed-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210417075428.2671-1-shawn.guo@linaro.org --- .../wireless/broadcom/brcm80211/brcmfmac/of.c | 57 ++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c index a7554265f95f..2f7bc3a70c65 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c @@ -12,12 +12,59 @@ #include "common.h" #include "of.h" +static int brcmf_of_get_country_codes(struct device *dev, + struct brcmf_mp_device *settings) +{ + struct device_node *np = dev->of_node; + struct brcmfmac_pd_cc_entry *cce; + struct brcmfmac_pd_cc *cc; + int count; + int i; + + count = of_property_count_strings(np, "brcm,ccode-map"); + if (count < 0) { + /* The property is optional, so return success if it doesn't + * exist. Otherwise propagate the error code. + */ + return (count == -EINVAL) ? 0 : count; + } + + cc = devm_kzalloc(dev, sizeof(*cc) + count * sizeof(*cce), GFP_KERNEL); + if (!cc) + return -ENOMEM; + + cc->table_size = count; + + for (i = 0; i < count; i++) { + const char *map; + + cce = &cc->table[i]; + + if (of_property_read_string_index(np, "brcm,ccode-map", + i, &map)) + continue; + + /* String format e.g. US-Q2-86 */ + if (sscanf(map, "%2c-%2c-%d", cce->iso3166, cce->cc, + &cce->rev) != 3) + brcmf_err("failed to read country map %s\n", map); + else + brcmf_dbg(INFO, "%s-%s-%d\n", cce->iso3166, cce->cc, + cce->rev); + } + + settings->country_codes = cc; + + return 0; +} + void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, struct brcmf_mp_device *settings) { struct brcmfmac_sdio_pd *sdio = &settings->bus.sdio; struct device_node *root, *np = dev->of_node; int irq; + int err; u32 irqf; u32 val; @@ -43,8 +90,14 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, of_node_put(root); } - if (!np || bus_type != BRCMF_BUSTYPE_SDIO || - !of_device_is_compatible(np, "brcm,bcm4329-fmac")) + if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac")) + return; + + err = brcmf_of_get_country_codes(dev, settings); + if (err) + brcmf_err("failed to get OF country code map (err=%d)\n", err); + + if (bus_type != BRCMF_BUSTYPE_SDIO) return; if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0) From 1d8820d5462dcdd34f3eb7ef4893536c439e476d Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Thu, 24 Jun 2021 10:34:59 +0800 Subject: [PATCH 169/170] rtw88: fix c2h memory leak Fix erroneous code that leads to unreferenced objects. During H2C operations, some functions returned without freeing the memory that only the function have access to. Release these objects when they're no longer needed to avoid potentially memory leaks. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210624023459.10294-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/coex.c | 11 ++++++++++- drivers/net/wireless/realtek/rtw88/fw.c | 2 ++ drivers/net/wireless/realtek/rtw88/main.c | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c index 103e87745be6..2551e228b581 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.c +++ b/drivers/net/wireless/realtek/rtw88/coex.c @@ -591,8 +591,10 @@ void rtw_coex_info_response(struct rtw_dev *rtwdev, struct sk_buff *skb) struct rtw_coex *coex = &rtwdev->coex; u8 *payload = get_payload_from_coex_resp(skb); - if (payload[0] != COEX_RESP_ACK_BY_WL_FW) + if (payload[0] != COEX_RESP_ACK_BY_WL_FW) { + dev_kfree_skb_any(skb); return; + } skb_queue_tail(&coex->queue, skb); wake_up(&coex->wait); @@ -3515,6 +3517,7 @@ static bool rtw_coex_get_bt_reg(struct rtw_dev *rtwdev, payload = get_payload_from_coex_resp(skb); *val = GET_COEX_RESP_BT_REG_VAL(payload); + dev_kfree_skb_any(skb); return true; } @@ -3533,6 +3536,8 @@ static bool rtw_coex_get_bt_patch_version(struct rtw_dev *rtwdev, payload = get_payload_from_coex_resp(skb); *patch_version = GET_COEX_RESP_BT_PATCH_VER(payload); + dev_kfree_skb_any(skb); + return true; } @@ -3550,6 +3555,8 @@ static bool rtw_coex_get_bt_supported_version(struct rtw_dev *rtwdev, payload = get_payload_from_coex_resp(skb); *supported_version = GET_COEX_RESP_BT_SUPP_VER(payload); + dev_kfree_skb_any(skb); + return true; } @@ -3567,6 +3574,8 @@ static bool rtw_coex_get_bt_supported_feature(struct rtw_dev *rtwdev, payload = get_payload_from_coex_resp(skb); *supported_feature = GET_COEX_RESP_BT_SUPP_FEAT(payload); + dev_kfree_skb_any(skb); + return true; } diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 176e8b67530e..3bfa5ecc0053 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -245,10 +245,12 @@ void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset, break; case C2H_WLAN_RFON: complete(&rtwdev->lps_leave_check); + dev_kfree_skb_any(skb); break; case C2H_SCAN_RESULT: complete(&rtwdev->fw_scan_density); rtw_fw_scan_result(rtwdev, c2h->payload, len); + dev_kfree_skb_any(skb); break; default: /* pass offset for further operation */ diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 4a9a8544e8ca..c6364837e83b 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1899,6 +1899,7 @@ void rtw_core_deinit(struct rtw_dev *rtwdev) destroy_workqueue(rtwdev->tx_wq); spin_lock_irqsave(&rtwdev->tx_report.q_lock, flags); skb_queue_purge(&rtwdev->tx_report.queue); + skb_queue_purge(&rtwdev->coex.queue); spin_unlock_irqrestore(&rtwdev->tx_report.q_lock, flags); list_for_each_entry_safe(rsvd_pkt, tmp, &rtwdev->rsvd_page_list, From c2a3823dad4988943c0b0f61af9336301e30d4e5 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 24 Jun 2021 08:29:18 +0300 Subject: [PATCH 170/170] iwlwifi: acpi: remove unused function iwl_acpi_eval_dsm_func() Stephen reported a warning: drivers/net/wireless/intel/iwlwifi/fw/acpi.c:720:12: warning: 'iwl_acpi_eval_dsm_func' defined but not used [-Wunused-function] The warning is correct and the function is not used anywhere, so let's just remove it. Reported-by: Stephen Rothwell Fixes: 7119f02b5d34 ("iwlwifi: mvm: support BIOS enable/disable for 11ax in Russia") Signed-off-by: Kalle Valo Acked-by: Luca Coelho Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210624052918.4946-1-kvalo@codeaurora.org --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 36 -------------------- 1 file changed, 36 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 8cf7bc3aa09a..34933f133a0a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -717,42 +717,6 @@ int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt, } IWL_EXPORT_SYMBOL(iwl_sar_geo_init); -static u32 iwl_acpi_eval_dsm_func(struct device *dev, enum iwl_dsm_funcs_rev_0 eval_func) -{ - union acpi_object *obj; - u32 ret; - - obj = iwl_acpi_get_dsm_object(dev, 0, - eval_func, NULL, - &iwl_guid); - - if (IS_ERR(obj)) { - IWL_DEBUG_DEV_RADIO(dev, - "ACPI: DSM func '%d': Got Error in obj = %ld\n", - eval_func, - PTR_ERR(obj)); - return 0; - } - - if (obj->type != ACPI_TYPE_INTEGER) { - IWL_DEBUG_DEV_RADIO(dev, - "ACPI: DSM func '%d' did not return a valid object, type=%d\n", - eval_func, - obj->type); - ret = 0; - goto out; - } - - ret = obj->integer.value; - IWL_DEBUG_DEV_RADIO(dev, - "ACPI: DSM method evaluated: func='%d', ret=%d\n", - eval_func, - ret); -out: - ACPI_FREE(obj); - return ret; -} - __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) { int ret;