From 2cb002e3c29434b0159a3a4d343d460264dae2ac Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 2 Jun 2020 22:26:38 +0200 Subject: mt76: add missing lock configuring coverage class Coverage class callback can potentially run in parallel with other routines (e.g. mt7615_set_channel) that configures timing registers. Run coverage class callback holding mt76 mutex Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7603/main.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt7615/main.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt7915/main.c | 3 +++ 3 files changed, 8 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 26cb711b465f..83dfa6da4761 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -642,8 +642,10 @@ mt7603_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) { struct mt7603_dev *dev = hw->priv; + mutex_lock(&dev->mt76.mutex); dev->coverage_class = max_t(s16, coverage_class, 0); mt7603_mac_set_timing(dev); + mutex_unlock(&dev->mt76.mutex); } static void mt7603_tx(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index c26f99b368d9..52d6544698fe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -735,9 +735,12 @@ static void mt7615_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) { struct mt7615_phy *phy = mt7615_hw_phy(hw); + struct mt7615_dev *dev = phy->dev; + mutex_lock(&dev->mt76.mutex); phy->coverage_class = max_t(s16, coverage_class, 0); mt7615_mac_set_timing(phy); + mutex_unlock(&dev->mt76.mutex); } static int diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 0575c259f245..05b5650c56c8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -716,9 +716,12 @@ static void mt7915_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) { struct mt7915_phy *phy = mt7915_hw_phy(hw); + struct mt7915_dev *dev = phy->dev; + mutex_lock(&dev->mt76.mutex); phy->coverage_class = max_t(s16, coverage_class, 0); mt7915_mac_set_timing(phy); + mutex_unlock(&dev->mt76.mutex); } static int -- cgit v1.2.3 From 8fc49625a33ad070013773b923fb945340000e37 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 30 May 2020 23:51:27 +0200 Subject: mt76: mt7615: fix lmac queue debugsfs entry acs and wmm index are swapped in mt7615_queues_acq respect to the hw design Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index fd3ef483a87c..d06afcf46d67 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -234,10 +234,11 @@ mt7615_queues_acq(struct seq_file *s, void *data) int i; for (i = 0; i < 16; i++) { - int j, acs = i / 4, index = i % 4; + int j, wmm_idx = i % MT7615_MAX_WMM_SETS; + int acs = i / MT7615_MAX_WMM_SETS; u32 ctrl, val, qlen = 0; - val = mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, index)); + val = mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, wmm_idx)); ctrl = BIT(31) | BIT(15) | (acs << 8); for (j = 0; j < 32; j++) { @@ -245,11 +246,11 @@ mt7615_queues_acq(struct seq_file *s, void *data) continue; mt76_wr(dev, MT_PLE_FL_Q0_CTRL, - ctrl | (j + (index << 5))); + ctrl | (j + (wmm_idx << 5))); qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL, GENMASK(11, 0)); } - seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen); + seq_printf(s, "AC%d%d: queued=%d\n", wmm_idx, acs, qlen); } return 0; -- cgit v1.2.3 From 1fec635bcc9e14604f06d0947725fd3c613e1af0 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 31 May 2020 00:32:04 +0200 Subject: mt76: mt7615: fix hw queue mapping mt7622/mt7663 chipsets rely on a fixed reverse queue map order respect to mac80211 one: - q(0): IEEE80211_AC_BK - q(1): IEEE80211_AC_BE - q(2): IEEE80211_AC_VI - q(3): IEEE80211_AC_VO Fixes: cdad4874057d ("mt76: mt7615: add dma and tx queue initialization for MT7622") Fixes: f40ac0f3d3c0 ("mt76: mt7615: introduce mt7663e support") Co-developed-by: Sean Wang Signed-off-by: Sean Wang Co-developed-by: Ryder Lee Signed-off-by: Ryder Lee Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/dma.c | 8 +++--- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/mac.h | 15 ----------- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 30 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/usb.c | 17 ++++++------ 6 files changed, 45 insertions(+), 28 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c index 5a124610d4af..83fdcf5db3c7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c @@ -36,10 +36,10 @@ static int mt7622_init_tx_queues_multi(struct mt7615_dev *dev) { static const u8 wmm_queue_map[] = { - MT7622_TXQ_AC0, - MT7622_TXQ_AC1, - MT7622_TXQ_AC2, - MT7622_TXQ_AC3, + [IEEE80211_AC_BK] = MT7622_TXQ_AC0, + [IEEE80211_AC_BE] = MT7622_TXQ_AC1, + [IEEE80211_AC_VI] = MT7622_TXQ_AC2, + [IEEE80211_AC_VO] = MT7622_TXQ_AC3, }; int ret; int i; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 9f1c6ca7a665..5990355bc731 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -528,7 +528,7 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, if (ieee80211_is_data(fc) || ieee80211_is_bufferable_mmpdu(fc)) { q_idx = wmm_idx * MT7615_MAX_WMM_SETS + - skb_get_queue_mapping(skb); + mt7615_lmac_mapping(dev, skb_get_queue_mapping(skb)); p_fmt = is_usb ? MT_TX_TYPE_SF : MT_TX_TYPE_CT; } else if (beacon) { if (ext_phy) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h index f0d4b29a52a2..81608ab656b8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h @@ -124,21 +124,6 @@ enum tx_pkt_type { MT_TX_TYPE_FW, }; -enum tx_pkt_queue_idx { - MT_LMAC_AC00, - MT_LMAC_AC01, - MT_LMAC_AC02, - MT_LMAC_AC03, - MT_LMAC_ALTX0 = 0x10, - MT_LMAC_BMC0, - MT_LMAC_BCN0, - MT_LMAC_PSMP0, - MT_LMAC_ALTX1, - MT_LMAC_BMC1, - MT_LMAC_BCN1, - MT_LMAC_PSMP1, -}; - enum tx_port_idx { MT_TX_PORT_IDX_LMAC, MT_TX_PORT_IDX_MCU diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 52d6544698fe..beaca8127680 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -397,6 +397,7 @@ mt7615_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_dev *dev = mt7615_hw_dev(hw); + queue = mt7615_lmac_mapping(dev, queue); queue += mvif->wmm_idx * MT7615_MAX_WMM_SETS; return mt7615_mcu_set_wmm(dev, queue, params); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index d6176d316bee..3e7d51bf42a4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -282,6 +282,21 @@ struct mt7615_dev { struct list_head wd_head; }; +enum tx_pkt_queue_idx { + MT_LMAC_AC00, + MT_LMAC_AC01, + MT_LMAC_AC02, + MT_LMAC_AC03, + MT_LMAC_ALTX0 = 0x10, + MT_LMAC_BMC0, + MT_LMAC_BCN0, + MT_LMAC_PSMP0, + MT_LMAC_ALTX1, + MT_LMAC_BMC1, + MT_LMAC_BCN1, + MT_LMAC_PSMP1, +}; + enum { HW_BSSID_0 = 0x0, HW_BSSID_1, @@ -447,6 +462,21 @@ static inline u16 mt7615_wtbl_size(struct mt7615_dev *dev) return MT7615_WTBL_SIZE; } +static inline u8 mt7615_lmac_mapping(struct mt7615_dev *dev, u8 ac) +{ + static const u8 lmac_queue_map[] = { + [IEEE80211_AC_BK] = MT_LMAC_AC00, + [IEEE80211_AC_BE] = MT_LMAC_AC01, + [IEEE80211_AC_VI] = MT_LMAC_AC02, + [IEEE80211_AC_VO] = MT_LMAC_AC03, + }; + + if (WARN_ON_ONCE(ac >= ARRAY_SIZE(lmac_queue_map))) + return MT_LMAC_AC01; /* BE */ + + return lmac_queue_map[ac]; +} + 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/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index fb97ea25b4d4..27abcdb61a06 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -1010,17 +1010,18 @@ static void mt76u_tx_kick(struct mt76_dev *dev, struct mt76_queue *q) static u8 mt76u_ac_to_hwq(struct mt76_dev *dev, u8 ac) { if (mt76_chip(dev) == 0x7663) { - static const u8 wmm_queue_map[] = { - [IEEE80211_AC_VO] = 0, - [IEEE80211_AC_VI] = 1, - [IEEE80211_AC_BE] = 2, - [IEEE80211_AC_BK] = 4, + static const u8 lmac_queue_map[] = { + /* ac to lmac mapping */ + [IEEE80211_AC_BK] = 0, + [IEEE80211_AC_BE] = 1, + [IEEE80211_AC_VI] = 2, + [IEEE80211_AC_VO] = 4, }; - if (WARN_ON(ac >= ARRAY_SIZE(wmm_queue_map))) - return 2; /* BE */ + if (WARN_ON(ac >= ARRAY_SIZE(lmac_queue_map))) + return 1; /* BE */ - return wmm_queue_map[ac]; + return lmac_queue_map[ac]; } return mt76_ac_to_hwq(ac); -- cgit v1.2.3 From d3c829985234450c0278e4fad994b70c8376c3b6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 1 Jun 2020 09:45:33 +0200 Subject: mt76: overwrite qid for non-bufferable mgmt frames Overwrite hw queue id for non-bufferable management frames if the hw support always txq (altxq) in order to be in sync with mac txwi code Fixes: cdad4874057d ("mt76: mt7615: add dma and tx queue initialization for MT7622") Fixes: f40ac0f3d3c0 ("mt76: mt7615: introduce mt7663e support") Suggested-by: Felix Fietkau Tested-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/dma.c | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 20 +++++++------------- drivers/net/wireless/mediatek/mt76/mt7615/mmio.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/usb.c | 2 +- drivers/net/wireless/mediatek/mt76/tx.c | 7 +++++++ 6 files changed, 18 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index dfe625a53c63..3d7db6ffb599 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -301,6 +301,7 @@ struct mt76_hw_cap { #define MT_DRV_TX_ALIGNED4_SKBS BIT(1) #define MT_DRV_SW_RX_AIRTIME BIT(2) #define MT_DRV_RX_DMA_HDR BIT(3) +#define MT_DRV_HW_MGMT_TXQ BIT(4) struct mt76_driver_ops { u32 drv_flags; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c index 83fdcf5db3c7..e5a965df899a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c @@ -100,6 +100,7 @@ mt7615_tx_cleanup(struct mt7615_dev *dev) int i; mt76_queue_tx_cleanup(dev, MT_TXQ_MCU, false); + mt76_queue_tx_cleanup(dev, MT_TXQ_PSD, false); if (is_mt7615(&dev->mt76)) { mt76_queue_tx_cleanup(dev, MT_TXQ_BE, false); } else { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 5990355bc731..d97315ec7265 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -526,22 +526,16 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2; fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4; - if (ieee80211_is_data(fc) || ieee80211_is_bufferable_mmpdu(fc)) { - q_idx = wmm_idx * MT7615_MAX_WMM_SETS + - mt7615_lmac_mapping(dev, skb_get_queue_mapping(skb)); - p_fmt = is_usb ? MT_TX_TYPE_SF : MT_TX_TYPE_CT; - } else if (beacon) { - if (ext_phy) - q_idx = MT_LMAC_BCN1; - else - q_idx = MT_LMAC_BCN0; + if (beacon) { p_fmt = MT_TX_TYPE_FW; + q_idx = ext_phy ? MT_LMAC_BCN1 : MT_LMAC_BCN0; + } else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) { + p_fmt = is_usb ? MT_TX_TYPE_SF : MT_TX_TYPE_CT; + q_idx = ext_phy ? MT_LMAC_ALTX1 : MT_LMAC_ALTX0; } else { - if (ext_phy) - q_idx = MT_LMAC_ALTX1; - else - q_idx = MT_LMAC_ALTX0; p_fmt = is_usb ? MT_TX_TYPE_SF : MT_TX_TYPE_CT; + q_idx = wmm_idx * MT7615_MAX_WMM_SETS + + mt7615_lmac_mapping(dev, skb_get_queue_mapping(skb)); } val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) | diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c index e670393506f0..2e99845b9c96 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c @@ -146,7 +146,7 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, static const struct mt76_driver_ops drv_ops = { /* txwi_size = txd size + txp size */ .txwi_size = MT_TXD_SIZE + sizeof(struct mt7615_txp_common), - .drv_flags = MT_DRV_TXWI_NO_FREE, + .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ, .survey_flags = SURVEY_INFO_TIME_TX | SURVEY_INFO_TIME_RX | SURVEY_INFO_TIME_BSS_RX, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c index a50077eb24d7..f5dc1b828518 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -270,7 +270,7 @@ static int mt7663u_probe(struct usb_interface *usb_intf, { static const struct mt76_driver_ops drv_ops = { .txwi_size = MT_USB_TXD_SIZE, - .drv_flags = MT_DRV_RX_DMA_HDR, + .drv_flags = MT_DRV_RX_DMA_HDR | MT_DRV_HW_MGMT_TXQ, .tx_prepare_skb = mt7663u_tx_prepare_skb, .tx_complete_skb = mt7663u_tx_complete_skb, .tx_status_data = mt7663u_tx_status_data, diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index fca38ea2441f..f10c98aa883c 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -264,6 +264,13 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta, skb_set_queue_mapping(skb, qid); } + if ((dev->drv->drv_flags & MT_DRV_HW_MGMT_TXQ) && + !ieee80211_is_data(hdr->frame_control) && + !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) { + qid = MT_TXQ_PSD; + skb_set_queue_mapping(skb, qid); + } + if (!(wcid->tx_info & MT_WCID_TX_INFO_SET)) ieee80211_get_tx_rates(info->control.vif, sta, skb, info->control.rates, 1); -- cgit v1.2.3 From a28bef561a5c144e7c6237626d748767fef7fc79 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 30 May 2020 17:19:45 +0200 Subject: mt76: mt7615: re-enable offloading of sequence number assignment Preparation for supporting more offload features Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 44 +++++++++++++++++----- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 5 +++ drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 1 + 3 files changed, 41 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index d97315ec7265..d150fac50c00 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -617,16 +617,19 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, } val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count); - if (ieee80211_is_data_qos(hdr->frame_control)) { - seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); - val |= MT_TXD3_SN_VALID; - } else if (ieee80211_is_back_req(hdr->frame_control)) { - struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data; - - seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(bar->start_seq_num)); - val |= MT_TXD3_SN_VALID; + if (info->flags & IEEE80211_TX_CTL_INJECTED) { + seqno = le16_to_cpu(hdr->seq_ctrl); + + if (ieee80211_is_back_req(hdr->frame_control)) { + struct ieee80211_bar *bar; + + bar = (struct ieee80211_bar *)skb->data; + seqno = le16_to_cpu(bar->start_seq_num); + } + + val |= MT_TXD3_SN_VALID | + FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno)); } - val |= FIELD_PREP(MT_TXD3_SEQ, seqno); txwi[3] |= cpu_to_le32(val); @@ -893,6 +896,29 @@ mt7615_mac_queue_rate_update(struct mt7615_phy *phy, struct mt7615_sta *sta, return 0; } +u32 mt7615_mac_get_sta_tid_sn(struct mt7615_dev *dev, int wcid, u8 tid) +{ + u32 addr, val, val2; + u8 offset; + + addr = mt7615_mac_wtbl_addr(dev, wcid) + 11 * 4; + + offset = tid * 12; + addr += 4 * (offset / 32); + offset %= 32; + + val = mt76_rr(dev, addr); + val >>= (tid % 32); + + if (offset > 20) { + addr += 4; + val2 = mt76_rr(dev, addr); + val |= val2 << (32 - offset); + } + + return val & GENMASK(11, 0); +} + void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, struct ieee80211_tx_rate *probe_rate, struct ieee80211_tx_rate *rates) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index beaca8127680..dfebf86b86d6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -660,6 +660,9 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mtxq->aggr = true; mtxq->send_bar = false; mt7615_mcu_add_tx_ba(dev, params, true); + ssn = mt7615_mac_get_sta_tid_sn(dev, msta->wcid.idx, tid); + ieee80211_send_bar(vif, sta->addr, tid, + IEEE80211_SN_TO_SEQ(ssn)); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: @@ -667,6 +670,8 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt7615_mcu_add_tx_ba(dev, params, false); break; case IEEE80211_AMPDU_TX_START: + ssn = mt7615_mac_get_sta_tid_sn(dev, msta->wcid.idx, tid); + params->ssn = ssn; mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 3e7d51bf42a4..640ff8b9b266 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -516,6 +516,7 @@ int mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, enum mt7615_cipher_type cipher, enum set_key_cmd cmd); void mt7615_mac_reset_work(struct work_struct *work); +u32 mt7615_mac_get_sta_tid_sn(struct mt7615_dev *dev, int wcid, u8 tid); int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq); int mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, -- cgit v1.2.3 From be49c5356f3923015ef7ace59c71be3013d18608 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 30 May 2020 23:48:56 +0200 Subject: mt76: usb: rely on mt76_for_each_q_rx Rely on mt76_for_each_q_rx whenever possible in order to simply the code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/debugfs.c | 3 -- drivers/net/wireless/mediatek/mt76/usb.c | 41 ++++++++-------------------- 2 files changed, 12 insertions(+), 32 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c index 3a5de1d1b121..9fda65db8cac 100644 --- a/drivers/net/wireless/mediatek/mt76/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/debugfs.c @@ -54,9 +54,6 @@ static int mt76_rx_queues_read(struct seq_file *s, void *data) mt76_for_each_q_rx(dev, i) { struct mt76_queue *q = &dev->q_rx[i]; - if (!q->ndesc) - continue; - queued = mt76_is_usb(dev) ? q->ndesc - q->queued : q->queued; seq_printf(s, "%d: queued=%d head=%d tail=%d\n", i, queued, q->head, q->tail); diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 27abcdb61a06..0ff3096f7455 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -672,17 +672,11 @@ mt76u_process_rx_queue(struct mt76_dev *dev, struct mt76_queue *q) static void mt76u_rx_tasklet(unsigned long data) { struct mt76_dev *dev = (struct mt76_dev *)data; - struct mt76_queue *q; int i; rcu_read_lock(); - for (i = 0; i < __MT_RXQ_MAX; i++) { - q = &dev->q_rx[i]; - if (!q->ndesc) - continue; - - mt76u_process_rx_queue(dev, q); - } + mt76_for_each_q_rx(dev, i) + mt76u_process_rx_queue(dev, &dev->q_rx[i]); rcu_read_unlock(); } @@ -756,27 +750,19 @@ mt76u_free_rx_queue(struct mt76_dev *dev, struct mt76_queue *q) static void mt76u_free_rx(struct mt76_dev *dev) { - struct mt76_queue *q; int i; - for (i = 0; i < __MT_RXQ_MAX; i++) { - q = &dev->q_rx[i]; - if (!q->ndesc) - continue; - - mt76u_free_rx_queue(dev, q); - } + mt76_for_each_q_rx(dev, i) + mt76u_free_rx_queue(dev, &dev->q_rx[i]); } void mt76u_stop_rx(struct mt76_dev *dev) { - struct mt76_queue *q; - int i, j; + int i; - for (i = 0; i < __MT_RXQ_MAX; i++) { - q = &dev->q_rx[i]; - if (!q->ndesc) - continue; + mt76_for_each_q_rx(dev, i) { + struct mt76_queue *q = &dev->q_rx[i]; + int j; for (j = 0; j < q->ndesc; j++) usb_poison_urb(q->entry[j].urb); @@ -788,14 +774,11 @@ EXPORT_SYMBOL_GPL(mt76u_stop_rx); int mt76u_resume_rx(struct mt76_dev *dev) { - struct mt76_queue *q; - int i, j, err; - - for (i = 0; i < __MT_RXQ_MAX; i++) { - q = &dev->q_rx[i]; + int i; - if (!q->ndesc) - continue; + mt76_for_each_q_rx(dev, i) { + struct mt76_queue *q = &dev->q_rx[i]; + int err, j; for (j = 0; j < q->ndesc; j++) usb_unpoison_urb(q->entry[j].urb); -- cgit v1.2.3 From 73741b9bee690ffd7c22e25c419b9f7979afadeb Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Sun, 7 Jun 2020 11:34:40 +0200 Subject: mt76: mt7663: introduce ARP filter offload Introduce ARP filter offload Co-developed-by: Wan-Feng Jiang Signed-off-by: Wan-Feng Jiang Co-developed-by: Soul Huang Signed-off-by: Soul Huang 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/mt7615/main.c | 3 + drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 74 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 13 +++- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 4 +- 4 files changed, 91 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index dfebf86b86d6..e6dbd7034bd7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -491,6 +491,9 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_PS) mt7615_mcu_set_vif_ps(dev, vif); + if (changed & BSS_CHANGED_ARP_FILTER) + mt7615_mcu_update_arp_filter(hw, vif, info); + mutex_unlock(&dev->mt76.mutex); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 6e869b8c5e26..b76ecc24f333 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -3542,6 +3542,32 @@ mt7615_mcu_set_gtk_rekey(struct mt7615_dev *dev, &req, sizeof(req), true); } +static int +mt7615_mcu_set_arp_filter(struct mt7615_dev *dev, struct ieee80211_vif *vif, + bool suspend) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct mt7615_arpns_tlv arpns; + } req = { + .hdr = { + .bss_idx = mvif->idx, + }, + .arpns = { + .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP), + .len = cpu_to_le16(sizeof(struct mt7615_arpns_tlv)), + .mode = suspend, + }, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_OFFLOAD, + &req, sizeof(req), true); +} + void mt7615_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { @@ -3554,6 +3580,7 @@ void mt7615_mcu_set_suspend_iter(void *priv, u8 *mac, mt7615_mcu_set_bss_pm(phy->dev, vif, suspend); mt7615_mcu_set_gtk_rekey(phy->dev, vif, suspend); + mt7615_mcu_set_arp_filter(phy->dev, vif, suspend); mt7615_mcu_set_suspend_mode(phy->dev, vif, suspend, 1, true); @@ -3653,6 +3680,53 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, sizeof(req), false); } +int mt7615_mcu_update_arp_filter(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt7615_dev *dev = mt7615_hw_dev(hw); + struct sk_buff *skb; + int i, len = min_t(int, info->arp_addr_cnt, + IEEE80211_BSS_ARP_ADDR_LIST_LEN); + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct mt7615_arpns_tlv arp; + } req_hdr = { + .hdr = { + .bss_idx = mvif->idx, + }, + .arp = { + .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP), + .len = cpu_to_le16(sizeof(struct mt7615_arpns_tlv)), + .ips_num = len, + .mode = 2, /* update */ + .option = 1, + }, + }; + + if (!mt7615_firmware_offload(dev)) + return 0; + + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, + sizeof(req_hdr) + len * sizeof(__be32)); + if (!skb) + return -ENOMEM; + + skb_put_data(skb, &req_hdr, sizeof(req_hdr)); + for (i = 0; i < len; i++) { + u8 *addr = (u8 *)skb_put(skb, sizeof(__be32)); + + memcpy(addr, &info->arp_addr_list[i], sizeof(__be32)); + } + + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_UNI_CMD_OFFLOAD, true); +} + int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 2314d0b23af1..64f7471a57bb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -545,6 +545,15 @@ struct mt7615_roc_tlv { u8 rsv1[8]; } __packed; +struct mt7615_arpns_tlv { + __le16 tag; + __le16 len; + u8 mode; + u8 ips_num; + u8 option; + u8 pad[1]; +} __packed; + /* offload mcu commands */ enum { MCU_CMD_START_HW_SCAN = MCU_CE_PREFIX | 0x03, @@ -580,8 +589,8 @@ enum { }; enum { - UNI_OFFLOAD_OFFLOAD_ARPNS_IPV4, - UNI_OFFLOAD_OFFLOAD_ARPNS_IPV6, + UNI_OFFLOAD_OFFLOAD_ARP, + UNI_OFFLOAD_OFFLOAD_ND, UNI_OFFLOAD_OFFLOAD_GTK_REKEY, UNI_OFFLOAD_OFFLOAD_BMC_RPY_DETECT, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 640ff8b9b266..913dac5c3006 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -586,7 +586,9 @@ void mt7615_mcu_set_suspend_iter(void *priv, u8 *mac, int mt7615_mcu_update_gtk_rekey(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_gtk_rekey_data *key); - +int mt7615_mcu_update_arp_filter(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info); int __mt7663_load_firmware(struct mt7615_dev *dev); /* usb */ -- cgit v1.2.3 From 642023d04335458a057b549da329ee4e30c8a838 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 9 Jun 2020 23:42:21 +0800 Subject: mt76: mt7615: fix up typo in Kconfig for MT7663U Fix up typo in Kconfig with indicating MT7663U is an 802.11ac device Fixes: eb99cc95c3b6 ("mt76: mt7615: introduce mt7663u support") Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig index e25db1135eda..c094260b0f89 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig @@ -35,6 +35,6 @@ config MT7663U depends on MAC80211 depends on USB help - This adds support for MT7663U 802.11ax 2x2:2 wireless devices. + This adds support for MT7663U 802.11ac 2x2:2 wireless devices. To compile this driver as a module, choose M here. -- cgit v1.2.3 From 9da82fb76d6cea157e31bf0c247d2b4c6883cead Mon Sep 17 00:00:00 2001 From: Markus Theil Date: Thu, 11 Jun 2020 14:40:22 +0200 Subject: mt76: allow more channels, allowed in ETSI domain While looking at the ETSI regulatory domain definitions and a patch, which allows more channels for ath10k, I also checked the channels allowed for mt76. ETSI regulations would possibly allow to add channels 32, 68, 96, 144, 169 and 173. IEEE 802.11-2016 defines no operating class for channels 32, 68 and 96. This leaves us channels 144, 169 and 173, which are included in this patch. I tested 169 and 173 with a mt76 based USB dongle (AVM AC 860) and they worked fine. If I saw that right, these channels are also covered by register definitions inside the driver. Channel 144 should also work, but gets disabled by the kernel as of now. Signed-off-by: Markus Theil Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 907098101898..4c10c8164aee 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -58,12 +58,15 @@ static const struct ieee80211_channel mt76_channels_5ghz[] = { CHAN5G(132, 5660), CHAN5G(136, 5680), CHAN5G(140, 5700), + CHAN5G(144, 5720), CHAN5G(149, 5745), CHAN5G(153, 5765), CHAN5G(157, 5785), CHAN5G(161, 5805), CHAN5G(165, 5825), + CHAN5G(169, 5845), + CHAN5G(173, 5865), }; static const struct ieee80211_tpt_blink mt76_tpt_blink[] = { -- cgit v1.2.3 From e39da597e5782a5fcdad0c23dee61dbe05d327b8 Mon Sep 17 00:00:00 2001 From: Markus Theil Date: Fri, 12 Jun 2020 10:05:23 +0200 Subject: mt76: fix include in pci.h kernel test robot found the following issue and Kalle Valo forwarded it to Linux wireless. drivers/net/wireless/mediatek/mt76/pci.c:8:6: warning: no previous prototype for 'mt76_pci_disable_aspm' Fix this by adding the missing include of mt76.h as Kalle suggested. Signed-off-by: Markus Theil Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/pci.c b/drivers/net/wireless/mediatek/mt76/pci.c index 04c5a692bc85..4c1c159fbb62 100644 --- a/drivers/net/wireless/mediatek/mt76/pci.c +++ b/drivers/net/wireless/mediatek/mt76/pci.c @@ -3,6 +3,7 @@ * Copyright (C) 2019 Lorenzo Bianconi */ +#include "mt76.h" #include void mt76_pci_disable_aspm(struct pci_dev *pdev) -- cgit v1.2.3 From 4a58d5d1097a6b1918c4e307a8d30211ba721932 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 12 Jun 2020 12:08:59 +0200 Subject: mt76: rely on register macros For consistency with the rest of the code always rely on defined macros for register access Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/debugfs.c | 4 ++-- drivers/net/wireless/mediatek/mt76/util.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c index 9fda65db8cac..5d58b16bfe9f 100644 --- a/drivers/net/wireless/mediatek/mt76/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/debugfs.c @@ -9,7 +9,7 @@ mt76_reg_set(void *data, u64 val) { struct mt76_dev *dev = data; - dev->bus->wr(dev, dev->debugfs_reg, val); + __mt76_wr(dev, dev->debugfs_reg, val); return 0; } @@ -18,7 +18,7 @@ mt76_reg_get(void *data, u64 *val) { struct mt76_dev *dev = data; - *val = dev->bus->rr(dev, dev->debugfs_reg); + *val = __mt76_rr(dev, dev->debugfs_reg); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/util.c b/drivers/net/wireless/mediatek/mt76/util.c index ecde87465bf6..f53bb4ae5001 100644 --- a/drivers/net/wireless/mediatek/mt76/util.c +++ b/drivers/net/wireless/mediatek/mt76/util.c @@ -13,7 +13,7 @@ bool __mt76_poll(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, timeout /= 10; do { - cur = dev->bus->rr(dev, offset) & mask; + cur = __mt76_rr(dev, offset) & mask; if (cur == val) return true; @@ -31,7 +31,7 @@ bool __mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, timeout /= 10; do { - cur = dev->bus->rr(dev, offset) & mask; + cur = __mt76_rr(dev, offset) & mask; if (cur == val) return true; -- cgit v1.2.3 From b807b368c4f9bbdb8410dcc6241d7903094f0bef Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 12 Jun 2020 13:46:31 +0200 Subject: mt76: add U-APSD support on AP side Introduce U-APSD support in mt76 driver for AP interface Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 4 ++- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 46 +++++++++++++++++++++++-- drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 21 +++++++++++ 3 files changed, 68 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 4c10c8164aee..d8533d0c6e81 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -282,7 +282,8 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw) wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH | - WIPHY_FLAG_SUPPORTS_TDLS; + WIPHY_FLAG_SUPPORTS_TDLS | + WIPHY_FLAG_AP_UAPSD; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); @@ -292,6 +293,7 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw) wiphy->available_antennas_rx = dev->phy.antenna_mask; hw->txq_data_size = sizeof(struct mt76_txq); + hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL; if (!hw->max_tx_fragments) hw->max_tx_fragments = 16; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index b76ecc24f333..d3a8ada3b779 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -926,6 +926,38 @@ mt7615_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) } } +static void +mt7615_mcu_sta_uapsd(struct sk_buff *skb, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct sta_rec_uapsd *uapsd; + struct tlv *tlv; + + if (vif->type != NL80211_IFTYPE_AP || !sta->wme) + return; + + tlv = mt7615_mcu_add_tlv(skb, STA_REC_APPS, sizeof(*uapsd)); + uapsd = (struct sta_rec_uapsd *)tlv; + + if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) { + uapsd->dac_map |= BIT(3); + uapsd->tac_map |= BIT(3); + } + if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) { + uapsd->dac_map |= BIT(2); + uapsd->tac_map |= BIT(2); + } + if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) { + uapsd->dac_map |= BIT(1); + uapsd->tac_map |= BIT(1); + } + if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) { + uapsd->dac_map |= BIT(0); + uapsd->tac_map |= BIT(0); + } + uapsd->max_sp = sta->max_sp; +} + static void mt7615_mcu_wtbl_ba_tlv(struct sk_buff *skb, struct ieee80211_ampdu_params *params, @@ -1188,8 +1220,10 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_dev *dev, struct ieee80211_vif *vif, return PTR_ERR(sskb); mt7615_mcu_sta_basic_tlv(sskb, vif, sta, enable); - if (enable && sta) + if (enable && sta) { mt7615_mcu_sta_ht_tlv(sskb, sta); + mt7615_mcu_sta_uapsd(sskb, vif, sta); + } wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_RESET_AND_SET, NULL, &wskb); @@ -1285,8 +1319,10 @@ mt7615_mcu_add_sta_cmd(struct mt7615_dev *dev, struct ieee80211_vif *vif, return PTR_ERR(skb); mt7615_mcu_sta_basic_tlv(skb, vif, sta, enable); - if (enable && sta) + if (enable && sta) { mt7615_mcu_sta_ht_tlv(skb, sta); + mt7615_mcu_sta_uapsd(skb, vif, sta); + } sta_wtbl = mt7615_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); @@ -1429,6 +1465,7 @@ mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, u8 pad[3]; } __packed hdr; struct mt7615_bss_basic_tlv basic; + struct mt7615_bss_qos_tlv qos; } basic_req = { .hdr = { .bss_idx = mvif->idx, @@ -1444,6 +1481,11 @@ mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, .active = true, /* keep bss deactivated */ .phymode = 0x38, }, + .qos = { + .tag = cpu_to_le16(UNI_BSS_INFO_QBSS), + .len = cpu_to_le16(sizeof(struct mt7615_bss_qos_tlv)), + .qos = vif->bss_conf.qos, + }, }; struct { struct { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 64f7471a57bb..4f70c4de69a4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -454,6 +454,13 @@ struct mt7615_bss_basic_tlv { u8 pad[3]; } __packed; +struct mt7615_bss_qos_tlv { + __le16 tag; + __le16 len; + u8 qos; + u8 pad[3]; +} __packed; + struct mt7615_wow_ctrl_tlv { __le16 tag; __le16 len; @@ -578,6 +585,8 @@ enum { UNI_BSS_INFO_BASIC = 0, UNI_BSS_INFO_RLM = 2, UNI_BSS_INFO_BCN_CONTENT = 7, + UNI_BSS_INFO_QBSS = 15, + UNI_BSS_INFO_UAPSD = 19, }; enum { @@ -891,6 +900,7 @@ struct wtbl_raw { sizeof(struct sta_rec_basic) + \ sizeof(struct sta_rec_ht) + \ sizeof(struct sta_rec_vht) + \ + sizeof(struct sta_rec_uapsd) + \ sizeof(struct tlv) + \ MT7615_WTBL_UPDATE_MAX_SIZE) @@ -980,6 +990,17 @@ struct sta_rec_ba { __le16 winsize; } __packed; +struct sta_rec_uapsd { + __le16 tag; + __le16 len; + u8 dac_map; + u8 tac_map; + u8 max_sp; + u8 rsv0; + __le16 listen_interval; + u8 rsv1[2]; +} __packed; + enum { STA_REC_BASIC, STA_REC_RA, -- cgit v1.2.3 From b876658b5e554c6bd251720b7cd40de5b5f6c366 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Thu, 18 Jun 2020 12:41:48 +0800 Subject: mt76: mt7615: add .set_tsf callback It is useful for IBSS Mesh to adjust t_clockdrift. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 21 +++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 1 + 2 files changed, 22 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index e6dbd7034bd7..f8ce485c8d19 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -740,6 +740,26 @@ mt7615_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) return tsf.t64; } +static void +mt7615_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u64 timestamp) +{ + struct mt7615_dev *dev = mt7615_hw_dev(hw); + union { + u64 t64; + u32 t32[2]; + } tsf = { .t64 = timestamp, }; + + mutex_lock(&dev->mt76.mutex); + + mt76_wr(dev, MT_LPON_UTTR0, tsf.t32[0]); + mt76_wr(dev, MT_LPON_UTTR1, tsf.t32[1]); + /* TSF software overwrite */ + mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_WRITE); + + mutex_unlock(&dev->mt76.mutex); +} + static void mt7615_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) { @@ -1038,6 +1058,7 @@ const struct ieee80211_ops mt7615_ops = { .channel_switch_beacon = mt7615_channel_switch_beacon, .get_stats = mt7615_get_stats, .get_tsf = mt7615_get_tsf, + .set_tsf = mt7615_set_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 aee433a9eff6..f0b36b162bf3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -417,6 +417,7 @@ enum mt7615_reg_base { #define MT_LPON_T0CR MT_LPON(0x010) #define MT_LPON_T0CR_MODE GENMASK(1, 0) +#define MT_LPON_T0CR_WRITE BIT(0) #define MT_LPON_UTTR0 MT_LPON(0x018) #define MT_LPON_UTTR1 MT_LPON(0x01c) -- cgit v1.2.3 From dcdecb128b2e0856e3131d93102d80bd748f2d9b Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Mon, 15 Jun 2020 02:23:34 +0800 Subject: mt76: mt7915: add a fixed AC queue mapping In MT7915, hardware queue map is flexible. However, certain firmware modules like MU and U-APSD presume a fixed queue order to adapt some devices that have DMA scheduler with a strict order, so this patch can help in the long run. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/mac.h | 10 --------- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 25 ++++++++++++++++++++++ 4 files changed, 29 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index a264e304a3df..660e1820cccf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -593,7 +593,7 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, if (ieee80211_is_data(fc) || ieee80211_is_bufferable_mmpdu(fc)) { q_idx = wmm_idx * MT7915_MAX_WMM_SETS + - skb_get_queue_mapping(skb); + mt7915_lmac_mapping(dev, skb_get_queue_mapping(skb)); p_fmt = MT_TX_TYPE_CT; } else if (beacon) { q_idx = MT_LMAC_BCN0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h index b9bc8b25b031..4b0871ab2414 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -149,16 +149,6 @@ enum tx_pkt_type { MT_TX_TYPE_FW, }; -enum tx_pkt_queue_idx { - MT_LMAC_AC00, - MT_LMAC_AC01, - MT_LMAC_AC02, - MT_LMAC_AC03, - MT_LMAC_ALTX0 = 0x10, - MT_LMAC_BMC0 = 0x10, - MT_LMAC_BCN0 = 0x12, -}; - enum tx_port_idx { MT_TX_PORT_IDX_LMAC, MT_TX_PORT_IDX_MCU diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 05b5650c56c8..e09899748c9b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -350,9 +350,12 @@ static int mt7915_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { + struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; /* no need to update right away, we'll get BSS_CHANGED_QOS */ + queue = mt7915_lmac_mapping(dev, queue); + mvif->wmm[queue].cw_min = params->cw_min; mvif->wmm[queue].cw_max = params->cw_max; mvif->wmm[queue].aifs = params->aifs; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 85d74ecd0351..b3b00d099236 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -199,6 +199,16 @@ enum { EXT_BSSID_END }; +enum { + MT_LMAC_AC00, + MT_LMAC_AC01, + MT_LMAC_AC02, + MT_LMAC_AC03, + MT_LMAC_ALTX0 = 0x10, + MT_LMAC_BMC0, + MT_LMAC_BCN0, +}; + enum { MT_RX_SEL0, MT_RX_SEL1, @@ -254,6 +264,21 @@ mt7915_ext_phy(struct mt7915_dev *dev) return phy->priv; } +static inline u8 mt7915_lmac_mapping(struct mt7915_dev *dev, u8 ac) +{ + static const u8 lmac_queue_map[] = { + [IEEE80211_AC_BK] = MT_LMAC_AC00, + [IEEE80211_AC_BE] = MT_LMAC_AC01, + [IEEE80211_AC_VI] = MT_LMAC_AC02, + [IEEE80211_AC_VO] = MT_LMAC_AC03, + }; + + if (WARN_ON_ONCE(ac >= ARRAY_SIZE(lmac_queue_map))) + return MT_LMAC_AC01; /* BE */ + + return lmac_queue_map[ac]; +} + static inline void mt7915_set_aggr_state(struct mt7915_sta *msta, u8 tid, enum mt7915_ampdu_state state) -- cgit v1.2.3 From f68e6a1f85c148f0b238bdaef22f31b01d5cf51e Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Mon, 15 Jun 2020 02:23:35 +0800 Subject: mt76: mt7915: add MU-MIMO support Enable MU-MIMO DL/UL and add relative counters in debugfs. Currently MU modules read WTBL first to notify BA changes to other cross modules, so adjust mt7915_mcu_sta_ba() accordingly. Tested-by: Evelyn Tsai Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/debugfs.c | 9 ++- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 77 ++++++++++++++++++++-- drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 6 +- drivers/net/wireless/mediatek/mt76/mt7915/regs.h | 5 ++ 4 files changed, 87 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 5278bee812f1..95e073c02ce6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -178,7 +178,14 @@ mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s) seq_printf(s, "Tx Beamformee feedback triggered counts: %ld\n", FIELD_GET(MT_ETBF_TX_FB_TRI, cnt)); - /* Tx SU counters */ + /* Tx SU & MU counters */ + cnt = mt76_rr(dev, MT_MIB_SDR34(ext_phy)); + seq_printf(s, "Tx multi-user Beamforming counts: %ld\n", + FIELD_GET(MT_MIB_MU_BF_TX_CNT, cnt)); + cnt = mt76_rr(dev, MT_MIB_DR8(ext_phy)); + seq_printf(s, "Tx multi-user MPDU counts: %d\n", cnt); + cnt = mt76_rr(dev, MT_MIB_DR9(ext_phy)); + seq_printf(s, "Tx multi-user successful MPDU counts: %d\n", cnt); cnt = mt76_rr(dev, MT_MIB_DR11(ext_phy)); seq_printf(s, "Tx single-user successful MPDU counts: %d\n", cnt); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index c8c12c740c1a..ca3e700425b6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1166,19 +1166,31 @@ mt7915_mcu_sta_ba(struct mt7915_dev *dev, struct wtbl_req_hdr *wtbl_hdr; struct tlv *sta_wtbl; struct sk_buff *skb; + int ret; skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, MT7915_STA_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); - mt7915_mcu_sta_ba_tlv(skb, params, enable, tx); sta_wtbl = mt7915_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); wtbl_hdr = mt7915_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, sta_wtbl, &skb); mt7915_mcu_wtbl_ba_tlv(skb, params, enable, tx, sta_wtbl, wtbl_hdr); + ret = __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_STA_REC_UPDATE, true); + 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); + + mt7915_mcu_sta_ba_tlv(skb, params, enable, tx); + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_STA_REC_UPDATE, true); } @@ -1466,16 +1478,39 @@ 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) +{ + 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); + + if (!sta->vht_cap.vht_supported && !sta->he_cap.has_he) + return 0; + + 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); +} + static void mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb, struct ieee80211_sta *sta) { struct tlv *tlv; + /* starec ht */ if (sta->ht_cap.ht_supported) { struct sta_rec_ht *ht; - /* starec ht */ tlv = mt7915_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); ht = (struct sta_rec_ht *)tlv; ht->ht_cap = cpu_to_le16(sta->ht_cap.cap); @@ -1495,10 +1530,6 @@ mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb, /* starec he */ if (sta->he_cap.has_he) mt7915_mcu_sta_he_tlv(skb, sta); - - /* starec muru */ - if (sta->he_cap.has_he || sta->vht_cap.vht_supported) - mt7915_mcu_sta_muru_tlv(skb, sta); } static void @@ -2064,6 +2095,32 @@ int mt7915_mcu_add_rate_ctrl(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), + }; + + 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) { @@ -2073,10 +2130,18 @@ 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; + ret = mt7915_mcu_add_mu(dev, vif, sta); + if (ret) + return ret; + if (enable) return mt7915_mcu_add_rate_ctrl(dev, vif, sta); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index c241dd7c4c36..cb35e718409a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -201,6 +201,7 @@ enum { MCU_EXT_CMD_EDCA_UPDATE = 0x27, MCU_EXT_CMD_DEV_INFO_UPDATE = 0x2A, MCU_EXT_CMD_THERMAL_CTRL = 0x2c, + MCU_EXT_CMD_SET_DRR_CTRL = 0x36, MCU_EXT_CMD_SET_RDD_CTRL = 0x3a, MCU_EXT_CMD_PROTECT_CTRL = 0x3e, MCU_EXT_CMD_MAC_INIT_CTRL = 0x46, @@ -653,7 +654,7 @@ struct sta_rec_muru { bool ofdma_ul_en; bool mimo_dl_en; bool mimo_ul_en; - bool rsv[4]; + u8 rsv[4]; } cfg; struct { @@ -664,7 +665,7 @@ struct sta_rec_muru { bool lt16_sigb; bool rx_su_comp_sigb; bool rx_su_non_comp_sigb; - bool rsv; + u8 rsv; } ofdma_dl; struct { @@ -951,7 +952,6 @@ enum { sizeof(struct sta_rec_ba) + \ sizeof(struct sta_rec_vht) + \ sizeof(struct tlv) + \ - sizeof(struct sta_rec_muru) + \ MT7915_WTBL_UPDATE_MAX_SIZE) #define MT7915_WTBL_UPDATE_BA_SIZE (sizeof(struct wtbl_req_hdr) + \ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index c121715f8bff..e0989141d9da 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -117,11 +117,16 @@ #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) #define MT_MIB_MB_SDR0(_band, n) MT_WF_MIB(_band, 0x100 + ((n) << 4)) -- cgit v1.2.3 From 80c9934004046a99f29ec89140556a2733641783 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Mon, 15 Jun 2020 02:23:36 +0800 Subject: mt76: mt7915: use ieee80211_tx_queue_params to avoid open coded This is easy to add MU EDCA parameters in the future. This patch also fixes a wrong cw_min assignment. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 6 +----- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 14 +++++++------- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 9 ++------- 3 files changed, 10 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index e09899748c9b..0c1217d3acd8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -355,11 +355,7 @@ mt7915_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, /* no need to update right away, we'll get BSS_CHANGED_QOS */ queue = mt7915_lmac_mapping(dev, queue); - - mvif->wmm[queue].cw_min = params->cw_min; - mvif->wmm[queue].cw_max = params->cw_max; - mvif->wmm[queue].aifs = params->aifs; - mvif->wmm[queue].txop = params->txop; + mvif->queue_params[queue] = *params; return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index ca3e700425b6..fa9f32fa9f2e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -2888,23 +2888,23 @@ int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif) int ac; for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac]; struct edca *e = &req.edca[ac]; e->queue = ac + mvif->wmm_idx * MT7915_MAX_WMM_SETS; - e->aifs = mvif->wmm[ac].aifs; - e->txop = cpu_to_le16(mvif->wmm[ac].txop); + e->aifs = q->aifs; + e->txop = cpu_to_le16(q->txop); - if (mvif->wmm[ac].cw_min) - e->cw_min = fls(mvif->wmm[ac].cw_max); + if (q->cw_min) + e->cw_min = fls(q->cw_min); else e->cw_min = 5; - if (mvif->wmm[ac].cw_max) - e->cw_max = cpu_to_le16(fls(mvif->wmm[ac].cw_max)); + if (q->cw_max) + e->cw_max = cpu_to_le16(fls(q->cw_max)); else e->cw_max = cpu_to_le16(10); } - return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, &req, sizeof(req), true); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index b3b00d099236..4a063c1e5ea2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -99,15 +99,10 @@ struct mt7915_vif { u8 band_idx; u8 wmm_idx; - struct { - u16 cw_min; - u16 cw_max; - u16 txop; - u8 aifs; - } wmm[IEEE80211_NUM_ACS]; - struct mt7915_sta sta; struct mt7915_dev *dev; + + struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; }; struct mib_stats { -- cgit v1.2.3 From dc076af55b86b4992114f6b3b889fbc96c5d4fd4 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Mon, 22 Jun 2020 10:16:55 +0800 Subject: mt76: mt7915: overwrite qid for non-bufferable mgmt frames Overwrite hw queue id for non-bufferable management frames if the hw/fw support always txq (altxq) in order to be in sync with mac txwi code Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/dma.c | 21 +++++++++++---------- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 15 ++++++++------- drivers/net/wireless/mediatek/mt76/mt7915/pci.c | 2 +- 3 files changed, 20 insertions(+), 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c index 766185d1aa21..a8832c5e6004 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -79,26 +79,27 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, } } +static void +mt7915_tx_cleanup(struct mt7915_dev *dev) +{ + mt76_queue_tx_cleanup(dev, MT_TXQ_MCU, false); + mt76_queue_tx_cleanup(dev, MT_TXQ_MCU_WA, false); + mt76_queue_tx_cleanup(dev, MT_TXQ_PSD, false); + mt76_queue_tx_cleanup(dev, MT_TXQ_BE, false); +} + static int mt7915_poll_tx(struct napi_struct *napi, int budget) { - static const u8 queue_map[] = { - MT_TXQ_MCU, - MT_TXQ_MCU_WA, - MT_TXQ_BE - }; struct mt7915_dev *dev; - int i; dev = container_of(napi, struct mt7915_dev, mt76.tx_napi); - for (i = 0; i < ARRAY_SIZE(queue_map); i++) - mt76_queue_tx_cleanup(dev, queue_map[i], false); + mt7915_tx_cleanup(dev); if (napi_complete_done(napi, 0)) mt7915_irq_enable(dev, MT_INT_TX_DONE_ALL); - for (i = 0; i < ARRAY_SIZE(queue_map); i++) - mt76_queue_tx_cleanup(dev, queue_map[i], false); + mt7915_tx_cleanup(dev); mt7915_mac_sta_poll(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 660e1820cccf..822540e5df6b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -591,16 +591,16 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2; fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4; - if (ieee80211_is_data(fc) || ieee80211_is_bufferable_mmpdu(fc)) { - q_idx = wmm_idx * MT7915_MAX_WMM_SETS + - mt7915_lmac_mapping(dev, skb_get_queue_mapping(skb)); - p_fmt = MT_TX_TYPE_CT; - } else if (beacon) { - q_idx = MT_LMAC_BCN0; + if (beacon) { p_fmt = MT_TX_TYPE_FW; - } else { + q_idx = MT_LMAC_BCN0; + } else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) { + p_fmt = MT_TX_TYPE_CT; q_idx = MT_LMAC_ALTX0; + } else { p_fmt = MT_TX_TYPE_CT; + q_idx = wmm_idx * MT7915_MAX_WMM_SETS + + mt7915_lmac_mapping(dev, skb_get_queue_mapping(skb)); } val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) | @@ -616,6 +616,7 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, FIELD_PREP(MT_TXD1_TID, skb->priority & IEEE80211_QOS_CTL_TID_MASK) | FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); + if (ext_phy && q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0) val |= MT_TXD1_TGID; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c index 7937c6965f59..0ec4e184b889 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c @@ -103,7 +103,7 @@ static int mt7915_pci_probe(struct pci_dev *pdev, static const struct mt76_driver_ops drv_ops = { /* txwi_size = txd size + txp size */ .txwi_size = MT_TXD_SIZE + sizeof(struct mt7915_txp), - .drv_flags = MT_DRV_TXWI_NO_FREE, + .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ, .survey_flags = SURVEY_INFO_TIME_TX | SURVEY_INFO_TIME_RX | SURVEY_INFO_TIME_BSS_RX, -- cgit v1.2.3 From 6ed942af4f68173eb511bc342d53f2593182d449 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 18 Jun 2020 19:00:23 +0200 Subject: mt76: mt76x2e: rename routines in pci.c Rely on mt76x2e prefix in mt76x2/pci.c and align to the rest of mt76 code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2/pci.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c index 53ca0cedf026..f36c71c1bc58 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c @@ -9,7 +9,7 @@ #include "mt76x2.h" -static const struct pci_device_id mt76pci_device_table[] = { +static const struct pci_device_id mt76x2e_device_table[] = { { PCI_DEVICE(0x14c3, 0x7662) }, { PCI_DEVICE(0x14c3, 0x7612) }, { PCI_DEVICE(0x14c3, 0x7602) }, @@ -17,7 +17,7 @@ static const struct pci_device_id mt76pci_device_table[] = { }; static int -mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +mt76x2e_probe(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct mt76_driver_ops drv_ops = { .txwi_size = sizeof(struct mt76x02_txwi), @@ -93,7 +93,7 @@ error: } static void -mt76pci_remove(struct pci_dev *pdev) +mt76x2e_remove(struct pci_dev *pdev) { struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); @@ -103,16 +103,16 @@ mt76pci_remove(struct pci_dev *pdev) mt76_free_device(mdev); } -MODULE_DEVICE_TABLE(pci, mt76pci_device_table); +MODULE_DEVICE_TABLE(pci, mt76x2e_device_table); MODULE_FIRMWARE(MT7662_FIRMWARE); MODULE_FIRMWARE(MT7662_ROM_PATCH); MODULE_LICENSE("Dual BSD/GPL"); static struct pci_driver mt76pci_driver = { .name = KBUILD_MODNAME, - .id_table = mt76pci_device_table, - .probe = mt76pci_probe, - .remove = mt76pci_remove, + .id_table = mt76x2e_device_table, + .probe = mt76x2e_probe, + .remove = mt76x2e_remove, }; module_pci_driver(mt76pci_driver); -- cgit v1.2.3 From 5bb923c767a4d2b4c20e7d4f437e35754ccd6554 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 17 Jun 2020 15:21:39 +0200 Subject: mt76: mt7615: schedule tx tasklet and sta poll on mac tx free Unlike on earlier chips, DMA completion on MT7615 does not imply actually having sent out any packets. Since AQL will prevent filling the hardware queues and will only allow more packets to be passed to the driver after tx completion, it makes much more sense to schedule the tx tasklet there. This is also needed for scheduling tx in testmode support Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/dma.c | 4 ---- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 6 ++++++ 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c index e5a965df899a..1231a5ddf9ea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c @@ -122,10 +122,6 @@ static int mt7615_poll_tx(struct napi_struct *napi, int budget) mt7615_tx_cleanup(dev); - rcu_read_lock(); - mt7615_mac_sta_poll(dev); - rcu_read_unlock(); - tasklet_schedule(&dev->mt76.tx_tasklet); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index d150fac50c00..1dc291e8b766 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1399,6 +1399,12 @@ static void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb) } dev_kfree_skb(skb); + + rcu_read_lock(); + mt7615_mac_sta_poll(dev); + rcu_read_unlock(); + + tasklet_schedule(&dev->mt76.tx_tasklet); } void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, -- cgit v1.2.3 From 557b5a17476893e2f40fd8e66eb46362804df2f5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 17 Jun 2020 20:44:23 +0200 Subject: mt76: mt7615: add support for accessing mapped registers via bus ops Makes it possible to read/write them via debugfs, similar to mt7603 Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mmio.c | 46 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 1 + 2 files changed, 47 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c index 2e99845b9c96..07ad64e4a77a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c @@ -140,6 +140,38 @@ static void mt7615_irq_tasklet(unsigned long data) mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); } +static u32 __mt7615_reg_addr(struct mt7615_dev *dev, u32 addr) +{ + if (addr < 0x100000) + return addr; + + return mt7615_reg_map(dev, addr); +} + +static u32 mt7615_rr(struct mt76_dev *mdev, u32 offset) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + u32 addr = __mt7615_reg_addr(dev, offset); + + return dev->bus_ops->rr(mdev, addr); +} + +static void mt7615_wr(struct mt76_dev *mdev, u32 offset, u32 val) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + u32 addr = __mt7615_reg_addr(dev, offset); + + dev->bus_ops->wr(mdev, addr, val); +} + +static u32 mt7615_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + u32 addr = __mt7615_reg_addr(dev, offset); + + return dev->bus_ops->rmw(mdev, addr, mask, val); +} + int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, int irq, const u32 *map) { @@ -159,6 +191,7 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, .sta_remove = mt7615_mac_sta_remove, .update_survey = mt7615_update_channel, }; + struct mt76_bus_ops *bus_ops; struct ieee80211_ops *ops; struct mt7615_dev *dev; struct mt76_dev *mdev; @@ -182,6 +215,19 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, (mt76_rr(dev, MT_HW_REV) & 0xff); dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev); + dev->bus_ops = dev->mt76.bus; + bus_ops = devm_kmemdup(dev->mt76.dev, dev->bus_ops, sizeof(*bus_ops), + GFP_KERNEL); + if (!bus_ops) { + ret = -ENOMEM; + goto error; + } + + bus_ops->rr = mt7615_rr; + bus_ops->wr = mt7615_wr; + bus_ops->rmw = mt7615_rmw; + dev->mt76.bus = bus_ops; + ret = devm_request_irq(mdev->dev, irq, mt7615_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 913dac5c3006..78cc2a2c31f7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -240,6 +240,7 @@ struct mt7615_dev { struct mt76_phy mphy; }; + const struct mt76_bus_ops *bus_ops; struct tasklet_struct irq_tasklet; struct mt7615_phy phy; -- cgit v1.2.3 From dc80405868e4d8ac94209cbdeb1e4de5b4991a01 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 18 Jun 2020 20:33:32 +0200 Subject: mt76: mt7615: add support for accessing RF registers via MCU Includes debugfs files for testing it. Will be used for testmode support. Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7615/debugfs.c | 28 ++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 43 +++++++++++++++++++++- drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 4 +- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 5 +++ 4 files changed, 77 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index d06afcf46d67..8bb7c64db738 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -285,6 +285,29 @@ mt7615_queues_read(struct seq_file *s, void *data) return 0; } +static int +mt7615_rf_reg_set(void *data, u64 val) +{ + struct mt7615_dev *dev = data; + + mt7615_rf_wr(dev, dev->debugfs_rf_wf, dev->debugfs_rf_reg, val); + + return 0; +} + +static int +mt7615_rf_reg_get(void *data, u64 *val) +{ + struct mt7615_dev *dev = data; + + *val = mt7615_rf_rr(dev, dev->debugfs_rf_wf, dev->debugfs_rf_reg); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_rf_reg, mt7615_rf_reg_get, mt7615_rf_reg_set, + "0x%08llx\n"); + int mt7615_init_debugfs(struct mt7615_dev *dev) { struct dentry *dir; @@ -324,6 +347,11 @@ int mt7615_init_debugfs(struct mt7615_dev *dev) debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir, mt7615_read_temperature); + debugfs_create_u32("rf_wfidx", 0600, dir, &dev->debugfs_rf_wf); + debugfs_create_u32("rf_regidx", 0600, dir, &dev->debugfs_rf_reg); + debugfs_create_file_unsafe("rf_regval", 0600, dir, dev, + &fops_rf_reg); + return 0; } EXPORT_SYMBOL_GPL(mt7615_init_debugfs); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index d3a8ada3b779..b4440f131925 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -151,8 +151,11 @@ void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb, break; default: mcu_txd->cid = MCU_CMD_EXT_CID; - mcu_txd->set_query = MCU_Q_SET; - mcu_txd->ext_cid = cmd; + if (cmd & MCU_QUERY_PREFIX) + mcu_txd->set_query = MCU_Q_QUERY; + else + mcu_txd->set_query = MCU_Q_SET; + mcu_txd->ext_cid = mcu_cmd; mcu_txd->ext_cid_ack = 1; break; } @@ -192,6 +195,10 @@ mt7615_mcu_parse_response(struct mt7615_dev *dev, int cmd, skb_pull(skb, sizeof(*rxd)); ret = le32_to_cpu(*(__le32 *)skb->data); break; + case MCU_EXT_CMD_RF_REG_ACCESS | MCU_QUERY_PREFIX: + skb_pull(skb, sizeof(*rxd)); + ret = le32_to_cpu(*(__le32 *)&skb->data[8]); + break; case MCU_UNI_CMD_DEV_INFO_UPDATE: case MCU_UNI_CMD_BSS_INFO_UPDATE: case MCU_UNI_CMD_STA_REC_UPDATE: @@ -271,6 +278,38 @@ int mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, } EXPORT_SYMBOL_GPL(mt7615_mcu_msg_send); +u32 mt7615_rf_rr(struct mt7615_dev *dev, u32 wf, u32 reg) +{ + struct { + __le32 wifi_stream; + __le32 address; + __le32 data; + } req = { + .wifi_stream = cpu_to_le32(wf), + .address = cpu_to_le32(reg), + }; + + return __mt76_mcu_send_msg(&dev->mt76, + MCU_EXT_CMD_RF_REG_ACCESS | MCU_QUERY_PREFIX, + &req, sizeof(req), true); +} + +int mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val) +{ + struct { + __le32 wifi_stream; + __le32 address; + __le32 data; + } req = { + .wifi_stream = cpu_to_le32(wf), + .address = cpu_to_le32(reg), + .data = cpu_to_le32(val), + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RF_REG_ACCESS, &req, + sizeof(req), false); +} + static void mt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 4f70c4de69a4..8e2be150a556 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -238,8 +238,9 @@ enum { #define MCU_FW_PREFIX BIT(31) #define MCU_UNI_PREFIX BIT(30) #define MCU_CE_PREFIX BIT(29) +#define MCU_QUERY_PREFIX BIT(28) #define MCU_CMD_MASK ~(MCU_FW_PREFIX | MCU_UNI_PREFIX | \ - MCU_CE_PREFIX) + MCU_CE_PREFIX | MCU_QUERY_PREFIX) enum { MCU_CMD_TARGET_ADDRESS_LEN_REQ = MCU_FW_PREFIX | 0x01, @@ -254,6 +255,7 @@ enum { }; enum { + MCU_EXT_CMD_RF_REG_ACCESS = 0x02, MCU_EXT_CMD_PM_STATE_CTRL = 0x07, MCU_EXT_CMD_CHANNEL_SWITCH = 0x08, MCU_EXT_CMD_SET_TX_POWER_CTRL = 0x11, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 78cc2a2c31f7..6e423f45b63f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -281,6 +281,9 @@ struct mt7615_dev { struct work_struct wtbl_work; struct list_head wd_head; + + u32 debugfs_rf_wf; + u32 debugfs_rf_reg; }; enum tx_pkt_queue_idx { @@ -522,6 +525,8 @@ u32 mt7615_mac_get_sta_tid_sn(struct mt7615_dev *dev, int wcid, u8 tid); int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq); int mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, int len, bool wait_resp); +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_set_mac_enable(struct mt7615_dev *dev, int band, bool enable); -- cgit v1.2.3 From b8c978663efb3991369b4944f79b098fc7ebb4e4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 18 Jun 2020 20:38:45 +0200 Subject: mt76: mt7615: use full on-chip memory address for WF_PHY registers Now that the bus access functions can use mapping for accessing full register addresses, use it for WF_PHY registers to keep them constant. Needed for follow-up work on testmode support Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mmio.c | 2 -- drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 3 +-- drivers/net/wireless/mediatek/mt76/mt7615/usb.c | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c index 07ad64e4a77a..461ac6c42271 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c @@ -17,7 +17,6 @@ const u32 mt7615e_reg_map[] = { [MT_CSR_BASE] = 0x07000, [MT_PLE_BASE] = 0x08000, [MT_PSE_BASE] = 0x0c000, - [MT_PHY_BASE] = 0x10000, [MT_CFG_BASE] = 0x20200, [MT_AGG_BASE] = 0x20a00, [MT_TMAC_BASE] = 0x21000, @@ -44,7 +43,6 @@ const u32 mt7663e_reg_map[] = { [MT_CSR_BASE] = 0x07000, [MT_PLE_BASE] = 0x08000, [MT_PSE_BASE] = 0x0c000, - [MT_PHY_BASE] = 0x10000, [MT_CFG_BASE] = 0x20000, [MT_AGG_BASE] = 0x22000, [MT_TMAC_BASE] = 0x24000, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index f0b36b162bf3..4743c12005a4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -14,7 +14,6 @@ enum mt7615_reg_base { MT_CSR_BASE, MT_PLE_BASE, MT_PSE_BASE, - MT_PHY_BASE, MT_CFG_BASE, MT_AGG_BASE, MT_TMAC_BASE, @@ -169,7 +168,7 @@ enum mt7615_reg_base { #define MT_PSE_PG_INFO MT_PSE(0x194) #define MT_PSE_SRC_CNT GENMASK(27, 16) -#define MT_WF_PHY_BASE ((dev)->reg_map[MT_PHY_BASE]) +#define MT_WF_PHY_BASE 0x82070000 #define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs)) #define MT_WF_PHY_WF2_RFCTRL0(n) MT_WF_PHY(0x1900 + (n) * 0x400) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c index f5dc1b828518..0ba28d37c414 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -25,7 +25,6 @@ static const u32 mt7663u_reg_map[] = { [MT_TOP_MISC_BASE] = 0x81020000, [MT_PLE_BASE] = 0x82060000, [MT_PSE_BASE] = 0x82068000, - [MT_PHY_BASE] = 0x82070000, [MT_WTBL_BASE_ADDR] = 0x820e0000, [MT_CFG_BASE] = 0x820f0000, [MT_AGG_BASE] = 0x820f2000, -- cgit v1.2.3 From beffe070b1880e7c53e3fc76f2e4e8f31d18f7c5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 11 Jun 2020 17:45:58 +0200 Subject: mt76: vif_mask to struct mt76_phy All drivers use this in pretty much the same way. Moving it to core helps with some checks for the upcoming testmode support Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt7603/main.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h | 2 -- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 1 - drivers/net/wireless/mediatek/mt76/mt76x02.h | 1 - drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 8 ++++---- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 1 - 10 files changed, 16 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 3d7db6ffb599..ece462e9c9ab 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -491,6 +491,8 @@ struct mt76_phy { struct mt76_sband sband_2g; struct mt76_sband sband_5g; + u32 vif_mask; + int txpower_cur; u8 antenna_mask; }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 83dfa6da4761..447f2c63ef38 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -44,7 +44,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mutex_lock(&dev->mt76.mutex); - mvif->idx = ffs(~dev->vif_mask) - 1; + mvif->idx = ffs(~dev->mphy.vif_mask) - 1; if (mvif->idx >= MT7603_MAX_INTERFACES) { ret = -ENOSPC; goto out; @@ -65,7 +65,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } idx = MT7603_WTBL_RESERVED - 1 - mvif->idx; - dev->vif_mask |= BIT(mvif->idx); + dev->mphy.vif_mask |= BIT(mvif->idx); INIT_LIST_HEAD(&mvif->sta.poll_list); mvif->sta.wcid.idx = idx; mvif->sta.wcid.hw_key_idx = -1; @@ -107,7 +107,7 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) spin_unlock_bh(&dev->sta_poll_lock); mutex_lock(&dev->mt76.mutex); - dev->vif_mask &= ~BIT(mvif->idx); + dev->mphy.vif_mask &= ~BIT(mvif->idx); mutex_unlock(&dev->mt76.mutex); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h index 7fadf094e9be..c86305241e66 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h @@ -108,8 +108,6 @@ struct mt7603_dev { u32 rxfilter; - u8 vif_mask; - struct list_head sta_poll_list; spinlock_t sta_poll_lock; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index f8ce485c8d19..abb9853eaa8b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -137,7 +137,7 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, mutex_lock(&dev->mt76.mutex); - mvif->idx = ffs(~dev->vif_mask) - 1; + mvif->idx = ffs(~dev->mphy.vif_mask) - 1; if (mvif->idx >= MT7615_MAX_INTERFACES) { ret = -ENOSPC; goto out; @@ -157,7 +157,7 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, else mvif->wmm_idx = mvif->idx % MT7615_MAX_WMM_SETS; - dev->vif_mask |= BIT(mvif->idx); + dev->mphy.vif_mask |= BIT(mvif->idx); dev->omac_mask |= BIT(mvif->omac_idx); phy->omac_mask |= BIT(mvif->omac_idx); @@ -204,7 +204,7 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw, mt76_txq_remove(&dev->mt76, vif->txq); mutex_lock(&dev->mt76.mutex); - dev->vif_mask &= ~BIT(mvif->idx); + dev->mphy.vif_mask &= ~BIT(mvif->idx); dev->omac_mask &= ~BIT(mvif->omac_idx); phy->omac_mask &= ~BIT(mvif->omac_idx); mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 6e423f45b63f..af86cf6925dd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -244,7 +244,6 @@ struct mt7615_dev { struct tasklet_struct irq_tasklet; struct mt7615_phy phy; - u32 vif_mask; u32 omac_mask; u16 chainmask; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index 4c9bbc7ce023..4660b9691ec3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -80,7 +80,6 @@ struct mt76x02_dev { struct mutex phy_mutex; - u16 vif_mask; u16 chainmask; u8 txdone_seq; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index cbbe986655fe..99611515a093 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -439,7 +439,7 @@ static void mt76x02_reset_state(struct mt76x02_dev *dev) memset(msta, 0, sizeof(*msta)); } - dev->vif_mask = 0; + dev->mphy.vif_mask = 0; dev->mt76.beacon_mask = 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 44822a849eb1..dbd4077ea283 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -305,7 +305,7 @@ mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) unsigned int idx = 0; /* Allow to change address in HW if we create first interface. */ - if (!dev->vif_mask && + if (!dev->mphy.vif_mask && (((vif->addr[0] ^ dev->mt76.macaddr[0]) & ~GENMASK(4, 1)) || memcmp(vif->addr + 1, dev->mt76.macaddr + 1, ETH_ALEN - 1))) mt76x02_mac_setaddr(dev, vif->addr); @@ -330,11 +330,11 @@ mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) idx += 8; /* vif is already set or idx is 8 for AP/Mesh/... */ - if (dev->vif_mask & BIT(idx) || + if (dev->mphy.vif_mask & BIT(idx) || (vif->type != NL80211_IFTYPE_STATION && idx > 7)) return -EBUSY; - dev->vif_mask |= BIT(idx); + dev->mphy.vif_mask |= BIT(idx); mt76x02_vif_init(dev, vif, idx); return 0; @@ -348,7 +348,7 @@ void mt76x02_remove_interface(struct ieee80211_hw *hw, struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; mt76_txq_remove(&dev->mt76, vif->txq); - dev->vif_mask &= ~BIT(mvif->idx); + dev->mphy.vif_mask &= ~BIT(mvif->idx); } EXPORT_SYMBOL_GPL(mt76x02_remove_interface); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 0c1217d3acd8..f95a0b55c4a2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -125,7 +125,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, mutex_lock(&dev->mt76.mutex); - mvif->idx = ffs(~phy->vif_mask) - 1; + mvif->idx = ffs(~phy->mt76->vif_mask) - 1; if (mvif->idx >= MT7915_MAX_INTERFACES) { ret = -ENOSPC; goto out; @@ -150,7 +150,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, if (ret) goto out; - phy->vif_mask |= BIT(mvif->idx); + phy->mt76->vif_mask |= BIT(mvif->idx); phy->omac_mask |= BIT(mvif->omac_idx); idx = MT7915_WTBL_RESERVED - mvif->idx; @@ -194,7 +194,7 @@ static void mt7915_remove_interface(struct ieee80211_hw *hw, mt76_txq_remove(&dev->mt76, vif->txq); mutex_lock(&dev->mt76.mutex); - phy->vif_mask &= ~BIT(mvif->idx); + phy->mt76->vif_mask &= ~BIT(mvif->idx); phy->omac_mask &= ~BIT(mvif->omac_idx); mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 4a063c1e5ea2..d8a13b4a2359 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -120,7 +120,6 @@ struct mt7915_phy { struct ieee80211_sband_iftype_data iftype[2][NUM_NL80211_IFTYPES]; u32 rxfilter; - u32 vif_mask; u32 omac_mask; u16 noise; -- cgit v1.2.3 From f0efa8621550e77492719072d056f30569242b6b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 18 Jun 2020 21:12:24 +0200 Subject: mt76: add API for testmode support This can be used for calibration in the manufacturing process. It supports sending a configurable number of packets with a specific rate and configurable tx power levels / antenna settings. It also supports receiving packets and showing some statistics, including packet counters and detailed RSSI information. It will only be compiled in if CONFIG_NL80211_TESTMODE is enabled Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Makefile | 1 + drivers/net/wireless/mediatek/mt76/dma.c | 6 + drivers/net/wireless/mediatek/mt76/eeprom.c | 5 + drivers/net/wireless/mediatek/mt76/mac80211.c | 7 + drivers/net/wireless/mediatek/mt76/mt76.h | 75 ++++ drivers/net/wireless/mediatek/mt76/testmode.c | 497 ++++++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/testmode.h | 156 ++++++++ drivers/net/wireless/mediatek/mt76/tx.c | 18 + 8 files changed, 765 insertions(+) create mode 100644 drivers/net/wireless/mediatek/mt76/testmode.c create mode 100644 drivers/net/wireless/mediatek/mt76/testmode.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index ef663b873b0b..949b3c8ffa1b 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -9,6 +9,7 @@ mt76-y := \ tx.o agg-rx.o mcu.o mt76-$(CONFIG_PCI) += pci.o +mt76-$(CONFIG_NL80211_TESTMODE) += testmode.o mt76-usb-y := usb.o usb_trace.o diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index f4d6074fe32a..6c25859dd386 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -370,6 +370,12 @@ unmap: tx_info.buf[n].len, DMA_TO_DEVICE); free: +#ifdef CONFIG_NL80211_TESTMODE + /* fix tx_done accounting on queue overflow */ + if (tx_info.skb == dev->test.tx_skb) + dev->test.tx_done--; +#endif + e.skb = tx_info.skb; e.txwi = t; dev->drv->tx_complete_skb(dev, qid, &e); diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index c236e303ccfd..3044e0069991 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -74,6 +74,11 @@ mt76_get_of_eeprom(struct mt76_dev *dev, int len) &data[i]); } +#ifdef CONFIG_NL80211_TESTMODE + dev->test.mtd_name = devm_kstrdup(dev->dev, part, GFP_KERNEL); + dev->test.mtd_offset = offset; +#endif + out_put_node: of_node_put(np); return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index d8533d0c6e81..10e6dbb64996 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -505,6 +505,13 @@ void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) return; } +#ifdef CONFIG_NL80211_TESTMODE + if (dev->test.state == MT76_TM_STATE_RX_FRAMES) { + dev->test.rx_stats.packets[q]++; + if (status->flag & RX_FLAG_FAILED_FCS_CRC) + dev->test.rx_stats.fcs_error[q]++; + } +#endif __skb_queue_tail(&dev->rx_skb[q], skb); } EXPORT_SYMBOL_GPL(mt76_rx); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index ece462e9c9ab..14b3a39cd55a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -15,6 +15,7 @@ #include #include #include "util.h" +#include "testmode.h" #define MT_TX_RING_SIZE 256 #define MT_MCU_RING_SIZE 32 @@ -475,6 +476,47 @@ struct mt76_rx_status { s8 chain_signal[IEEE80211_MAX_CHAINS]; }; +struct mt76_testmode_ops { + int (*set_state)(struct mt76_dev *dev, enum mt76_testmode_state state); + int (*set_params)(struct mt76_dev *dev, struct nlattr **tb, + enum mt76_testmode_state new_state); + int (*dump_stats)(struct mt76_dev *dev, struct sk_buff *msg); +}; + +struct mt76_testmode_data { + enum mt76_testmode_state state; + + u32 param_set[DIV_ROUND_UP(NUM_MT76_TM_ATTRS, 32)]; + struct sk_buff *tx_skb; + + u32 tx_count; + u16 tx_msdu_len; + + u8 tx_rate_mode; + u8 tx_rate_idx; + u8 tx_rate_nss; + u8 tx_rate_sgi; + u8 tx_rate_ldpc; + + u8 tx_antenna_mask; + + u32 freq_offset; + + u8 tx_power[4]; + u8 tx_power_control; + + const char *mtd_name; + u32 mtd_offset; + + u32 tx_pending; + u32 tx_queued; + u32 tx_done; + struct { + u64 packets[__MT_RXQ_MAX]; + u64 fcs_error[__MT_RXQ_MAX]; + } rx_stats; +}; + struct mt76_phy { struct ieee80211_hw *hw; struct mt76_dev *dev; @@ -574,6 +616,11 @@ struct mt76_dev { u32 rxfilter; +#ifdef CONFIG_NL80211_TESTMODE + const struct mt76_testmode_ops *test_ops; + struct mt76_testmode_data test; +#endif + union { struct mt76_mmio mmio; struct mt76_usb usb; @@ -807,6 +854,15 @@ static inline u8 mt76_tx_power_nss_delta(u8 nss) return nss_delta[nss - 1]; } +static inline bool mt76_testmode_enabled(struct mt76_dev *dev) +{ +#ifdef CONFIG_NL80211_TESTMODE + return dev->test.state != MT76_TM_STATE_OFF; +#else + return false; +#endif +} + void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb); void mt76_tx(struct mt76_phy *dev, struct ieee80211_sta *sta, struct mt76_wcid *wcid, struct sk_buff *skb); @@ -879,6 +935,24 @@ void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *mac); void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + void *data, int len); +int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, + struct netlink_callback *cb, void *data, int len); +int mt76_testmode_set_state(struct mt76_dev *dev, enum mt76_testmode_state state); + +static inline void mt76_testmode_reset(struct mt76_dev *dev, bool disable) +{ +#ifdef CONFIG_NL80211_TESTMODE + enum mt76_testmode_state state = MT76_TM_STATE_IDLE; + + if (disable || dev->test.state == MT76_TM_STATE_OFF) + state = MT76_TM_STATE_OFF; + + mt76_testmode_set_state(dev, state); +#endif +} + /* internal */ static inline struct ieee80211_hw * @@ -903,6 +977,7 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, struct napi_struct *napi); void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames); +void mt76_testmode_tx_pending(struct mt76_dev *dev); /* usb */ static inline bool mt76u_urb_error(struct urb *urb) diff --git a/drivers/net/wireless/mediatek/mt76/testmode.c b/drivers/net/wireless/mediatek/mt76/testmode.c new file mode 100644 index 000000000000..75bb02cdfdae --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/testmode.c @@ -0,0 +1,497 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 Felix Fietkau */ +#include "mt76.h" + +static const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = { + [MT76_TM_ATTR_RESET] = { .type = NLA_FLAG }, + [MT76_TM_ATTR_STATE] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_COUNT] = { .type = NLA_U32 }, + [MT76_TM_ATTR_TX_RATE_MODE] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_RATE_NSS] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_RATE_IDX] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_RATE_SGI] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_RATE_LDPC] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_ANTENNA] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_POWER_CONTROL] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_POWER] = { .type = NLA_NESTED }, + [MT76_TM_ATTR_FREQ_OFFSET] = { .type = NLA_U32 }, +}; + +void mt76_testmode_tx_pending(struct mt76_dev *dev) +{ + struct mt76_testmode_data *td = &dev->test; + struct mt76_wcid *wcid = &dev->global_wcid; + struct sk_buff *skb = td->tx_skb; + struct mt76_queue *q; + int qid; + + if (!skb || !td->tx_pending) + return; + + qid = skb_get_queue_mapping(skb); + q = dev->q_tx[qid].q; + + spin_lock_bh(&q->lock); + + while (td->tx_pending > 0 && q->queued < q->ndesc / 2) { + int ret; + + ret = dev->queue_ops->tx_queue_skb(dev, qid, skb_get(skb), wcid, NULL); + if (ret < 0) + break; + + td->tx_pending--; + td->tx_queued++; + } + + dev->queue_ops->kick(dev, q); + + spin_unlock_bh(&q->lock); +} + + +static int +mt76_testmode_tx_init(struct mt76_dev *dev) +{ + struct mt76_testmode_data *td = &dev->test; + struct ieee80211_tx_info *info; + struct ieee80211_hdr *hdr; + struct sk_buff *skb; + u16 fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | + IEEE80211_FCTL_FROMDS; + struct ieee80211_tx_rate *rate; + u8 max_nss = hweight8(dev->phy.antenna_mask); + + if (td->tx_antenna_mask) + max_nss = min_t(u8, max_nss, hweight8(td->tx_antenna_mask)); + + skb = alloc_skb(td->tx_msdu_len, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + dev_kfree_skb(td->tx_skb); + td->tx_skb = skb; + hdr = __skb_put_zero(skb, td->tx_msdu_len); + hdr->frame_control = cpu_to_le16(fc); + memcpy(hdr->addr1, dev->macaddr, sizeof(dev->macaddr)); + memcpy(hdr->addr2, dev->macaddr, sizeof(dev->macaddr)); + memcpy(hdr->addr3, dev->macaddr, sizeof(dev->macaddr)); + + info = IEEE80211_SKB_CB(skb); + info->flags = IEEE80211_TX_CTL_INJECTED | + IEEE80211_TX_CTL_NO_ACK | + IEEE80211_TX_CTL_NO_PS_BUFFER; + rate = &info->control.rates[0]; + rate->count = 1; + rate->idx = td->tx_rate_idx; + + switch (td->tx_rate_mode) { + case MT76_TM_TX_MODE_CCK: + if (dev->phy.chandef.chan->band != NL80211_BAND_2GHZ) + return -EINVAL; + + if (rate->idx > 4) + return -EINVAL; + break; + case MT76_TM_TX_MODE_OFDM: + if (dev->phy.chandef.chan->band != NL80211_BAND_2GHZ) + break; + + if (rate->idx > 8) + return -EINVAL; + + rate->idx += 4; + break; + case MT76_TM_TX_MODE_HT: + if (rate->idx > 8 * max_nss && + !(rate->idx == 32 && + dev->phy.chandef.width >= NL80211_CHAN_WIDTH_40)) + return -EINVAL; + + rate->flags |= IEEE80211_TX_RC_MCS; + break; + case MT76_TM_TX_MODE_VHT: + if (rate->idx > 9) + return -EINVAL; + + if (td->tx_rate_nss > max_nss) + return -EINVAL; + + ieee80211_rate_set_vht(rate, td->tx_rate_idx, td->tx_rate_nss); + rate->flags |= IEEE80211_TX_RC_VHT_MCS; + break; + default: + break; + } + + if (td->tx_rate_sgi) + rate->flags |= IEEE80211_TX_RC_SHORT_GI; + + if (td->tx_rate_ldpc) + info->flags |= IEEE80211_TX_CTL_LDPC; + + if (td->tx_rate_mode >= MT76_TM_TX_MODE_HT) { + switch (dev->phy.chandef.width) { + case NL80211_CHAN_WIDTH_40: + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + break; + case NL80211_CHAN_WIDTH_80: + rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; + break; + case NL80211_CHAN_WIDTH_80P80: + case NL80211_CHAN_WIDTH_160: + rate->flags |= IEEE80211_TX_RC_160_MHZ_WIDTH; + break; + default: + break; + } + } + + skb_set_queue_mapping(skb, IEEE80211_AC_BE); + + return 0; +} + +static void +mt76_testmode_tx_start(struct mt76_dev *dev) +{ + struct mt76_testmode_data *td = &dev->test; + + td->tx_queued = 0; + td->tx_done = 0; + td->tx_pending = td->tx_count; + tasklet_schedule(&dev->tx_tasklet); +} + +static void +mt76_testmode_tx_stop(struct mt76_dev *dev) +{ + struct mt76_testmode_data *td = &dev->test; + + tasklet_disable(&dev->tx_tasklet); + + td->tx_pending = 0; + + tasklet_enable(&dev->tx_tasklet); + + wait_event_timeout(dev->tx_wait, td->tx_done == td->tx_queued, 10 * HZ); + + dev_kfree_skb(td->tx_skb); + td->tx_skb = NULL; +} + +static inline void +mt76_testmode_param_set(struct mt76_testmode_data *td, u16 idx) +{ + td->param_set[idx / 32] |= BIT(idx % 32); +} + +static inline bool +mt76_testmode_param_present(struct mt76_testmode_data *td, u16 idx) +{ + return td->param_set[idx / 32] & BIT(idx % 32); +} + +static void +mt76_testmode_init_defaults(struct mt76_dev *dev) +{ + struct mt76_testmode_data *td = &dev->test; + + if (td->tx_msdu_len > 0) + return; + + td->tx_msdu_len = 1024; + td->tx_count = 1; + td->tx_rate_mode = MT76_TM_TX_MODE_OFDM; + td->tx_rate_nss = 1; +} + +static int +__mt76_testmode_set_state(struct mt76_dev *dev, enum mt76_testmode_state state) +{ + enum mt76_testmode_state prev_state = dev->test.state; + int err; + + if (prev_state == MT76_TM_STATE_TX_FRAMES) + mt76_testmode_tx_stop(dev); + + if (state == MT76_TM_STATE_TX_FRAMES) { + err = mt76_testmode_tx_init(dev); + if (err) + return err; + } + + err = dev->test_ops->set_state(dev, state); + if (err) { + if (state == MT76_TM_STATE_TX_FRAMES) + mt76_testmode_tx_stop(dev); + + return err; + } + + if (state == MT76_TM_STATE_TX_FRAMES) + mt76_testmode_tx_start(dev); + else if (state == MT76_TM_STATE_RX_FRAMES) { + memset(&dev->test.rx_stats, 0, sizeof(dev->test.rx_stats)); + } + + dev->test.state = state; + + return 0; +} + +int mt76_testmode_set_state(struct mt76_dev *dev, enum mt76_testmode_state state) +{ + struct mt76_testmode_data *td = &dev->test; + struct ieee80211_hw *hw = dev->phy.hw; + + if (state == td->state && state == MT76_TM_STATE_OFF) + return 0; + + if (state > MT76_TM_STATE_OFF && + (!test_bit(MT76_STATE_RUNNING, &dev->phy.state) || + !(hw->conf.flags & IEEE80211_CONF_MONITOR))) + return -ENOTCONN; + + if (state != MT76_TM_STATE_IDLE && + td->state != MT76_TM_STATE_IDLE) { + int ret; + + ret = __mt76_testmode_set_state(dev, MT76_TM_STATE_IDLE); + if (ret) + return ret; + } + + return __mt76_testmode_set_state(dev, state); + +} +EXPORT_SYMBOL(mt76_testmode_set_state); + +static int +mt76_tm_get_u8(struct nlattr *attr, u8 *dest, u8 min, u8 max) +{ + u8 val; + + if (!attr) + return 0; + + val = nla_get_u8(attr); + if (val < min || val > max) + return -EINVAL; + + *dest = val; + return 0; +} + +int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + void *data, int len) +{ + struct mt76_phy *phy = hw->priv; + struct mt76_dev *dev = phy->dev; + struct mt76_testmode_data *td = &dev->test; + struct nlattr *tb[NUM_MT76_TM_ATTRS]; + u32 state; + int err; + int i; + + if (!dev->test_ops) + return -EOPNOTSUPP; + + err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len, + mt76_tm_policy, NULL); + if (err) + return err; + + err = -EINVAL; + + mutex_lock(&dev->mutex); + + if (tb[MT76_TM_ATTR_RESET]) { + mt76_testmode_set_state(dev, MT76_TM_STATE_OFF); + memset(td, 0, sizeof(*td)); + } + + mt76_testmode_init_defaults(dev); + + if (tb[MT76_TM_ATTR_TX_COUNT]) + td->tx_count = nla_get_u32(tb[MT76_TM_ATTR_TX_COUNT]); + + if (tb[MT76_TM_ATTR_TX_LENGTH]) { + u32 val = nla_get_u32(tb[MT76_TM_ATTR_TX_LENGTH]); + + if (val > IEEE80211_MAX_FRAME_LEN || + val < sizeof(struct ieee80211_hdr)) + goto out; + + td->tx_msdu_len = val; + } + + if (tb[MT76_TM_ATTR_TX_RATE_IDX]) + td->tx_rate_idx = nla_get_u8(tb[MT76_TM_ATTR_TX_RATE_IDX]); + + if (mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_MODE], &td->tx_rate_mode, + 0, MT76_TM_TX_MODE_MAX) || + mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_NSS], &td->tx_rate_nss, + 1, hweight8(phy->antenna_mask)) || + mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_SGI], &td->tx_rate_sgi, 0, 1) || + mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_LDPC], &td->tx_rate_ldpc, 0, 1) || + mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_ANTENNA], &td->tx_antenna_mask, 1, + phy->antenna_mask) || + mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_POWER_CONTROL], + &td->tx_power_control, 0, 1)) + goto out; + + if (tb[MT76_TM_ATTR_FREQ_OFFSET]) + td->freq_offset = nla_get_u32(tb[MT76_TM_ATTR_FREQ_OFFSET]); + + if (tb[MT76_TM_ATTR_STATE]) { + state = nla_get_u32(tb[MT76_TM_ATTR_STATE]); + if (state > MT76_TM_STATE_MAX) + goto out; + } else { + state = td->state; + } + + if (tb[MT76_TM_ATTR_TX_POWER]) { + struct nlattr *cur; + int idx = 0; + int rem; + + nla_for_each_nested(cur, tb[MT76_TM_ATTR_TX_POWER], rem) { + if (nla_len(cur) != 1 || + idx >= ARRAY_SIZE(td->tx_power)) + goto out; + + td->tx_power[idx++] = nla_get_u8(cur); + } + } + + if (dev->test_ops->set_params) { + err = dev->test_ops->set_params(dev, tb, state); + if (err) + goto out; + } + + for (i = MT76_TM_ATTR_STATE; i < ARRAY_SIZE(tb); i++) + if (tb[i]) + mt76_testmode_param_set(td, i); + + err = 0; + if (tb[MT76_TM_ATTR_STATE]) + err = mt76_testmode_set_state(dev, state); + +out: + mutex_unlock(&dev->mutex); + + return err; +} +EXPORT_SYMBOL(mt76_testmode_cmd); + +static int +mt76_testmode_dump_stats(struct mt76_dev *dev, struct sk_buff *msg) +{ + struct mt76_testmode_data *td = &dev->test; + u64 rx_packets = 0; + u64 rx_fcs_error = 0; + int i; + + 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]; + } + + if (nla_put_u32(msg, MT76_TM_STATS_ATTR_TX_PENDING, td->tx_pending) || + nla_put_u32(msg, MT76_TM_STATS_ATTR_TX_QUEUED, td->tx_queued) || + nla_put_u32(msg, MT76_TM_STATS_ATTR_TX_DONE, td->tx_done) || + nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_PACKETS, rx_packets, + MT76_TM_STATS_ATTR_PAD) || + nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_FCS_ERROR, rx_fcs_error, + MT76_TM_STATS_ATTR_PAD)) + return -EMSGSIZE; + + if (dev->test_ops->dump_stats) + return dev->test_ops->dump_stats(dev, msg); + + return 0; +} + +int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, + struct netlink_callback *cb, void *data, int len) +{ + struct mt76_phy *phy = hw->priv; + struct mt76_dev *dev = phy->dev; + struct mt76_testmode_data *td = &dev->test; + struct nlattr *tb[NUM_MT76_TM_ATTRS] = {}; + int err = 0; + void *a; + int i; + + if (!dev->test_ops) + return -EOPNOTSUPP; + + if (cb->args[2]++ > 0) + return -ENOENT; + + if (data) { + err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len, + mt76_tm_policy, NULL); + if (err) + return err; + } + + mutex_lock(&dev->mutex); + + if (tb[MT76_TM_ATTR_STATS]) { + a = nla_nest_start(msg, MT76_TM_ATTR_STATS); + err = mt76_testmode_dump_stats(dev, msg); + nla_nest_end(msg, a); + + goto out; + } + + mt76_testmode_init_defaults(dev); + + err = -EMSGSIZE; + if (nla_put_u32(msg, MT76_TM_ATTR_STATE, td->state)) + goto out; + + if (td->mtd_name && + (nla_put_string(msg, MT76_TM_ATTR_MTD_PART, td->mtd_name) || + nla_put_u32(msg, MT76_TM_ATTR_MTD_OFFSET, td->mtd_offset))) + goto out; + + if (nla_put_u32(msg, MT76_TM_ATTR_TX_COUNT, td->tx_count) || + nla_put_u32(msg, MT76_TM_ATTR_TX_LENGTH, td->tx_msdu_len) || + nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_MODE, td->tx_rate_mode) || + nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_NSS, td->tx_rate_nss) || + nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_IDX, td->tx_rate_idx) || + nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_SGI, td->tx_rate_sgi) || + nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_LDPC, td->tx_rate_ldpc) || + (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_ANTENNA) && + nla_put_u8(msg, MT76_TM_ATTR_TX_ANTENNA, td->tx_antenna_mask)) || + (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER_CONTROL) && + nla_put_u8(msg, MT76_TM_ATTR_TX_POWER_CONTROL, td->tx_power_control)) || + (mt76_testmode_param_present(td, MT76_TM_ATTR_FREQ_OFFSET) && + nla_put_u8(msg, MT76_TM_ATTR_FREQ_OFFSET, td->freq_offset))) + goto out; + + if (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER)) { + a = nla_nest_start(msg, MT76_TM_ATTR_TX_POWER); + if (!a) + goto out; + + for (i = 0; i < ARRAY_SIZE(td->tx_power); i++) + if (nla_put_u8(msg, i, td->tx_power[i])) + goto out; + + nla_nest_end(msg, a); + } + + err = 0; + +out: + mutex_unlock(&dev->mutex); + + return err; +} +EXPORT_SYMBOL(mt76_testmode_dump); diff --git a/drivers/net/wireless/mediatek/mt76/testmode.h b/drivers/net/wireless/mediatek/mt76/testmode.h new file mode 100644 index 000000000000..691fe5773244 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/testmode.h @@ -0,0 +1,156 @@ +/* SPDX-License-Identifier: ISC */ +/* + * Copyright (C) 2020 Felix Fietkau + */ +#ifndef __MT76_TESTMODE_H +#define __MT76_TESTMODE_H + +/** + * enum mt76_testmode_attr - testmode attributes inside NL80211_ATTR_TESTDATA + * + * @MT76_TM_ATTR_UNSPEC: (invalid attribute) + * + * @MT76_TM_ATTR_RESET: reset parameters to default (flag) + * @MT76_TM_ATTR_STATE: test state (u32), see &enum mt76_testmode_state + * + * @MT76_TM_ATTR_MTD_PART: mtd partition used for eeprom data (string) + * @MT76_TM_ATTR_MTD_OFFSET: offset of eeprom data within the partition (u32) + * + * @MT76_TM_ATTR_TX_COUNT: configured number of frames to send when setting + * state to MT76_TM_STATE_TX_FRAMES (u32) + * @MT76_TM_ATTR_TX_PENDING: pending frames during MT76_TM_STATE_TX_FRAMES (u32) + * @MT76_TM_ATTR_TX_LENGTH: packet tx msdu length (u32) + * @MT76_TM_ATTR_TX_RATE_MODE: packet tx mode (u8, see &enum mt76_testmode_tx_mode) + * @MT76_TM_ATTR_TX_RATE_NSS: packet tx number of spatial streams (u8) + * @MT76_TM_ATTR_TX_RATE_IDX: packet tx rate/MCS index (u8) + * @MT76_TM_ATTR_TX_RATE_SGI: packet tx use short guard interval (u8) + * @MT76_TM_ATTR_TX_RATE_LDPC: packet tx enable LDPC (u8) + * + * @MT76_TM_ATTR_TX_ANTENNA: tx antenna mask (u8) + * @MT76_TM_ATTR_TX_POWER_CONTROL: enable tx power control (u8) + * @MT76_TM_ATTR_TX_POWER: per-antenna tx power array (nested, u8 attrs) + * + * @MT76_TM_ATTR_FREQ_OFFSET: RF frequency offset (u32) + * + * @MT76_TM_ATTR_STATS: statistics (nested, see &enum mt76_testmode_stats_attr) + */ +enum mt76_testmode_attr { + MT76_TM_ATTR_UNSPEC, + + MT76_TM_ATTR_RESET, + MT76_TM_ATTR_STATE, + + MT76_TM_ATTR_MTD_PART, + MT76_TM_ATTR_MTD_OFFSET, + + MT76_TM_ATTR_TX_COUNT, + MT76_TM_ATTR_TX_LENGTH, + MT76_TM_ATTR_TX_RATE_MODE, + MT76_TM_ATTR_TX_RATE_NSS, + MT76_TM_ATTR_TX_RATE_IDX, + MT76_TM_ATTR_TX_RATE_SGI, + MT76_TM_ATTR_TX_RATE_LDPC, + + MT76_TM_ATTR_TX_ANTENNA, + MT76_TM_ATTR_TX_POWER_CONTROL, + MT76_TM_ATTR_TX_POWER, + + MT76_TM_ATTR_FREQ_OFFSET, + + MT76_TM_ATTR_STATS, + + /* keep last */ + NUM_MT76_TM_ATTRS, + MT76_TM_ATTR_MAX = NUM_MT76_TM_ATTRS - 1, +}; + +/** + * enum mt76_testmode_state - statistics attributes + * + * @MT76_TM_STATS_ATTR_TX_PENDING: pending tx frames (u32) + * @MT76_TM_STATS_ATTR_TX_QUEUED: queued tx frames (u32) + * @MT76_TM_STATS_ATTR_TX_QUEUED: completed tx frames (u32) + * + * @MT76_TM_STATS_ATTR_RX_PACKETS: number of rx packets (u64) + * @MT76_TM_STATS_ATTR_RX_FCS_ERROR: number of rx packets with FCS error (u64) + * @MT76_TM_STATS_ATTR_LAST_RX: information about the last received packet + * see &enum mt76_testmode_rx_attr + */ +enum mt76_testmode_stats_attr { + MT76_TM_STATS_ATTR_UNSPEC, + MT76_TM_STATS_ATTR_PAD, + + MT76_TM_STATS_ATTR_TX_PENDING, + MT76_TM_STATS_ATTR_TX_QUEUED, + MT76_TM_STATS_ATTR_TX_DONE, + + MT76_TM_STATS_ATTR_RX_PACKETS, + MT76_TM_STATS_ATTR_RX_FCS_ERROR, + MT76_TM_STATS_ATTR_LAST_RX, + + /* keep last */ + NUM_MT76_TM_STATS_ATTRS, + MT76_TM_STATS_ATTR_MAX = NUM_MT76_TM_STATS_ATTRS - 1, +}; + + +/** + * enum mt76_testmode_rx_attr - packet rx information + * + * @MT76_TM_RX_ATTR_FREQ_OFFSET: frequency offset (s32) + * @MT76_TM_RX_ATTR_RCPI: received channel power indicator (array, u8) + * @MT76_TM_RX_ATTR_IB_RSSI: internal inband RSSI (s8) + * @MT76_TM_RX_ATTR_WB_RSSI: internal wideband RSSI (s8) + */ +enum mt76_testmode_rx_attr { + MT76_TM_RX_ATTR_UNSPEC, + + MT76_TM_RX_ATTR_FREQ_OFFSET, + MT76_TM_RX_ATTR_RCPI, + MT76_TM_RX_ATTR_IB_RSSI, + MT76_TM_RX_ATTR_WB_RSSI, + + /* keep last */ + NUM_MT76_TM_RX_ATTRS, + MT76_TM_RX_ATTR_MAX = NUM_MT76_TM_RX_ATTRS - 1, +}; + +/** + * enum mt76_testmode_state - phy test state + * + * @MT76_TM_STATE_OFF: test mode disabled (normal operation) + * @MT76_TM_STATE_IDLE: test mode enabled, but idle + * @MT76_TM_STATE_TX_FRAMES: send a fixed number of test frames + * @MT76_TM_STATE_RX_FRAMES: receive packets and keep statistics + */ +enum mt76_testmode_state { + MT76_TM_STATE_OFF, + MT76_TM_STATE_IDLE, + MT76_TM_STATE_TX_FRAMES, + MT76_TM_STATE_RX_FRAMES, + + /* keep last */ + NUM_MT76_TM_STATES, + MT76_TM_STATE_MAX = NUM_MT76_TM_STATES - 1, +}; + +/** + * enum mt76_testmode_tx_mode - packet tx phy mode + * + * @MT76_TM_TX_MODE_CCK: legacy CCK mode + * @MT76_TM_TX_MODE_OFDM: legacy OFDM mode + * @MT76_TM_TX_MODE_HT: 802.11n MCS + * @MT76_TM_TX_MODE_VHT: 802.11ac MCS + */ +enum mt76_testmode_tx_mode { + MT76_TM_TX_MODE_CCK, + MT76_TM_TX_MODE_OFDM, + MT76_TM_TX_MODE_HT, + MT76_TM_TX_MODE_VHT, + + /* keep last */ + NUM_MT76_TM_TX_MODES, + MT76_TM_TX_MODE_MAX = NUM_MT76_TM_TX_MODES - 1, +}; + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index f10c98aa883c..5adf92d7a9f3 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -236,6 +236,14 @@ void mt76_tx_complete_skb(struct mt76_dev *dev, struct sk_buff *skb) struct ieee80211_hw *hw; struct sk_buff_head list; +#ifdef CONFIG_NL80211_TESTMODE + if (skb == dev->test.tx_skb) { + dev->test.tx_done++; + if (dev->test.tx_queued == dev->test.tx_done) + wake_up(&dev->tx_wait); + } +#endif + if (!skb->prev) { hw = mt76_tx_status_get_hw(dev, skb); ieee80211_free_txskb(hw, skb); @@ -259,6 +267,11 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta, int qid = skb_get_queue_mapping(skb); bool ext_phy = phy != &dev->phy; + if (mt76_testmode_enabled(dev)) { + ieee80211_free_txskb(phy->hw, skb); + return; + } + if (WARN_ON(qid >= MT_TXQ_PSD)) { qid = MT_TXQ_BE; skb_set_queue_mapping(skb, qid); @@ -579,6 +592,11 @@ void mt76_tx_tasklet(unsigned long data) mt76_txq_schedule_all(&dev->phy); if (dev->phy2) mt76_txq_schedule_all(dev->phy2); + +#ifdef CONFIG_NL80211_TESTMODE + if (dev->test.tx_pending) + mt76_testmode_tx_pending(dev); +#endif } void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta, -- cgit v1.2.3 From 4f0bce1c8888245e006f8c88f44b7419b47a1b4b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 18 Jun 2020 21:14:43 +0200 Subject: mt76: mt7615: implement testmode support Supports sending a configurable number of packets with a specific rate and configurable tx power levels / antenna settings, as well as displaying rx statistics. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/Makefile | 1 + drivers/net/wireless/mediatek/mt76/mt7615/init.c | 8 +- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 36 ++ drivers/net/wireless/mediatek/mt76/mt7615/mac.h | 5 + drivers/net/wireless/mediatek/mt76/mt7615/main.c | 44 ++- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 34 +- drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 6 + drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 18 + drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 17 + .../net/wireless/mediatek/mt76/mt7615/testmode.c | 363 +++++++++++++++++++++ 10 files changed, 523 insertions(+), 9 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/testmode.c (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile index 99f353b8b9aa..d2ad84cb5244 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile @@ -8,6 +8,7 @@ CFLAGS_trace.o := -I$(src) mt7615-common-y := main.o init.o mcu.o eeprom.o mac.o \ debugfs.o trace.o +mt7615-common-$(CONFIG_NL80211_TESTMODE) += testmode.o mt7615e-y := pci.o pci_init.o dma.o pci_mac.o mmio.o mt7615e-$(CONFIG_MT7622_WMAC) += soc.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index e2d80518e5af..2e0840b0e902 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -321,6 +321,7 @@ mt7615_init_wiphy(struct ieee80211_hw *hw) ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN); + ieee80211_hw_set(hw, WANT_MONITOR_VIF); if (is_mt7615(&phy->dev->mt76)) hw->max_tx_fragments = MT_TXP_MAX_BUF_NUM; @@ -405,9 +406,6 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) mphy->sband_2g.sband.n_channels = 0; mphy->hw->wiphy->bands[NL80211_BAND_2GHZ] = NULL; - /* The second interface does not get any packets unless it has a vif */ - ieee80211_hw_set(mphy->hw, WANT_MONITOR_VIF); - ret = mt76_register_phy(mphy); if (ret) ieee80211_free_hw(mphy->hw); @@ -457,5 +455,9 @@ void mt7615_init_device(struct mt7615_dev *dev) IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; mt7615_cap_dbdc_disable(dev); dev->phy.dfs_state = -1; + +#ifdef CONFIG_NL80211_TESTMODE + dev->mt76.test_ops = &mt7615_testmode_ops; +#endif } EXPORT_SYMBOL_GPL(mt7615_init_device); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 1dc291e8b766..2d432d052780 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -186,6 +186,40 @@ mt7615_get_status_freq_info(struct mt7615_dev *dev, struct mt76_phy *mphy, status->freq = ieee80211_channel_to_frequency(chfreq, status->band); } +static void mt7615_mac_fill_tm_rx(struct mt7615_dev *dev, __le32 *rxv) +{ +#ifdef CONFIG_NL80211_TESTMODE + u32 rxv1 = le32_to_cpu(rxv[0]); + u32 rxv3 = le32_to_cpu(rxv[2]); + u32 rxv4 = le32_to_cpu(rxv[3]); + u32 rxv5 = le32_to_cpu(rxv[4]); + u8 cbw = FIELD_GET(MT_RXV1_FRAME_MODE, rxv1); + u8 mode = FIELD_GET(MT_RXV1_TX_MODE, rxv1); + s16 foe = FIELD_GET(MT_RXV5_FOE, rxv5); + u32 foe_const = (BIT(cbw + 1) & 0xf) * 10000; + + if (!mode) { + /* CCK */ + foe &= ~BIT(11); + foe *= 1000; + foe >>= 11; + } else { + if (foe > 2048) + foe -= 4096; + + foe = (foe * foe_const) >> 15; + } + + dev->test.last_freq_offset = foe; + dev->test.last_rcpi[0] = FIELD_GET(MT_RXV4_RCPI0, rxv4); + dev->test.last_rcpi[1] = FIELD_GET(MT_RXV4_RCPI1, rxv4); + dev->test.last_rcpi[2] = FIELD_GET(MT_RXV4_RCPI2, rxv4); + dev->test.last_rcpi[3] = FIELD_GET(MT_RXV4_RCPI3, rxv4); + dev->test.last_ib_rssi = FIELD_GET(MT_RXV3_IB_RSSI, rxv3); + dev->test.last_wb_rssi = FIELD_GET(MT_RXV3_WB_RSSI, rxv3); +#endif +} + static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; @@ -401,6 +435,8 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) status->chain_signal[i]); } + mt7615_mac_fill_tm_rx(dev, rxd); + rxd += 6; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h index 81608ab656b8..169f4e17b5b4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h @@ -100,11 +100,16 @@ enum rx_pkt_type { #define MT_RXV2_GROUP_ID GENMASK(26, 21) #define MT_RXV2_LENGTH GENMASK(20, 0) +#define MT_RXV3_WB_RSSI GENMASK(31, 24) +#define MT_RXV3_IB_RSSI GENMASK(23, 16) + #define MT_RXV4_RCPI3 GENMASK(31, 24) #define MT_RXV4_RCPI2 GENMASK(23, 16) #define MT_RXV4_RCPI1 GENMASK(15, 8) #define MT_RXV4_RCPI0 GENMASK(7, 0) +#define MT_RXV5_FOE GENMASK(11, 0) + #define MT_RXV6_NF3 GENMASK(31, 24) #define MT_RXV6_NF2 GENMASK(23, 16) #define MT_RXV6_NF1 GENMASK(15, 8) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index abb9853eaa8b..3abb33ddab7d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -76,6 +76,8 @@ static void mt7615_stop(struct ieee80211_hw *hw) mutex_lock(&dev->mt76.mutex); + mt76_testmode_reset(&dev->mt76, true); + clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); cancel_delayed_work_sync(&phy->scan_work); @@ -137,6 +139,12 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, mutex_lock(&dev->mt76.mutex); + mt76_testmode_reset(&dev->mt76, true); + + if (vif->type == NL80211_IFTYPE_MONITOR && + is_zero_ether_addr(vif->addr)) + phy->monitor_vif = vif; + mvif->idx = ffs(~dev->mphy.vif_mask) - 1; if (mvif->idx >= MT7615_MAX_INTERFACES) { ret = -ENOSPC; @@ -197,6 +205,13 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw, /* TODO: disable beacon for the bss */ + mutex_lock(&dev->mt76.mutex); + mt76_testmode_reset(&dev->mt76, true); + mutex_unlock(&dev->mt76.mutex); + + if (vif == phy->monitor_vif) + phy->monitor_vif = NULL; + mt7615_mcu_add_dev_info(dev, vif, false); rcu_assign_pointer(dev->mt76.wcid[idx], NULL); @@ -234,7 +249,7 @@ static void mt7615_init_dfs_state(struct mt7615_phy *phy) phy->dfs_state = -1; } -static int mt7615_set_channel(struct mt7615_phy *phy) +int mt7615_set_channel(struct mt7615_phy *phy) { struct mt7615_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; @@ -260,7 +275,7 @@ static int mt7615_set_channel(struct mt7615_phy *phy) mt7615_mac_set_timing(phy); ret = mt7615_dfs_init_radar_detector(phy); mt7615_mac_cca_stats_reset(phy); - mt7615_mcu_set_sku_en(phy, true); + mt7615_mcu_set_sku_en(phy, !mt76_testmode_enabled(&dev->mt76)); mt7615_mac_reset_counters(dev); phy->noise = 0; @@ -271,8 +286,11 @@ out: mutex_unlock(&dev->mt76.mutex); mt76_txq_schedule_all(phy->mt76); - ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work, - MT7615_WATCHDOG_TIME); + + if (!mt76_testmode_enabled(&dev->mt76)) + ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work, + MT7615_WATCHDOG_TIME); + return ret; } @@ -369,6 +387,13 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed) if (changed & (IEEE80211_CONF_CHANGE_CHANNEL | IEEE80211_CONF_CHANGE_POWER)) { +#ifdef CONFIG_NL80211_TESTMODE + if (dev->mt76.test.state != MT76_TM_STATE_OFF) { + mutex_lock(&dev->mt76.mutex); + mt76_testmode_reset(&dev->mt76, false); + mutex_unlock(&dev->mt76.mutex); + } +#endif ieee80211_stop_queues(hw); ret = mt7615_set_channel(phy); ieee80211_wake_queues(hw); @@ -377,6 +402,8 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&dev->mt76.mutex); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { + mt76_testmode_reset(&dev->mt76, true); + if (!(hw->conf.flags & IEEE80211_CONF_MONITOR)) phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; else @@ -419,10 +446,13 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw, MT_WF_RFCR1_DROP_CFACK; u32 flags = 0; + mutex_lock(&dev->mt76.mutex); + #define MT76_FILTER(_flag, _hw) do { \ flags |= *total_flags & FIF_##_flag; \ phy->rxfilter &= ~(_hw); \ - phy->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ + if (!mt76_testmode_enabled(&dev->mt76)) \ + phy->rxfilter |= !(flags & FIF_##_flag) * (_hw);\ } while (0) phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | @@ -455,6 +485,8 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw, mt76_clear(dev, MT_WF_RFCR1(band), ctl_flags); else mt76_set(dev, MT_WF_RFCR1(band), ctl_flags); + + mutex_unlock(&dev->mt76.mutex); } static void mt7615_bss_info_changed(struct ieee80211_hw *hw, @@ -1069,6 +1101,8 @@ const struct ieee80211_ops mt7615_ops = { .sched_scan_stop = mt7615_stop_sched_scan, .remain_on_channel = mt7615_remain_on_channel, .cancel_remain_on_channel = mt7615_cancel_remain_on_channel, + CFG80211_TESTMODE_CMD(mt76_testmode_cmd) + CFG80211_TESTMODE_DUMP(mt76_testmode_dump) #ifdef CONFIG_PM .suspend = mt7615_suspend, .resume = mt7615_resume, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index b4440f131925..445eb81267ef 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2806,6 +2806,14 @@ int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd) .center_chan2 = ieee80211_frequency_to_channel(freq2), }; +#ifdef CONFIG_NL80211_TESTMODE + if (dev->mt76.test.state == MT76_TM_STATE_TX_FRAMES && + dev->mt76.test.tx_antenna_mask) { + req.tx_streams = hweight8(dev->mt76.test.tx_antenna_mask); + req.rx_streams_mask = dev->mt76.test.tx_antenna_mask; + } +#endif + if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && @@ -2817,7 +2825,10 @@ int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd) req.band_idx = phy != &dev->phy; req.bw = mt7615_mcu_chan_bw(chandef); - mt7615_mcu_set_txpower_sku(phy, req.txpower_sku); + if (mt76_testmode_enabled(&dev->mt76)) + memset(req.txpower_sku, 0x3f, 49); + else + mt7615_mcu_set_txpower_sku(phy, req.txpower_sku); return __mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); } @@ -2835,6 +2846,27 @@ int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index) sizeof(req), true); } +int mt7615_mcu_set_test_param(struct mt7615_dev *dev, u8 param, bool test_mode, + u32 val) +{ + struct { + u8 test_mode_en; + u8 param_idx; + u8 _rsv[2]; + + __le32 value; + + u8 pad[8]; + } req = { + .test_mode_en = test_mode, + .param_idx = param, + .value = cpu_to_le32(val), + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_ATE_CTRL, &req, + sizeof(req), false); +} + int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable) { struct mt7615_dev *dev = phy->dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 8e2be150a556..e8c7aa5c35ce 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -268,6 +268,7 @@ enum { MCU_EXT_CMD_GET_TEMP = 0x2c, MCU_EXT_CMD_WTBL_UPDATE = 0x32, MCU_EXT_CMD_SET_RDD_CTRL = 0x3a, + MCU_EXT_CMD_ATE_CTRL = 0x3d, MCU_EXT_CMD_PROTECT_CTRL = 0x3e, MCU_EXT_CMD_DBDC_CTRL = 0x45, MCU_EXT_CMD_MAC_INIT_CTRL = 0x46, @@ -289,6 +290,11 @@ enum { MCU_UNI_CMD_HIF_CTRL = MCU_UNI_PREFIX | 0x07, }; +enum { + MCU_ATE_SET_FREQ_OFFSET = 0xa, + MCU_ATE_SET_TX_POWER_CONTROL = 0x15, +}; + struct mt7615_mcu_uni_event { u8 cid; u8 pad[3]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index af86cf6925dd..a995d41fb9c1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -169,6 +169,8 @@ struct mt7615_phy { struct mt76_phy *mt76; struct mt7615_dev *dev; + struct ieee80211_vif *monitor_vif; + u32 rxfilter; u32 omac_mask; @@ -283,6 +285,17 @@ struct mt7615_dev { u32 debugfs_rf_wf; u32 debugfs_rf_reg; + +#ifdef CONFIG_NL80211_TESTMODE + struct { + u32 *reg_backup; + + s16 last_freq_offset; + u8 last_rcpi[4]; + s8 last_ib_rssi; + s8 last_wb_rssi; + } test; +#endif }; enum tx_pkt_queue_idx { @@ -377,6 +390,7 @@ extern const u32 mt7615e_reg_map[__MT_BASE_MAX]; extern const u32 mt7663e_reg_map[__MT_BASE_MAX]; extern struct pci_driver mt7615_pci_driver; extern struct platform_driver mt7622_wmac_driver; +extern const struct mt76_testmode_ops mt7615_testmode_ops; #ifdef CONFIG_MT7622_WMAC int mt7622_wmac_init(struct mt7615_dev *dev); @@ -488,6 +502,7 @@ void mt7615_init_txpower(struct mt7615_dev *dev, struct ieee80211_supported_band *sband); void mt7615_phy_init(struct mt7615_dev *dev); void mt7615_mac_init(struct mt7615_dev *dev); +int mt7615_set_channel(struct mt7615_phy *phy); int mt7615_mcu_restart(struct mt76_dev *dev); void mt7615_update_channel(struct mt76_dev *mdev); @@ -531,6 +546,7 @@ int mt7615_mcu_set_eeprom(struct mt7615_dev *dev); int mt7615_mcu_set_mac_enable(struct mt7615_dev *dev, int band, bool enable); int mt7615_mcu_set_rts_thresh(struct mt7615_phy *phy, u32 val); int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index); +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, int cmd, int *wait_seq); @@ -569,6 +585,8 @@ int mt7615_mcu_set_pulse_th(struct mt7615_dev *dev, const struct mt7615_dfs_pulse *pulse); int mt7615_mcu_set_radar_th(struct mt7615_dev *dev, int index, const struct mt7615_dfs_pattern *pattern); +int mt7615_mcu_set_test_param(struct mt7615_dev *dev, u8 param, bool test_mode, + u32 val); int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable); int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy); int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 4743c12005a4..32216bfef4b9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -212,6 +212,9 @@ enum mt7615_reg_base { #define MT_WF_PHY_RXTD2_BASE MT_WF_PHY(0x2a00) #define MT_WF_PHY_RXTD2(_n) (MT_WF_PHY_RXTD2_BASE + ((_n) << 2)) +#define MT_WF_PHY_RFINTF3_0(_n) MT_WF_PHY(0x1100 + (_n) * 0x400) +#define MT_WF_PHY_RFINTF3_0_ANT GENMASK(7, 4) + #define MT_WF_CFG_BASE ((dev)->reg_map[MT_CFG_BASE]) #define MT_WF_CFG(ofs) (MT_WF_CFG_BASE + (ofs)) @@ -255,6 +258,13 @@ enum mt7615_reg_base { #define MT_WF_ARB_BASE ((dev)->reg_map[MT_ARB_BASE]) #define MT_WF_ARB(ofs) (MT_WF_ARB_BASE + (ofs)) +#define MT_ARB_RQCR MT_WF_ARB(0x070) +#define MT_ARB_RQCR_RX_START BIT(0) +#define MT_ARB_RQCR_RXV_START BIT(4) +#define MT_ARB_RQCR_RXV_R_EN BIT(7) +#define MT_ARB_RQCR_RXV_T_EN BIT(8) +#define MT_ARB_RQCR_BAND_SHIFT 16 + #define MT_ARB_SCR MT_WF_ARB(0x080) #define MT_ARB_SCR_TX0_DISABLE BIT(8) #define MT_ARB_SCR_RX0_DISABLE BIT(9) @@ -550,4 +560,11 @@ enum mt7615_reg_base { #define MT_WL_RX_BUSY BIT(30) #define MT_WL_TX_BUSY BIT(31) +#define MT_MCU_PTA_BASE 0x81060000 +#define MT_MCU_PTA(_n) (MT_MCU_PTA_BASE + (_n)) + +#define MT_ANT_SWITCH_CON(n) MT_MCU_PTA(0x0c8) +#define MT_ANT_SWITCH_CON_MODE(_n) (GENMASK(4, 0) << (_n * 8)) +#define MT_ANT_SWITCH_CON_MODE1(_n) (GENMASK(3, 0) << (_n * 8)) + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7615/testmode.c new file mode 100644 index 000000000000..1730751133aa --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7615/testmode.c @@ -0,0 +1,363 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 Felix Fietkau */ + +#include "mt7615.h" +#include "eeprom.h" +#include "mcu.h" + +enum { + TM_CHANGED_TXPOWER_CTRL, + TM_CHANGED_TXPOWER, + TM_CHANGED_FREQ_OFFSET, + + /* must be last */ + NUM_TM_CHANGED +}; + + +static const u8 tm_change_map[] = { + [TM_CHANGED_TXPOWER_CTRL] = MT76_TM_ATTR_TX_POWER_CONTROL, + [TM_CHANGED_TXPOWER] = MT76_TM_ATTR_TX_POWER, + [TM_CHANGED_FREQ_OFFSET] = MT76_TM_ATTR_FREQ_OFFSET, +}; + +static const u32 reg_backup_list[] = { + MT_WF_PHY_RFINTF3_0(0), + MT_WF_PHY_RFINTF3_0(1), + MT_WF_PHY_RFINTF3_0(2), + MT_WF_PHY_RFINTF3_0(3), + MT_ANT_SWITCH_CON(2), + MT_ANT_SWITCH_CON(3), + MT_ANT_SWITCH_CON(4), + MT_ANT_SWITCH_CON(6), + MT_ANT_SWITCH_CON(7), + MT_ANT_SWITCH_CON(8), +}; + +static const struct { + u16 wf; + u16 reg; +} rf_backup_list[] = { + { 0, 0x48 }, + { 1, 0x48 }, + { 2, 0x48 }, + { 3, 0x48 }, +}; + +static int +mt7615_tm_set_tx_power(struct mt7615_phy *phy) +{ + struct mt7615_dev *dev = phy->dev; + struct mt76_phy *mphy = phy->mt76; + int i, ret, n_chains = hweight8(mphy->antenna_mask); + struct cfg80211_chan_def *chandef = &mphy->chandef; + int freq = chandef->center_freq1, len, target_chains; + u8 *data, *eep = (u8 *)dev->mt76.eeprom.data; + enum nl80211_band band = chandef->chan->band; + struct sk_buff *skb; + struct { + u8 center_chan; + u8 dbdc_idx; + u8 band; + u8 rsv; + } __packed req_hdr = { + .center_chan = ieee80211_frequency_to_channel(freq), + .band = band, + .dbdc_idx = phy != &dev->phy, + }; + u8 *tx_power = NULL; + + if (dev->mt76.test.state != MT76_TM_STATE_OFF) + tx_power = dev->mt76.test.tx_power; + + len = sizeof(req_hdr) + MT7615_EE_MAX - MT_EE_NIC_CONF_0; + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req_hdr) + len); + if (!skb) + return -ENOMEM; + + skb_put_data(skb, &req_hdr, sizeof(req_hdr)); + data = skb_put_data(skb, eep + MT_EE_NIC_CONF_0, len); + + target_chains = mt7615_ext_pa_enabled(dev, band) ? 1 : n_chains; + for (i = 0; i < target_chains; i++) { + int index; + + ret = mt7615_eeprom_get_target_power_index(dev, chandef->chan, i); + if (ret < 0) + return -EINVAL; + + index = ret - MT_EE_NIC_CONF_0; + if (tx_power && tx_power[i]) + data[ret - MT_EE_NIC_CONF_0] = tx_power[i]; + } + + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_SET_TX_POWER_CTRL, false); +} + +static void +mt7615_tm_reg_backup_restore(struct mt7615_dev *dev) +{ + u32 *b = dev->test.reg_backup; + int n_regs = ARRAY_SIZE(reg_backup_list); + int n_rf_regs = ARRAY_SIZE(rf_backup_list); + int i; + + if (dev->mt76.test.state == MT76_TM_STATE_OFF) { + for (i = 0; i < n_regs; i++) + mt76_wr(dev, reg_backup_list[i], b[i]); + + for (i = 0; i < n_rf_regs; i++) + mt7615_rf_wr(dev, rf_backup_list[i].wf, + rf_backup_list[i].reg, b[n_regs + i]); + return; + } + + if (b) + return; + + b = devm_kzalloc(dev->mt76.dev, 4 * (n_regs + n_rf_regs), + GFP_KERNEL); + if (!b) + return; + + dev->test.reg_backup = b; + for (i = 0; i < n_regs; i++) + b[i] = mt76_rr(dev, reg_backup_list[i]); + for (i = 0; i < n_rf_regs; i++) + b[n_regs + i] = mt7615_rf_rr(dev, rf_backup_list[i].wf, + rf_backup_list[i].reg); +} + + +static void +mt7615_tm_init_phy(struct mt7615_dev *dev, struct mt7615_phy *phy) +{ + unsigned int total_flags = ~0; + + if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) + return; + + mutex_unlock(&dev->mt76.mutex); + mt7615_set_channel(phy); + mt7615_ops.configure_filter(phy->mt76->hw, 0, &total_flags, 0); + mutex_lock(&dev->mt76.mutex); + + mt7615_tm_reg_backup_restore(dev); +} + +static void +mt7615_tm_init(struct mt7615_dev *dev) +{ + mt7615_tm_init_phy(dev, &dev->phy); + + if (dev->mt76.phy2) + mt7615_tm_init_phy(dev, dev->mt76.phy2->priv); +} + +static void +mt7615_tm_set_rx_enable(struct mt7615_dev *dev, bool en) +{ + u32 rqcr_mask = (MT_ARB_RQCR_RX_START | + MT_ARB_RQCR_RXV_START | + MT_ARB_RQCR_RXV_R_EN | + MT_ARB_RQCR_RXV_T_EN) * + (BIT(0) | BIT(MT_ARB_RQCR_BAND_SHIFT)); + + if (en) { + mt76_clear(dev, MT_ARB_SCR, + MT_ARB_SCR_RX0_DISABLE | MT_ARB_SCR_RX1_DISABLE); + mt76_set(dev, MT_ARB_RQCR, rqcr_mask); + } else { + mt76_set(dev, MT_ARB_SCR, + MT_ARB_SCR_RX0_DISABLE | MT_ARB_SCR_RX1_DISABLE); + mt76_clear(dev, MT_ARB_RQCR, rqcr_mask); + } +} + +static void +mt7615_tm_set_tx_antenna(struct mt7615_dev *dev, bool en) +{ + struct mt76_testmode_data *td = &dev->mt76.test; + u8 mask = td->tx_antenna_mask; + int i; + + if (!mask) + return; + + if (!en) + mask = dev->phy.chainmask; + + for (i = 0; i < 4; i++) { + mt76_rmw_field(dev, MT_WF_PHY_RFINTF3_0(i), + MT_WF_PHY_RFINTF3_0_ANT, + td->tx_antenna_mask & BIT(i) ? 0 : 0xa); + + } + + /* 2.4 GHz band */ + mt76_rmw_field(dev, MT_ANT_SWITCH_CON(3), MT_ANT_SWITCH_CON_MODE(0), + (td->tx_antenna_mask & BIT(0)) ? 0x8 : 0x1b); + mt76_rmw_field(dev, MT_ANT_SWITCH_CON(4), MT_ANT_SWITCH_CON_MODE(2), + (td->tx_antenna_mask & BIT(1)) ? 0xe : 0x1b); + mt76_rmw_field(dev, MT_ANT_SWITCH_CON(6), MT_ANT_SWITCH_CON_MODE1(0), + (td->tx_antenna_mask & BIT(2)) ? 0x0 : 0xf); + mt76_rmw_field(dev, MT_ANT_SWITCH_CON(7), MT_ANT_SWITCH_CON_MODE1(2), + (td->tx_antenna_mask & BIT(3)) ? 0x6 : 0xf); + + /* 5 GHz band */ + mt76_rmw_field(dev, MT_ANT_SWITCH_CON(4), MT_ANT_SWITCH_CON_MODE(1), + (td->tx_antenna_mask & BIT(0)) ? 0xd : 0x1b); + mt76_rmw_field(dev, MT_ANT_SWITCH_CON(2), MT_ANT_SWITCH_CON_MODE(3), + (td->tx_antenna_mask & BIT(1)) ? 0x13 : 0x1b); + mt76_rmw_field(dev, MT_ANT_SWITCH_CON(7), MT_ANT_SWITCH_CON_MODE1(1), + (td->tx_antenna_mask & BIT(2)) ? 0x5 : 0xf); + mt76_rmw_field(dev, MT_ANT_SWITCH_CON(8), MT_ANT_SWITCH_CON_MODE1(3), + (td->tx_antenna_mask & BIT(3)) ? 0xb : 0xf); + + for (i = 0; i < 4; i++) { + u32 val; + + val = mt7615_rf_rr(dev, i, 0x48); + val &= ~(0x3ff << 20); + if (td->tx_antenna_mask & BIT(i)) + val |= 3 << 20; + else + val |= (2 << 28) | (2 << 26) | (8 << 20); + mt7615_rf_wr(dev, i, 0x48, val); + } +} + +static void +mt7615_tm_set_tx_frames(struct mt7615_dev *dev, bool en) +{ + struct ieee80211_tx_info *info; + struct sk_buff *skb = dev->mt76.test.tx_skb; + + mt7615_mcu_set_chan_info(&dev->phy, MCU_EXT_CMD_SET_RX_PATH); + mt7615_tm_set_tx_antenna(dev, en); + mt7615_tm_set_rx_enable(dev, !en); + if (!en || !skb) + return; + + info = IEEE80211_SKB_CB(skb); + info->control.vif = dev->phy.monitor_vif; +} + +static void +mt7615_tm_update_params(struct mt7615_dev *dev, u32 changed) +{ + struct mt76_testmode_data *td = &dev->mt76.test; + bool en = dev->mt76.test.state != MT76_TM_STATE_OFF; + + if (changed & BIT(TM_CHANGED_TXPOWER_CTRL)) + mt7615_mcu_set_test_param(dev, MCU_ATE_SET_TX_POWER_CONTROL, + en, en && td->tx_power_control); + if (changed & BIT(TM_CHANGED_FREQ_OFFSET)) + mt7615_mcu_set_test_param(dev, MCU_ATE_SET_FREQ_OFFSET, + en, en ? td->freq_offset : 0); + if (changed & BIT(TM_CHANGED_TXPOWER)) + mt7615_tm_set_tx_power(&dev->phy); +} + +static int +mt7615_tm_set_state(struct mt76_dev *mdev, enum mt76_testmode_state state) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + struct mt76_testmode_data *td = &mdev->test; + enum mt76_testmode_state prev_state = td->state; + + mdev->test.state = state; + + if (prev_state == MT76_TM_STATE_TX_FRAMES) + mt7615_tm_set_tx_frames(dev, false); + else if (state == MT76_TM_STATE_TX_FRAMES) + mt7615_tm_set_tx_frames(dev, true); + + if (state <= MT76_TM_STATE_IDLE) + mt7615_tm_init(dev); + + if ((state == MT76_TM_STATE_IDLE && + prev_state == MT76_TM_STATE_OFF) || + (state == MT76_TM_STATE_OFF && + prev_state == MT76_TM_STATE_IDLE)) { + u32 changed = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) { + u16 cur = tm_change_map[i]; + + if (td->param_set[cur / 32] & BIT(cur % 32)) + changed |= BIT(i); + } + + mt7615_tm_update_params(dev, changed); + } + + return 0; +} + +static int +mt7615_tm_set_params(struct mt76_dev *mdev, struct nlattr **tb, + enum mt76_testmode_state new_state) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + struct mt76_testmode_data *td = &dev->mt76.test; + u32 changed = 0; + int i; + + BUILD_BUG_ON(NUM_TM_CHANGED >= 32); + + if (new_state == MT76_TM_STATE_OFF || + td->state == MT76_TM_STATE_OFF) + return 0; + + if (td->tx_antenna_mask & ~dev->phy.chainmask) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) { + if (tb[tm_change_map[i]]) + changed |= BIT(i); + } + + mt7615_tm_update_params(dev, changed); + + return 0; +} + +static int +mt7615_tm_dump_stats(struct mt76_dev *mdev, struct sk_buff *msg) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + void *rx, *rssi; + int i; + + rx = nla_nest_start(msg, MT76_TM_STATS_ATTR_LAST_RX); + if (!rx) + return -ENOMEM; + + if (nla_put_s32(msg, MT76_TM_RX_ATTR_FREQ_OFFSET, dev->test.last_freq_offset) || + nla_put_s32(msg, MT76_TM_RX_ATTR_IB_RSSI, dev->test.last_ib_rssi) || + nla_put_s32(msg, MT76_TM_RX_ATTR_WB_RSSI, dev->test.last_wb_rssi)) + return -ENOMEM; + + rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_RCPI); + if (!rssi) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(dev->test.last_rcpi); i++) + if (nla_put_u8(msg, i, dev->test.last_rcpi[i])) + return -ENOMEM; + + nla_nest_end(msg, rssi); + + nla_nest_end(msg, rx); + + return 0; +} + +const struct mt76_testmode_ops mt7615_testmode_ops = { + .set_state = mt7615_tm_set_state, + .set_params = mt7615_tm_set_params, + .dump_stats = mt7615_tm_dump_stats, +}; -- cgit v1.2.3 From d9ea74c4131626396c783ad0d2162b13a0c4490c Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Thu, 25 Jun 2020 01:23:17 +0800 Subject: mt76: mt7915: update HE capabilities Sync from SDK to update HE capabilities. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 44 ++++++++++++++---------- 1 file changed, 26 insertions(+), 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index aadf56e80bae..e90d0087e377 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -417,11 +417,6 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, he_cap_elem->mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE; - he_cap_elem->mac_cap_info[1] = - IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_0US | - IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_1; - he_cap_elem->mac_cap_info[2] = - IEEE80211_HE_MAC_CAP2_BSR; he_cap_elem->mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_OMI_CONTROL | IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_RESERVED; @@ -443,27 +438,27 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ; - /* TODO: OFDMA */ - 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] |= IEEE80211_HE_MAC_CAP4_BQR; + he_cap_elem->mac_cap_info[5] |= + IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX; 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[6] |= IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; - he_cap_elem->phy_cap_info[9] |= - IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU; break; case NL80211_IFTYPE_STATION: he_cap_elem->mac_cap_info[0] |= IEEE80211_HE_MAC_CAP0_TWT_REQ; - he_cap_elem->mac_cap_info[3] |= - IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED; + he_cap_elem->mac_cap_info[1] |= + IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US; if (band == NL80211_BAND_2GHZ) he_cap_elem->phy_cap_info[0] |= @@ -473,18 +468,31 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G; he_cap_elem->phy_cap_info[1] |= - IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A; + IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | + IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US; + 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[6] |= + IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB | + IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE | + IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; + he_cap_elem->phy_cap_info[7] |= + IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR | + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI; he_cap_elem->phy_cap_info[8] |= 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_80MHZ_IN_160MHZ_HE_PPDU | + IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484; he_cap_elem->phy_cap_info[9] |= - IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU; + IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM | + IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | + IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU | + 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; break; -#ifdef CONFIG_MAC80211_MESH - case NL80211_IFTYPE_MESH_POINT: - break; -#endif } he_mcs->rx_mcs_80 = cpu_to_le16(mcs_map); -- cgit v1.2.3 From 40ba9a938fb40e69d14c8e102d2c675ccc6868cc Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 29 Jun 2020 17:12:16 +0200 Subject: mt76: mt76x2: fix pci suspend/resume on mt7612e Fix the following mt7612e hw hangs during suspend/resume reported on Dell Vostro 3360 mt76x2e 0000:01:00.0: MCU message 2 (seq 11) timed out mt76x2e 0000:01:00.0: MCU message 30 (seq 12) timed out mt76x2e 0000:01:00.0: MCU message 30 (seq 13) timed out mt76x2e 0000:01:00.0: Firmware Version: 0.0.00 mt76x2e 0000:01:00.0: Build: 1 mt76x2e 0000:01:00.0: Build Time: 201507311614____ mt76x2e 0000:01:00.0: Firmware running! ieee80211 phy0: Hardware restart was requested mt76x2e 0000:01:00.0: MCU message 2 (seq 1) timed out mt76x2e 0000:01:00.0: MCU message 30 (seq 2) timed out mt76x2e 0000:01:00.0: MCU message 30 (seq 3) timed out mt76x2e 0000:01:00.0: Firmware Version: 0.0.00 mt76x2e 0000:01:00.0: Build: 1 mt76x2e 0000:01:00.0: Build Time: 201507311614____ mt76x2e 0000:01:00.0: Firmware running! ieee80211 phy0: Hardware restart was requested mt76x2e 0000:01:00.0: MCU message 31 (seq 5) timed out mt76x2e 0000:01:00.0: MCU message 31 (seq 6) timed out mt76x2e 0000:01:00.0: MCU message 31 (seq 7) timed out mt76x2e 0000:01:00.0: MCU message 31 (seq 8) timed out mt76x2e 0000:01:00.0: MCU message 31 (seq 9) timed out mt76x2e 0000:01:00.0: MCU message 31 (seq 10) timed out mt76x2e 0000:01:00.0: MCU message 31 (seq 11) timed out mt76x2e 0000:01:00.0: Firmware Version: 0.0.00 mt76x2e 0000:01:00.0: Build: 1 mt76x2e 0000:01:00.0: Build Time: 201507311614____ mt76x2e 0000:01:00.0: Firmware running! ieee80211 phy0: Hardware restart was requested ------------[ cut here ]----------- CPU: 3 PID: 11956 Comm: kworker/3:1 Not tainted 5.7.0-pf2 #1 Hardware name: Dell Inc. Vostro 3360/0F5DWF, BIOS A18 09/25/2013 Workqueue: events_freezable ieee80211_restart_work [mac80211] RIP: 0010:ieee80211_reconfig+0x234/0x1700 [mac80211] RSP: 0018:ffffb803c23ffdf0 EFLAGS: 00010286 RAX: 00000000fffffff0 RBX: ffff9595a7564900 RCX: 0000000000000008 RDX: 0000000000000000 RSI: 0000000000000100 RDI: 0000000000000100 RBP: ffff9595a7ec07e0 R08: 0000000000000000 R09: 0000000000000001 R10: 0000000000000001 R11: 0000000000000000 R12: ffff9595a7ec18d0 R13: 00000000ffffffff R14: 0000000000000000 R15: 00000000fffffff0 FS: 0000000000000000(0000) GS:ffff9595af2c0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000055e56d7de000 CR3: 000000042200a001 CR4: 00000000001706e0 Call Trace: ieee80211_restart_work+0xb7/0xe0 [mac80211] process_one_work+0x1d4/0x3c0 worker_thread+0x228/0x470 ? process_one_work+0x3c0/0x3c0 kthread+0x19c/0x1c0 ? __kthread_init_worker+0x30/0x30 ret_from_fork+0x35/0x40 wlp1s0: Failed check-sdata-in-driver check, flags: 0x0 CPU: 3 PID: 11956 Comm: kworker/3:1 Tainted: G W 5.7.0-pf2 #1 Hardware name: Dell Inc. Vostro 3360/0F5DWF, BIOS A18 09/25/2013 Workqueue: events_freezable ieee80211_restart_work [mac80211] RIP: 0010:drv_remove_interface+0x11f/0x130 [mac80211] RSP: 0018:ffffb803c23ffc80 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffff9595a7564900 RCX: 0000000000000000 RDX: 0000000000000001 RSI: 0000000000000082 RDI: 00000000ffffffff RBP: ffff9595a7ec1930 R08: 00000000000004b6 R09: 0000000000000001 R10: 0000000000000001 R11: 0000000000006f08 R12: ffff9595a7ec1000 R13: ffff9595a75654b8 R14: ffff9595a7ec0ca0 R15: ffff9595a7ec07e0 FS: 0000000000000000(0000) GS:ffff9595af2c0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000055e56d7de000 CR3: 000000042200a001 CR4: 00000000001706e0 Call Trace: ieee80211_do_stop+0x5af/0x8c0 [mac80211] ieee80211_stop+0x16/0x20 [mac80211] __dev_close_many+0xaa/0x120 dev_close_many+0xa1/0x2b0 dev_close+0x6d/0x90 cfg80211_shutdown_all_interfaces+0x71/0xd0 [cfg80211] ieee80211_reconfig+0xa2/0x1700 [mac80211] ieee80211_restart_work+0xb7/0xe0 [mac80211] process_one_work+0x1d4/0x3c0 worker_thread+0x228/0x470 ? process_one_work+0x3c0/0x3c0 kthread+0x19c/0x1c0 ? __kthread_init_worker+0x30/0x30 ret_from_fork+0x35/0x40 Fixes: 7bc04215a66b ("mt76: add driver code for MT76x2e") Tested-by: Oleksandr Natalenko Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x2/pci.c | 56 ++++++++++++++++++++++ .../net/wireless/mediatek/mt76/mt76x2/pci_init.c | 17 +++++++ 3 files changed, 74 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index eca95b7f64d2..d01f47c83eb1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -39,6 +39,7 @@ static inline bool mt76x2_channel_silent(struct mt76x02_dev *dev) extern const struct ieee80211_ops mt76x2_ops; int mt76x2_register_device(struct mt76x02_dev *dev); +int mt76x2_resume_device(struct mt76x02_dev *dev); void mt76x2_phy_power_on(struct mt76x02_dev *dev); void mt76x2_stop_hardware(struct mt76x02_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c index f36c71c1bc58..6dfb0df8ec8a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c @@ -103,6 +103,58 @@ mt76x2e_remove(struct pci_dev *pdev) mt76_free_device(mdev); } +static int __maybe_unused +mt76x2e_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + int i, err; + + napi_disable(&mdev->tx_napi); + tasklet_kill(&mdev->pre_tbtt_tasklet); + tasklet_kill(&mdev->tx_tasklet); + + mt76_for_each_q_rx(mdev, i) + napi_disable(&mdev->napi[i]); + + pci_enable_wake(pdev, pci_choose_state(pdev, state), true); + pci_save_state(pdev); + err = pci_set_power_state(pdev, pci_choose_state(pdev, state)); + if (err) + goto restore; + + return 0; + +restore: + mt76_for_each_q_rx(mdev, i) + napi_enable(&mdev->napi[i]); + napi_enable(&mdev->tx_napi); + + return err; +} + +static int __maybe_unused +mt76x2e_resume(struct pci_dev *pdev) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); + int i, err; + + err = pci_set_power_state(pdev, PCI_D0); + if (err) + return err; + + pci_restore_state(pdev); + + mt76_for_each_q_rx(mdev, i) { + napi_enable(&mdev->napi[i]); + napi_schedule(&mdev->napi[i]); + } + napi_enable(&mdev->tx_napi); + napi_schedule(&mdev->tx_napi); + + return mt76x2_resume_device(dev); +} + MODULE_DEVICE_TABLE(pci, mt76x2e_device_table); MODULE_FIRMWARE(MT7662_FIRMWARE); MODULE_FIRMWARE(MT7662_ROM_PATCH); @@ -113,6 +165,10 @@ static struct pci_driver mt76pci_driver = { .id_table = mt76x2e_device_table, .probe = mt76x2e_probe, .remove = mt76x2e_remove, +#ifdef CONFIG_PM + .suspend = mt76x2e_suspend, + .resume = mt76x2e_resume, +#endif /* CONFIG_PM */ }; module_pci_driver(mt76pci_driver); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index f27774f57438..101a0fe00ef3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -217,6 +217,23 @@ mt76x2_power_on(struct mt76x02_dev *dev) mt76x2_power_on_rf(dev, 1); } +int mt76x2_resume_device(struct mt76x02_dev *dev) +{ + int err; + + mt76x02_dma_disable(dev); + mt76x2_reset_wlan(dev, true); + mt76x2_power_on(dev); + + err = mt76x2_mac_reset(dev, true); + if (err) + return err; + + mt76x02_mac_start(dev); + + return mt76x2_mcu_init(dev); +} + static int mt76x2_init_hardware(struct mt76x02_dev *dev) { int ret; -- cgit v1.2.3 From 05b5a339a7b2308ec38563a7da6649ff1f9cc28b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 29 Jun 2020 19:05:33 +0200 Subject: mt76: mt76x2u: enable HC-M7662BU1 Enable support for HC-M7662BU1 module on mt76x2u driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2/usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index 3a4e41724af1..b27acf1bbc03 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -16,6 +16,7 @@ static const struct usb_device_id mt76x2u_device_table[] = { { USB_DEVICE(0x0e8d, 0x7612) }, /* Aukey USBAC1200 - Alfa AWUS036ACM */ { USB_DEVICE(0x057c, 0x8503) }, /* Avm FRITZ!WLAN AC860 */ { USB_DEVICE(0x7392, 0xb711) }, /* Edimax EW 7722 UAC */ + { USB_DEVICE(0x0e8d, 0x7632) }, /* HC-M7662BU1 */ { USB_DEVICE(0x2c4e, 0x0103) }, /* Mercury UD13 */ { USB_DEVICE(0x0846, 0x9053) }, /* Netgear A6210 */ { USB_DEVICE(0x045e, 0x02e6) }, /* XBox One Wireless Adapter */ -- cgit v1.2.3 From 0d4b6909987723f11c23b3a996499cb8f7a0e2b7 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Wed, 1 Jul 2020 16:13:07 +0800 Subject: mt76: mt7915: avoid memcpy in rxv operation Avoid memcpy in Rx hot path to slightly improve performance. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 78 ++++++++++++------------- drivers/net/wireless/mediatek/mt76/mt7915/mac.h | 7 --- 2 files changed, 37 insertions(+), 48 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 822540e5df6b..6825afca1efb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -178,14 +178,14 @@ void mt7915_mac_sta_poll(struct mt7915_dev *dev) static void mt7915_mac_decode_he_radiotap_ru(struct mt76_rx_status *status, - struct mt7915_rxv *rxv, - struct ieee80211_radiotap_he *he) + struct ieee80211_radiotap_he *he, + __le32 *rxv) { u32 ru_h, ru_l; u8 ru, offs = 0; - ru_l = FIELD_GET(MT_PRXV_HE_RU_ALLOC_L, le32_to_cpu(rxv->v[0])); - ru_h = FIELD_GET(MT_PRXV_HE_RU_ALLOC_H, le32_to_cpu(rxv->v[1])); + ru_l = FIELD_GET(MT_PRXV_HE_RU_ALLOC_L, le32_to_cpu(rxv[0])); + ru_h = FIELD_GET(MT_PRXV_HE_RU_ALLOC_H, le32_to_cpu(rxv[1])); ru = (u8)(ru_l | ru_h << 4); status->bw = RATE_INFO_BW_HE_RU; @@ -228,7 +228,7 @@ mt7915_mac_decode_he_radiotap_ru(struct mt76_rx_status *status, static void mt7915_mac_decode_he_radiotap(struct sk_buff *skb, struct mt76_rx_status *status, - struct mt7915_rxv *rxv) + __le32 *rxv, u32 phy) { /* TODO: struct ieee80211_radiotap_he_mu */ static const struct ieee80211_radiotap_he known = { @@ -245,48 +245,45 @@ mt7915_mac_decode_he_radiotap(struct sk_buff *skb, HE_BITS(DATA2_TXOP_KNOWN), }; struct ieee80211_radiotap_he *he = NULL; - __le32 v2 = rxv->v[2]; - __le32 v11 = rxv->v[11]; - __le32 v14 = rxv->v[14]; - u32 ltf_size = le32_get_bits(v2, MT_CRXV_HE_LTF_SIZE) + 1; + u32 ltf_size = le32_get_bits(rxv[2], MT_CRXV_HE_LTF_SIZE) + 1; he = skb_push(skb, sizeof(known)); memcpy(he, &known, sizeof(known)); - he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, v14) | - HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, v2); - he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, v2) | + he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[14]) | + HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[2]); + he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) | le16_encode_bits(ltf_size, IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); - he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, v14) | - HE_PREP(DATA6_DOPPLER, DOPPLER, v14); + he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) | + HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]); - switch (rxv->phy) { + switch (phy) { case MT_PHY_TYPE_HE_SU: he->data1 |= HE_BITS(DATA1_FORMAT_SU) | HE_BITS(DATA1_UL_DL_KNOWN) | HE_BITS(DATA1_BEAM_CHANGE_KNOWN) | HE_BITS(DATA1_SPTL_REUSE_KNOWN); - he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, v14) | - HE_PREP(DATA3_UL_DL, UPLINK, v2); - he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, v11); + he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[14]) | + HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); + he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]); break; case MT_PHY_TYPE_HE_EXT_SU: he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) | HE_BITS(DATA1_UL_DL_KNOWN); - he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, v2); + he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); break; case MT_PHY_TYPE_HE_MU: he->data1 |= HE_BITS(DATA1_FORMAT_MU) | HE_BITS(DATA1_UL_DL_KNOWN) | HE_BITS(DATA1_SPTL_REUSE_KNOWN); - he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, v2); - he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, v11); + he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); + he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]); - mt7915_mac_decode_he_radiotap_ru(status, rxv, he); + mt7915_mac_decode_he_radiotap_ru(status, he, rxv); break; case MT_PHY_TYPE_HE_TB: he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) | @@ -295,12 +292,12 @@ mt7915_mac_decode_he_radiotap(struct sk_buff *skb, HE_BITS(DATA1_SPTL_REUSE3_KNOWN) | HE_BITS(DATA1_SPTL_REUSE4_KNOWN); - he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, v11) | - HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, v11) | - HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, v11) | - HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, v11); + he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[11]) | + HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[11]) | + HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[11]) | + HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[11]); - mt7915_mac_decode_he_radiotap_ru(status, rxv, he); + mt7915_mac_decode_he_radiotap_ru(status, he, rxv); break; default: break; @@ -314,8 +311,9 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) struct mt7915_phy *phy = &dev->phy; struct ieee80211_supported_band *sband; struct ieee80211_hdr *hdr; - struct mt7915_rxv rxv = {}; __le32 *rxd = (__le32 *)skb->data; + __le32 *rxv = NULL; + u32 mode = 0; u32 rxd1 = le32_to_cpu(rxd[1]); u32 rxd2 = le32_to_cpu(rxd[2]); u32 rxd3 = le32_to_cpu(rxd[3]); @@ -427,15 +425,14 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) if (rxd1 & MT_RXD1_NORMAL_GROUP_3) { u32 v0, v1, v2; - memcpy(rxv.v, rxd, sizeof(rxv.v)); - + rxv = rxd; rxd += 2; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; - v0 = le32_to_cpu(rxv.v[0]); - v1 = le32_to_cpu(rxv.v[1]); - v2 = le32_to_cpu(rxv.v[2]); + v0 = le32_to_cpu(rxv[0]); + v1 = le32_to_cpu(rxv[1]); + v2 = le32_to_cpu(rxv[2]); if (v0 & MT_PRXV_HT_AD_CODE) status->enc_flags |= RX_ENC_FLAG_LDPC; @@ -466,9 +463,9 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) return -EINVAL; idx = i = FIELD_GET(MT_PRXV_TX_RATE, v0); - rxv.phy = FIELD_GET(MT_CRXV_TX_MODE, v2); + mode = FIELD_GET(MT_CRXV_TX_MODE, v2); - switch (rxv.phy) { + switch (mode) { case MT_PHY_TYPE_CCK: cck = true; /* fall through */ @@ -503,8 +500,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) if (gi <= NL80211_RATE_INFO_HE_GI_3_2) status->he_gi = gi; - if (idx & MT_PRXV_TX_DCM) - status->he_dcm = true; + status->he_dcm = !!(idx & MT_PRXV_TX_DCM); break; default: return -EINVAL; @@ -515,7 +511,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) case IEEE80211_STA_RX_BW_20: break; case IEEE80211_STA_RX_BW_40: - if (rxv.phy & MT_PHY_TYPE_HE_EXT_SU && + if (mode & MT_PHY_TYPE_HE_EXT_SU && (idx & MT_PRXV_TX_ER_SU_106T)) { status->bw = RATE_INFO_BW_HE_RU; status->he_ru = @@ -535,7 +531,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) } status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc; - if (rxv.phy < MT_PHY_TYPE_HE_SU && gi) + if (mode < MT_PHY_TYPE_HE_SU && gi) status->enc_flags |= RX_ENC_FLAG_SHORT_GI; } } @@ -548,8 +544,8 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) mt76_insert_ccmp_hdr(skb, key_id); } - if (status->flag & RX_FLAG_RADIOTAP_HE) - mt7915_mac_decode_he_radiotap(skb, status, &rxv); + if (rxv && status->flag & RX_FLAG_RADIOTAP_HE) + mt7915_mac_decode_he_radiotap(skb, status, rxv, mode); hdr = mt76_skb_get_hdr(skb); if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h index 4b0871ab2414..c8bb5ea96c60 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -128,13 +128,6 @@ enum rx_pkt_type { #define MT_CRXV_HE_BEAM_CHNG BIT(13) #define MT_CRXV_HE_DOPPLER BIT(16) -struct mt7915_rxv { - u32 phy; - - /* P-RXV: bit 0~1, C-RXV: bit 2~19 */ - __le32 v[20]; -}; - enum tx_header_format { MT_HDR_FORMAT_802_3, MT_HDR_FORMAT_CMD, -- cgit v1.2.3 From 757b0e7fd6f4f2e558fac602ea34a9be20143c95 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:40 +0200 Subject: mt76: mt7615: avoid polling in fw_own for mt7663 According to the vendor sdk, mt7663 does not need to poll register after firmware own. Since just mt7622 polls status register, set proper timeout value according to the vendor sdk Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 445eb81267ef..0fcb379a8c06 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1918,9 +1918,9 @@ int mt7615_firmware_own(struct mt7615_dev *dev) mt76_wr(dev, addr, MT_CFG_LPCR_HOST_FW_OWN); - if (!is_mt7615(&dev->mt76) && + if (is_mt7622(&dev->mt76) && !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, - MT_CFG_LPCR_HOST_FW_OWN, 3000)) { + MT_CFG_LPCR_HOST_FW_OWN, 300)) { dev_err(dev->mt76.dev, "Timeout for firmware own\n"); return -EIO; } -- cgit v1.2.3 From a86f1d01f5ce5c5e6c685168747822e82ba5bf83 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:41 +0200 Subject: mt76: move mt76 workqueue in common code Move mt76 workqueue from usb to common code in order to be reused adding low-power support for mt7663 chipset Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 13 ++++++++++++- drivers/net/wireless/mediatek/mt76/mt76.h | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/usb.c | 6 ++---- drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 6 ++---- drivers/net/wireless/mediatek/mt76/mt76x2/usb.c | 7 ++----- drivers/net/wireless/mediatek/mt76/usb.c | 20 ++++---------------- 8 files changed, 26 insertions(+), 34 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 10e6dbb64996..6aa3efa8f55e 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -437,6 +437,12 @@ mt76_alloc_device(struct device *pdev, unsigned int size, tasklet_init(&dev->tx_tasklet, mt76_tx_tasklet, (unsigned long)dev); + dev->wq = alloc_ordered_workqueue("mt76", 0); + if (!dev->wq) { + ieee80211_free_hw(hw); + return NULL; + } + return dev; } EXPORT_SYMBOL_GPL(mt76_alloc_device); @@ -490,7 +496,12 @@ EXPORT_SYMBOL_GPL(mt76_unregister_device); void mt76_free_device(struct mt76_dev *dev) { - mt76_tx_free(dev); + if (dev->wq) { + destroy_workqueue(dev->wq); + dev->wq = NULL; + } + if (mt76_is_mmio(dev)) + mt76_tx_free(dev); ieee80211_free_hw(dev->hw); } EXPORT_SYMBOL_GPL(mt76_free_device); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 14b3a39cd55a..dea63d6579f5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -423,7 +423,6 @@ struct mt76_usb { u16 data_len; struct tasklet_struct rx_tasklet; - struct workqueue_struct *wq; struct work_struct stat_work; u8 out_ep[__MT_EP_OUT_MAX]; @@ -621,6 +620,8 @@ struct mt76_dev { struct mt76_testmode_data test; #endif + struct workqueue_struct *wq; + union { struct mt76_mmio mmio; struct mt76_usb usb; @@ -1018,7 +1019,6 @@ int mt76u_vendor_request(struct mt76_dev *dev, u8 req, void *buf, size_t len); void mt76u_single_wr(struct mt76_dev *dev, const u8 req, const u16 offset, const u32 val); -void mt76u_deinit(struct mt76_dev *dev); int mt76u_init(struct mt76_dev *dev, struct usb_interface *intf, bool ext); int mt76u_alloc_mcu_queue(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 2d432d052780..73b994a410b0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -927,7 +927,7 @@ mt7615_mac_queue_rate_update(struct mt7615_phy *phy, struct mt7615_sta *sta, mt7615_mac_update_rate_desc(phy, sta, probe_rate, rates, &wd->rate); list_add_tail(&wd->node, &dev->wd_head); - queue_work(dev->mt76.usb.wq, &dev->wtbl_work); + queue_work(dev->mt76.wq, &dev->wtbl_work); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 3abb33ddab7d..3bcbd13c26d7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -319,7 +319,7 @@ mt7615_queue_key_update(struct mt7615_dev *dev, enum set_key_cmd cmd, wd->key.cmd = cmd; list_add_tail(&wd->node, &dev->wd_head); - queue_work(dev->mt76.usb.wq, &dev->wtbl_work); + queue_work(dev->mt76.wq, &dev->wtbl_work); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c index 0ba28d37c414..f70a7d9d65e2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -349,11 +349,10 @@ alloc_queues: error_freeq: mt76u_queues_deinit(&dev->mt76); error: - mt76u_deinit(&dev->mt76); usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); - ieee80211_free_hw(mdev->hw); + mt76_free_device(&dev->mt76); return ret; } @@ -371,8 +370,7 @@ static void mt7663u_disconnect(struct usb_interface *usb_intf) usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); - mt76u_deinit(&dev->mt76); - ieee80211_free_hw(dev->mt76.hw); + mt76_free_device(&dev->mt76); } #ifdef CONFIG_PM diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 5535b9c0632f..ce6b286a8152 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -277,9 +277,8 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, err: usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); - mt76u_deinit(&dev->mt76); + mt76_free_device(&dev->mt76); - ieee80211_free_hw(mdev->hw); return ret; } @@ -297,8 +296,7 @@ static void mt76x0_disconnect(struct usb_interface *usb_intf) usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); - mt76u_deinit(&dev->mt76); - ieee80211_free_hw(dev->mt76.hw); + mt76_free_device(&dev->mt76); } static int __maybe_unused mt76x0_suspend(struct usb_interface *usb_intf, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index b27acf1bbc03..4e003c7b62cf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -75,8 +75,7 @@ static int mt76x2u_probe(struct usb_interface *intf, return 0; err: - ieee80211_free_hw(mt76_hw(dev)); - mt76u_deinit(&dev->mt76); + mt76_free_device(&dev->mt76); usb_set_intfdata(intf, NULL); usb_put_dev(udev); @@ -92,9 +91,7 @@ static void mt76x2u_disconnect(struct usb_interface *intf) set_bit(MT76_REMOVED, &dev->mphy.state); ieee80211_unregister_hw(hw); mt76x2u_cleanup(dev); - mt76u_deinit(&dev->mt76); - - ieee80211_free_hw(hw); + mt76_free_device(&dev->mt76); usb_set_intfdata(intf, NULL); usb_put_dev(udev); } diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 0ff3096f7455..84e2fd0a4fc1 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -842,7 +842,7 @@ static void mt76u_tx_tasklet(unsigned long data) if (dev->drv->tx_status_data && !test_and_set_bit(MT76_READING_STATS, &dev->phy.state)) - queue_work(dev->usb.wq, &dev->usb.stat_work); + queue_work(dev->wq, &dev->usb.stat_work); if (wake) ieee80211_wake_queue(dev->hw, i); } @@ -868,7 +868,7 @@ static void mt76u_tx_status_data(struct work_struct *work) } if (count && test_bit(MT76_STATE_RUNNING, &dev->phy.state)) - queue_work(usb->wq, &usb->stat_work); + queue_work(dev->wq, &usb->stat_work); else clear_bit(MT76_READING_STATS, &dev->phy.state); } @@ -1132,15 +1132,6 @@ static const struct mt76_queue_ops usb_queue_ops = { .kick = mt76u_tx_kick, }; -void mt76u_deinit(struct mt76_dev *dev) -{ - if (dev->usb.wq) { - destroy_workqueue(dev->usb.wq); - dev->usb.wq = NULL; - } -} -EXPORT_SYMBOL_GPL(mt76u_deinit); - int mt76u_init(struct mt76_dev *dev, struct usb_interface *intf, bool ext) { @@ -1163,10 +1154,6 @@ int mt76u_init(struct mt76_dev *dev, tasklet_init(&dev->tx_tasklet, mt76u_tx_tasklet, (unsigned long)dev); INIT_WORK(&usb->stat_work, mt76u_tx_status_data); - usb->wq = alloc_workqueue("mt76u", WQ_UNBOUND, 0); - if (!usb->wq) - return -ENOMEM; - usb->data_len = usb_maxpacket(udev, usb_sndctrlpipe(udev, 0), 1); if (usb->data_len < 32) usb->data_len = 32; @@ -1190,7 +1177,8 @@ int mt76u_init(struct mt76_dev *dev, return 0; error: - mt76u_deinit(dev); + destroy_workqueue(dev->wq); + return err; } EXPORT_SYMBOL_GPL(mt76u_init); -- cgit v1.2.3 From 08523a2a1db5eba808de0ba0a7aa29cb993771dd Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:42 +0200 Subject: mt76: mt7615: add mt7615_pm_wake utility routine Introduce mt7615_pm_wake utility routine to wake the device from runtime low-power state (lower-power state is currently supported by offload firmware for pcie devices). Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/init.c | 3 ++ drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 42 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/main.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 25 +++++++++---- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 8 +++++ 6 files changed, 75 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index dea63d6579f5..7e4adb9be273 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -291,6 +291,7 @@ enum { MT76_STATE_POWER_OFF, MT76_STATE_SUSPEND, MT76_STATE_ROC, + MT76_STATE_PM, }; struct mt76_hw_cap { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 2e0840b0e902..e1bf45466ad6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -435,6 +435,9 @@ void mt7615_init_device(struct mt7615_dev *dev) dev->phy.dev = dev; dev->phy.mt76 = &dev->mt76.phy; dev->mt76.phy.priv = &dev->phy; + + INIT_WORK(&dev->pm.wake_work, mt7615_pm_wake_work); + init_completion(&dev->pm.wake_cmpl); INIT_DELAYED_WORK(&dev->phy.mac_work, mt7615_mac_work); INIT_DELAYED_WORK(&dev->phy.scan_work, mt7615_scan_work); skb_queue_head_init(&dev->phy.scan_event_list); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 73b994a410b0..d4dbaaa0b279 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1808,6 +1808,48 @@ mt7615_mac_update_mib_stats(struct mt7615_phy *phy) } } +void mt7615_pm_wake_work(struct work_struct *work) +{ + struct mt7615_dev *dev; + struct mt76_phy *mphy; + + dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, + pm.wake_work); + mphy = dev->phy.mt76; + + if (mt7615_driver_own(dev)) + dev_err(mphy->dev->dev, "failed to wake device\n"); + + complete_all(&dev->pm.wake_cmpl); +} + +int mt7615_pm_wake(struct mt7615_dev *dev) +{ + struct mt76_phy *mphy = dev->phy.mt76; + + if (!mt7615_firmware_offload(dev)) + return 0; + + if (!mt76_is_mmio(mphy->dev)) + return 0; + + if (!test_bit(MT76_STATE_PM, &mphy->state)) + return 0; + + if (test_bit(MT76_HW_SCANNING, &mphy->state) || + test_bit(MT76_HW_SCHED_SCANNING, &mphy->state)) + return 0; + + if (queue_work(dev->mt76.wq, &dev->pm.wake_work)) + reinit_completion(&dev->pm.wake_cmpl); + + if (!wait_for_completion_timeout(&dev->pm.wake_cmpl, 3 * HZ)) + return -ETIMEDOUT; + + return 0; +} +EXPORT_SYMBOL_GPL(mt7615_pm_wake); + void mt7615_mac_work(struct work_struct *work) { struct mt7615_phy *phy; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 3bcbd13c26d7..1e7f7b9b1388 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -74,6 +74,8 @@ static void mt7615_stop(struct ieee80211_hw *hw) del_timer_sync(&phy->roc_timer); cancel_work_sync(&phy->roc_work); + cancel_work_sync(&dev->pm.wake_work); + mutex_lock(&dev->mt76.mutex); mt76_testmode_reset(&dev->mt76, true); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 0fcb379a8c06..2f9f079bad0b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1889,28 +1889,36 @@ static void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en) int mt7615_driver_own(struct mt7615_dev *dev) { + struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_dev *mdev = &dev->mt76; + int err = 0; u32 addr; + mt7622_trigger_hif_int(dev, true); + addr = is_mt7663(mdev) ? MT_PCIE_DOORBELL_PUSH : MT_CFG_LPCR_HOST; mt76_wr(dev, addr, MT_CFG_LPCR_HOST_DRV_OWN); - mt7622_trigger_hif_int(dev, true); - addr = is_mt7663(mdev) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST; if (!mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000)) { dev_err(dev->mt76.dev, "Timeout for driver own\n"); - return -EIO; + err = -EIO; + goto out; } + clear_bit(MT76_STATE_PM, &mphy->state); + +out: mt7622_trigger_hif_int(dev, false); - return 0; + return err; } EXPORT_SYMBOL_GPL(mt7615_driver_own); int mt7615_firmware_own(struct mt7615_dev *dev) { + struct mt76_phy *mphy = &dev->mt76.phy; + int err = 0; u32 addr; addr = is_mt7663(&dev->mt76) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST; @@ -1922,11 +1930,16 @@ int mt7615_firmware_own(struct mt7615_dev *dev) !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, MT_CFG_LPCR_HOST_FW_OWN, 300)) { dev_err(dev->mt76.dev, "Timeout for firmware own\n"); - return -EIO; + err = -EIO; + goto out; } + + set_bit(MT76_STATE_PM, &mphy->state); + +out: mt7622_trigger_hif_int(dev, false); - return 0; + return err; } EXPORT_SYMBOL_GPL(mt7615_firmware_own); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index a995d41fb9c1..27d4dfd81dfd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -4,6 +4,7 @@ #ifndef __MT7615_H #define __MT7615_H +#include #include #include #include @@ -296,6 +297,11 @@ struct mt7615_dev { s8 last_wb_rssi; } test; #endif + + struct { + struct work_struct wake_work; + struct completion wake_cmpl; + } pm; }; enum tx_pkt_queue_idx { @@ -425,6 +431,8 @@ bool mt7615_wait_for_mcu_init(struct mt7615_dev *dev); void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, struct ieee80211_tx_rate *probe_rate, struct ieee80211_tx_rate *rates); +void mt7615_pm_wake_work(struct work_struct *work); +int mt7615_pm_wake(struct mt7615_dev *dev); int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev); int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd); int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue, -- cgit v1.2.3 From adfd5112c81b31cc4c9ac481bd0ad372149771ea Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:43 +0200 Subject: mt76: mt7615: introduce mt7615_mutex_{acquire,release} utilities Introduce mt7615_mutex_{acquire,release} utility routines in order to switch in full-power/low-power before/after accessing device register-map Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 14 ++-- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 82 +++++++++++----------- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 16 +++++ drivers/net/wireless/mediatek/mt76/mt7615/usb.c | 11 +-- 5 files changed, 72 insertions(+), 52 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index d4dbaaa0b279..3f470388fe01 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1530,7 +1530,7 @@ void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable) bool ext_phy = phy != &dev->phy; u32 reg, mask; - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); if (phy->scs_en == enable) goto out; @@ -1557,7 +1557,7 @@ void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable) phy->scs_en = enable; out: - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); } void mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy) @@ -1859,7 +1859,7 @@ void mt7615_mac_work(struct work_struct *work) mac_work.work); mdev = &phy->dev->mt76; - mutex_lock(&mdev->mutex); + mt7615_mutex_acquire(phy->dev); mt76_update_survey(mdev); if (++phy->mac_work_count == 5) { @@ -1869,7 +1869,7 @@ void mt7615_mac_work(struct work_struct *work) mt7615_mac_scs_check(phy); } - mutex_unlock(&mdev->mutex); + mt7615_mutex_release(phy->dev); mt76_tx_status_check(mdev, NULL, false); ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work, @@ -1973,7 +1973,7 @@ void mt7615_mac_reset_work(struct work_struct *work) napi_disable(&dev->mt76.napi[1]); napi_disable(&dev->mt76.tx_napi); - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_PDMA_STOPPED); @@ -2006,10 +2006,10 @@ void mt7615_mac_reset_work(struct work_struct *work) mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE); mt7615_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); - mutex_unlock(&dev->mt76.mutex); - mt7615_update_beacons(dev); + mt7615_mutex_release(dev); + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->phy.mac_work, MT7615_WATCHDOG_TIME); if (phy2) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 1e7f7b9b1388..5f2c50a2449b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -33,7 +33,7 @@ static int mt7615_start(struct ieee80211_hw *hw) if (!mt7615_wait_for_mcu_init(dev)) return -EIO; - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); running = mt7615_dev_running(dev); @@ -60,7 +60,7 @@ static int mt7615_start(struct ieee80211_hw *hw) if (!running) mt7615_mac_reset_counters(dev); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return 0; } @@ -76,7 +76,7 @@ static void mt7615_stop(struct ieee80211_hw *hw) cancel_work_sync(&dev->pm.wake_work); - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); mt76_testmode_reset(&dev->mt76, true); @@ -93,7 +93,7 @@ static void mt7615_stop(struct ieee80211_hw *hw) mt7615_mcu_set_mac_enable(dev, 0, false); } - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); } static int get_omac_idx(enum nl80211_iftype type, u32 mask) @@ -139,7 +139,7 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, bool ext_phy = phy != &dev->phy; int idx, ret = 0; - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); mt76_testmode_reset(&dev->mt76, true); @@ -191,7 +191,7 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, ret = mt7615_mcu_add_dev_info(dev, vif, true); out: - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return ret; } @@ -207,10 +207,9 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw, /* TODO: disable beacon for the bss */ - mutex_lock(&dev->mt76.mutex); - mt76_testmode_reset(&dev->mt76, true); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); + mt76_testmode_reset(&dev->mt76, true); if (vif == phy->monitor_vif) phy->monitor_vif = NULL; @@ -220,11 +219,11 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw, if (vif->txq) mt76_txq_remove(&dev->mt76, vif->txq); - mutex_lock(&dev->mt76.mutex); dev->mphy.vif_mask &= ~BIT(mvif->idx); dev->omac_mask &= ~BIT(mvif->omac_idx); phy->omac_mask &= ~BIT(mvif->omac_idx); - mutex_unlock(&dev->mt76.mutex); + + mt7615_mutex_release(dev); spin_lock_bh(&dev->sta_poll_lock); if (!list_empty(&msta->poll_list)) @@ -259,7 +258,8 @@ int mt7615_set_channel(struct mt7615_phy *phy) cancel_delayed_work_sync(&phy->mac_work); - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); + set_bit(MT76_RESET, &phy->mt76->state); mt7615_init_dfs_state(phy); @@ -285,7 +285,8 @@ int mt7615_set_channel(struct mt7615_phy *phy) out: clear_bit(MT76_RESET, &phy->mt76->state); - mutex_unlock(&dev->mt76.mutex); + + mt7615_mutex_release(dev); mt76_txq_schedule_all(phy->mt76); @@ -391,9 +392,9 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed) IEEE80211_CONF_CHANGE_POWER)) { #ifdef CONFIG_NL80211_TESTMODE if (dev->mt76.test.state != MT76_TM_STATE_OFF) { - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); mt76_testmode_reset(&dev->mt76, false); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); } #endif ieee80211_stop_queues(hw); @@ -401,7 +402,7 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed) ieee80211_wake_queues(hw); } - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { mt76_testmode_reset(&dev->mt76, true); @@ -414,7 +415,7 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed) mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter); } - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return ret; } @@ -448,7 +449,7 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw, MT_WF_RFCR1_DROP_CFACK; u32 flags = 0; - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); #define MT76_FILTER(_flag, _hw) do { \ flags |= *total_flags & FIF_##_flag; \ @@ -488,7 +489,7 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw, else mt76_set(dev, MT_WF_RFCR1(band), ctl_flags); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); } static void mt7615_bss_info_changed(struct ieee80211_hw *hw, @@ -499,7 +500,7 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); if (changed & BSS_CHANGED_ERP_SLOT) { int slottime = info->use_short_slot ? 9 : 20; @@ -528,7 +529,7 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ARP_FILTER) mt7615_mcu_update_arp_filter(hw, vif, info); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); } static void @@ -538,9 +539,9 @@ mt7615_channel_switch_beacon(struct ieee80211_hw *hw, { struct mt7615_dev *dev = mt7615_hw_dev(hw); - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); mt7615_mcu_add_beacon(dev, hw, vif, true); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); } int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, @@ -656,9 +657,9 @@ static int mt7615_set_rts_threshold(struct ieee80211_hw *hw, u32 val) struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); mt7615_mcu_set_rts_thresh(phy, val); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return 0; } @@ -682,7 +683,8 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mtxq = (struct mt76_txq *)txq->drv_priv; - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); + switch (action) { case IEEE80211_AMPDU_RX_START: mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, @@ -718,7 +720,7 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return ret; } @@ -763,13 +765,13 @@ mt7615_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) u32 t32[2]; } tsf; - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* TSF read */ tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0); tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return tsf.t64; } @@ -784,14 +786,14 @@ mt7615_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 t32[2]; } tsf = { .t64 = timestamp, }; - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); mt76_wr(dev, MT_LPON_UTTR0, tsf.t32[0]); mt76_wr(dev, MT_LPON_UTTR1, tsf.t32[1]); /* TSF software overwrite */ mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_WRITE); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); } static void @@ -800,10 +802,10 @@ mt7615_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) struct mt7615_phy *phy = mt7615_hw_phy(hw); struct mt7615_dev *dev = phy->dev; - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); phy->coverage_class = max_t(s16, coverage_class, 0); mt7615_mac_set_timing(phy); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); } static int @@ -820,7 +822,7 @@ mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) if ((BIT(hweight8(tx_ant)) - 1) != tx_ant) tx_ant = BIT(ffs(tx_ant) - 1) - 1; - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); phy->mt76->antenna_mask = tx_ant; if (ext_phy) { @@ -833,7 +835,7 @@ mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) mt76_set_stream_caps(phy->mt76, true); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return 0; } @@ -995,7 +997,7 @@ static int mt7615_suspend(struct ieee80211_hw *hw, bool ext_phy = phy != &dev->phy; int err = 0; - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); cancel_delayed_work_sync(&phy->scan_work); @@ -1011,7 +1013,7 @@ static int mt7615_suspend(struct ieee80211_hw *hw, if (!mt7615_dev_running(dev)) err = mt7615_mcu_set_hif_suspend(dev, true); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return err; } @@ -1022,7 +1024,7 @@ static int mt7615_resume(struct ieee80211_hw *hw) struct mt7615_phy *phy = mt7615_hw_phy(hw); bool running, ext_phy = phy != &dev->phy; - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); running = mt7615_dev_running(dev); set_bit(MT76_STATE_RUNNING, &phy->mt76->state); @@ -1032,7 +1034,7 @@ static int mt7615_resume(struct ieee80211_hw *hw) err = mt7615_mcu_set_hif_suspend(dev, false); if (err < 0) { - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return err; } } @@ -1046,7 +1048,7 @@ static int mt7615_resume(struct ieee80211_hw *hw) MT7615_WATCHDOG_TIME); mt76_clear(dev, MT_WF_RFCR(ext_phy), MT_WF_RFCR_DROP_OTHER_BEACON); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 2f9f079bad0b..72cfc197b936 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1910,6 +1910,7 @@ int mt7615_driver_own(struct mt7615_dev *dev) out: mt7622_trigger_hif_int(dev, false); + dev->pm.last_activity = jiffies; return err; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 27d4dfd81dfd..ec91b729a25c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -301,6 +301,8 @@ struct mt7615_dev { struct { struct work_struct wake_work; struct completion wake_cmpl; + + unsigned long last_activity; } pm; }; @@ -487,6 +489,20 @@ static inline u16 mt7615_wtbl_size(struct mt7615_dev *dev) return MT7615_WTBL_SIZE; } +static inline void mt7615_mutex_acquire(struct mt7615_dev *dev) + __acquires(&dev->mt76.mutex) +{ + mutex_lock(&dev->mt76.mutex); + mt7615_pm_wake(dev); +} + +static inline void mt7615_mutex_release(struct mt7615_dev *dev) + __releases(&dev->mt76.mutex) +{ + dev->pm.last_activity = jiffies; + mutex_unlock(&dev->mt76.mutex); +} + static inline u8 mt7615_lmac_mapping(struct mt7615_dev *dev, u8 ac) { static const u8 lmac_queue_map[] = { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c index f70a7d9d65e2..a780127377bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -201,12 +201,13 @@ void mt7663u_wtbl_work(struct work_struct *work) dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, wtbl_work); + mt7615_mutex_acquire(dev); + list_for_each_entry_safe(wd, wd_next, &dev->wd_head, node) { spin_lock_bh(&dev->mt76.lock); list_del(&wd->node); spin_unlock_bh(&dev->mt76.lock); - mutex_lock(&dev->mt76.mutex); switch (wd->type) { case MT7615_WTBL_RATE_DESC: __mt7663u_mac_set_rates(dev, wd); @@ -215,10 +216,10 @@ void mt7663u_wtbl_work(struct work_struct *work) __mt7663u_mac_set_key(dev, wd); break; } - mutex_unlock(&dev->mt76.mutex); - kfree(wd); } + + mt7615_mutex_release(dev); } static void @@ -257,9 +258,9 @@ static bool mt7663u_tx_status_data(struct mt76_dev *mdev, u8 *update) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); mt7615_mac_sta_poll(dev); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return 0; } -- cgit v1.2.3 From ea4906c4be4944f8341d500f83267d1ba3e8e838 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:44 +0200 Subject: mt76: mt7615: wake device before accessing regmap in debugfs Make sure the device is in full-power before reading regs in debugfs Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7615/debugfs.c | 25 +++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index 8bb7c64db738..8894a0ab407b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -6,11 +6,16 @@ static int mt7615_radar_pattern_set(void *data, u64 val) { struct mt7615_dev *dev = data; + int err; if (!mt7615_wait_for_mcu_init(dev)) return 0; - return mt7615_mcu_rdd_send_pattern(dev); + mt7615_mutex_acquire(dev); + err = mt7615_mcu_rdd_send_pattern(dev); + mt7615_mutex_release(dev); + + return err; } DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_pattern, NULL, @@ -84,7 +89,10 @@ mt7615_fw_debug_set(void *data, u64 val) return 0; dev->fw_debug = val; + + mt7615_mutex_acquire(dev); mt7615_mcu_fw_log_2_host(dev, dev->fw_debug ? 2 : 0); + mt7615_mutex_release(dev); return 0; } @@ -111,6 +119,8 @@ mt7615_reset_test_set(void *data, u64 val) if (!mt7615_wait_for_mcu_init(dev)) return 0; + mt7615_mutex_acquire(dev); + skb = alloc_skb(1, GFP_KERNEL); if (!skb) return -ENOMEM; @@ -118,6 +128,8 @@ mt7615_reset_test_set(void *data, u64 val) skb_put(skb, 1); mt76_tx_queue_skb_raw(dev, 0, skb, 0); + mt7615_mutex_release(dev); + return 0; } @@ -167,9 +179,13 @@ mt7615_ampdu_stat_read(struct seq_file *file, void *data) { struct mt7615_dev *dev = file->private; + mt7615_mutex_acquire(dev); + mt7615_ampdu_stat_read_phy(&dev->phy, file); mt7615_ampdu_stat_read_phy(mt7615_ext_phy(dev), file); + mt7615_mutex_release(dev); + return 0; } @@ -221,7 +237,10 @@ static int mt7615_read_temperature(struct seq_file *s, void *data) 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; @@ -233,6 +252,8 @@ mt7615_queues_acq(struct seq_file *s, void *data) struct mt7615_dev *dev = dev_get_drvdata(s->private); int i; + mt7615_mutex_acquire(dev); + for (i = 0; i < 16; i++) { int j, wmm_idx = i % MT7615_MAX_WMM_SETS; int acs = i / MT7615_MAX_WMM_SETS; @@ -253,6 +274,8 @@ mt7615_queues_acq(struct seq_file *s, void *data) seq_printf(s, "AC%d%d: queued=%d\n", wmm_idx, acs, qlen); } + mt7615_mutex_release(dev); + return 0; } -- cgit v1.2.3 From 940a0c63e0c3df5881ff4a034501638de01a63a9 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:45 +0200 Subject: mt76: mt7615: wake device before configuring hw keys Make sure the device is in full-power before uploading keys to the hw Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 5f2c50a2449b..3c230479b36c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -336,7 +336,7 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct mt7615_sta *msta = sta ? (struct mt7615_sta *)sta->drv_priv : &mvif->sta; struct mt76_wcid *wcid = &msta->wcid; - int idx = key->keyidx; + int idx = key->keyidx, err; /* The hardware does not support per-STA RX GTK, fallback * to software mode for these. @@ -366,6 +366,8 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return -EOPNOTSUPP; } + mt7615_mutex_acquire(dev); + if (cmd == SET_KEY) { key->hw_key_idx = wcid->idx; wcid->hw_key_idx = idx; @@ -376,9 +378,13 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, cmd == SET_KEY ? key : NULL); if (mt76_is_usb(&dev->mt76)) - return mt7615_queue_key_update(dev, cmd, msta, key); + err = mt7615_queue_key_update(dev, cmd, msta, key); + else + err = mt7615_mac_wtbl_set_key(dev, wcid, key, cmd); - return mt7615_mac_wtbl_set_key(dev, wcid, key, cmd); + mt7615_mutex_release(dev); + + return err; } static int mt7615_config(struct ieee80211_hw *hw, u32 changed) -- cgit v1.2.3 From de5ff3c9d1a2d6ecbe4b8d29565430e7ce29bac2 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:46 +0200 Subject: mt76: mt7615: introduce pm_power_save delayed work Introduce runtime-pm power_save delayed work used to enable low-power after an inactivity period Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 28 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/main.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 8 ++++++- 4 files changed, 39 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index e1bf45466ad6..5bb87dd21279 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -436,6 +436,7 @@ void mt7615_init_device(struct mt7615_dev *dev) dev->phy.mt76 = &dev->mt76.phy; dev->mt76.phy.priv = &dev->phy; + INIT_DELAYED_WORK(&dev->pm.ps_work, mt7615_pm_power_save_work); INIT_WORK(&dev->pm.wake_work, mt7615_pm_wake_work); init_completion(&dev->pm.wake_cmpl); INIT_DELAYED_WORK(&dev->phy.mac_work, mt7615_mac_work); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 3f470388fe01..b1148654771a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1850,6 +1850,34 @@ int mt7615_pm_wake(struct mt7615_dev *dev) } EXPORT_SYMBOL_GPL(mt7615_pm_wake); +void mt7615_pm_power_save_sched(struct mt7615_dev *dev) +{ + struct mt76_phy *mphy = dev->phy.mt76; + + if (!mt7615_firmware_offload(dev) || + !dev->pm.enable || !mt76_is_mmio(mphy->dev) || + !test_bit(MT76_STATE_RUNNING, &mphy->state)) + return; + + dev->pm.last_activity = jiffies; + if (!test_bit(MT76_STATE_PM, &mphy->state)) + queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, + MT7615_PM_TIMEOUT); +} +EXPORT_SYMBOL_GPL(mt7615_pm_power_save_sched); + +void mt7615_pm_power_save_work(struct work_struct *work) +{ + struct mt7615_dev *dev; + + dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, + pm.ps_work.work); + + if (mt7615_firmware_own(dev)) + queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, + MT7615_PM_TIMEOUT); +} + void mt7615_mac_work(struct work_struct *work) { struct mt7615_phy *phy; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 3c230479b36c..d1ddd5b15955 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -74,6 +74,7 @@ static void mt7615_stop(struct ieee80211_hw *hw) del_timer_sync(&phy->roc_timer); cancel_work_sync(&phy->roc_work); + cancel_delayed_work_sync(&dev->pm.ps_work); cancel_work_sync(&dev->pm.wake_work); mt7615_mutex_acquire(dev); @@ -1003,6 +1004,8 @@ static int mt7615_suspend(struct ieee80211_hw *hw, bool ext_phy = phy != &dev->phy; int err = 0; + cancel_delayed_work_sync(&dev->pm.ps_work); + mt7615_mutex_acquire(dev); clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index ec91b729a25c..3c5cd7f0ea1e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -19,6 +19,7 @@ #define MT7615_WTBL_STA (MT7615_WTBL_RESERVED - \ 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) @@ -299,9 +300,12 @@ struct mt7615_dev { #endif struct { + bool enable; + struct work_struct wake_work; struct completion wake_cmpl; + struct delayed_work ps_work; unsigned long last_activity; } pm; }; @@ -435,6 +439,8 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, struct ieee80211_tx_rate *rates); void mt7615_pm_wake_work(struct work_struct *work); int mt7615_pm_wake(struct mt7615_dev *dev); +void mt7615_pm_power_save_sched(struct mt7615_dev *dev); +void mt7615_pm_power_save_work(struct work_struct *work); int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev); int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd); int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue, @@ -499,7 +505,7 @@ static inline void mt7615_mutex_acquire(struct mt7615_dev *dev) static inline void mt7615_mutex_release(struct mt7615_dev *dev) __releases(&dev->mt76.mutex) { - dev->pm.last_activity = jiffies; + mt7615_pm_power_save_sched(dev); mutex_unlock(&dev->mt76.mutex); } -- cgit v1.2.3 From 04414240adb7092a03a2ede3cd3e24d461adb756 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:47 +0200 Subject: mt76: mt7615: wake device in mt7615_update_channel before access regmap Introduce mt7615_update_survey utility routine in order to compute survey stats without waking up the device since it runs holding mt76 lock. Run mt7615_pm_wake directly in mt7615_update_channel since it can run with mt76.mutex held if called by mac80211 Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 30 ++++++++++++++++++++++--- 3 files changed, 30 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 6aa3efa8f55e..f340af40f8f4 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -560,8 +560,7 @@ mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c) return &msband->chan[idx]; } -static void -mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time) +void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time) { struct mt76_channel_state *state = phy->chan_state; @@ -569,6 +568,7 @@ mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time) phy->survey_time)); phy->survey_time = time; } +EXPORT_SYMBOL_GPL(mt76_update_survey_active_time); void mt76_update_survey(struct mt76_dev *dev) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 7e4adb9be273..532267056ff3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -884,6 +884,7 @@ void mt76_release_buffered_frames(struct ieee80211_hw *hw, 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_active_time(struct mt76_phy *phy, ktime_t time); int mt76_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey); void mt76_set_stream_caps(struct mt76_phy *phy, bool vht); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index b1148654771a..e17cba62252f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1747,9 +1747,9 @@ mt7615_phy_update_channel(struct mt76_phy *mphy, int idx) state->noise = -(phy->noise >> 4); } -void mt7615_update_channel(struct mt76_dev *mdev) +static void __mt7615_update_channel(struct mt7615_dev *dev) { - struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + struct mt76_dev *mdev = &dev->mt76; mt7615_phy_update_channel(&mdev->phy, 0); if (mdev->phy2) @@ -1758,8 +1758,32 @@ void mt7615_update_channel(struct mt76_dev *mdev) /* 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 (mt7615_pm_wake(dev)) + return; + + __mt7615_update_channel(dev); + mt7615_pm_power_save_sched(dev); +} 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); + 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); +} + static void mt7615_mac_update_mib_stats(struct mt7615_phy *phy) { @@ -1889,7 +1913,7 @@ void mt7615_mac_work(struct work_struct *work) mt7615_mutex_acquire(phy->dev); - mt76_update_survey(mdev); + mt7615_update_survey(phy->dev); if (++phy->mac_work_count == 5) { phy->mac_work_count = 0; -- cgit v1.2.3 From 3d0558c82200f86715f0db59e636144551c7c0ba Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:48 +0200 Subject: mt76: mt7615: acquire driver_own before configuring device for suspend Make sure to wake the device in mt7615_pci_suspend in order to properly configure device registers before suspend Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/pci.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c index ba12f199bce0..2328d78e06a1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c @@ -75,6 +75,10 @@ static int mt7615_pci_suspend(struct pci_dev *pdev, pm_message_t state) bool hif_suspend; int i, err; + err = mt7615_pm_wake(dev); + if (err < 0) + return err; + hif_suspend = !test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) && mt7615_firmware_offload(dev); if (hif_suspend) { -- cgit v1.2.3 From 888a678a64e08c4c0478daf773bf8f7a937895ed Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:49 +0200 Subject: mt76: mt7615: wake device before performing freq scan Set device in full power before performing hw scan or hw scheduled scan Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 34 +++++++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index d1ddd5b15955..eb56cd7cb429 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -915,17 +915,26 @@ static int mt7615_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_scan_request *req) { + struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt76_phy *mphy = hw->priv; + int err; - return mt7615_mcu_hw_scan(mphy->priv, vif, req); + mt7615_mutex_acquire(dev); + err = mt7615_mcu_hw_scan(mphy->priv, vif, req); + mt7615_mutex_release(dev); + + return err; } static void mt7615_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { + struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt76_phy *mphy = hw->priv; + mt7615_mutex_acquire(dev); mt7615_mcu_cancel_hw_scan(mphy->priv, vif); + mt7615_mutex_release(dev); } static int @@ -933,22 +942,35 @@ mt7615_start_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, struct ieee80211_scan_ies *ies) { + struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt76_phy *mphy = hw->priv; int err; + mt7615_mutex_acquire(dev); + err = mt7615_mcu_sched_scan_req(mphy->priv, vif, req); if (err < 0) - return err; + goto out; - return mt7615_mcu_sched_scan_enable(mphy->priv, vif, true); + err = mt7615_mcu_sched_scan_enable(mphy->priv, vif, true); +out: + mt7615_mutex_release(dev); + + return err; } static int mt7615_stop_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { + struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt76_phy *mphy = hw->priv; + int err; + + mt7615_mutex_acquire(dev); + err = mt7615_mcu_sched_scan_enable(mphy->priv, vif, false); + mt7615_mutex_release(dev); - return mt7615_mcu_sched_scan_enable(mphy->priv, vif, false); + return err; } static int mt7615_remain_on_channel(struct ieee80211_hw *hw, @@ -1074,7 +1096,11 @@ static void mt7615_set_rekey_data(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_gtk_rekey_data *data) { + struct mt7615_dev *dev = mt7615_hw_dev(hw); + + mt7615_mutex_acquire(dev); mt7615_mcu_update_gtk_rekey(hw, vif, data); + mt7615_mutex_release(dev); } #endif /* CONFIG_PM */ -- cgit v1.2.3 From 030aaeddbab161403aa4e4f34b84971bb5db7a9f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:50 +0200 Subject: mt76: mt7615: add missing lock in mt7615_regd_notifier Make sure to run mt7615_dfs_init_radar_detector in mt7615_regd_notifier holding mt76 mutex in order to avoid races and set the device in full power Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 5bb87dd21279..fdc40a1c84c4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -285,7 +285,9 @@ mt7615_regd_notifier(struct wiphy *wiphy, if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR)) return; + mt7615_mutex_acquire(dev); mt7615_dfs_init_radar_detector(phy); + mt7615_mutex_release(dev); } static void -- cgit v1.2.3 From de1f66bab9b7d9c1c80ae18bb1d85b699bbf8f44 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:51 +0200 Subject: mt76: mt7615: run mt7615_mcu_set_wmm holding mt76 mutex Make sure to run mt7615_mcu_set_wmm() holding mt76 mutex in order to wake the device from low power state and avoid races Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index eb56cd7cb429..c52b5c68ba97 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -433,11 +433,17 @@ mt7615_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_dev *dev = mt7615_hw_dev(hw); + int err; + + mt7615_mutex_acquire(dev); queue = mt7615_lmac_mapping(dev, queue); queue += mvif->wmm_idx * MT7615_MAX_WMM_SETS; + err = mt7615_mcu_set_wmm(dev, queue, params); - return mt7615_mcu_set_wmm(dev, queue, params); + mt7615_mutex_release(dev); + + return err; } static void mt7615_configure_filter(struct ieee80211_hw *hw, -- cgit v1.2.3 From 46dadc3104415ad834db1be3208311fd5f02e3ab Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:52 +0200 Subject: mt76: mt7615: run mt7615_mcu_set_roc holding mt76 mutex Make sure to run mt7615_mcu_set_roc() holding mt76 mutex in order to wake the device from low power state and avoid races Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index c52b5c68ba97..47dca270150d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -871,9 +871,11 @@ void mt7615_roc_work(struct work_struct *work) if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) return; + mt7615_mutex_acquire(phy->dev); ieee80211_iterate_active_interfaces(phy->mt76->hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7615_roc_iter, phy); + mt7615_mutex_release(phy->dev); ieee80211_remain_on_channel_expired(phy->mt76->hw); } @@ -991,20 +993,24 @@ static int mt7615_remain_on_channel(struct ieee80211_hw *hw, if (test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state)) return 0; + mt7615_mutex_acquire(phy->dev); + err = mt7615_mcu_set_roc(phy, vif, chan, duration); if (err < 0) { clear_bit(MT76_STATE_ROC, &phy->mt76->state); - return err; + goto out; } if (!wait_event_timeout(phy->roc_wait, phy->roc_grant, HZ)) { mt7615_mcu_set_roc(phy, vif, NULL, 0); clear_bit(MT76_STATE_ROC, &phy->mt76->state); - - return -ETIMEDOUT; + err = -ETIMEDOUT; } - return 0; +out: + mt7615_mutex_release(phy->dev); + + return err; } static int mt7615_cancel_remain_on_channel(struct ieee80211_hw *hw, @@ -1018,7 +1024,9 @@ static int mt7615_cancel_remain_on_channel(struct ieee80211_hw *hw, del_timer_sync(&phy->roc_timer); cancel_work_sync(&phy->roc_work); + mt7615_mutex_acquire(phy->dev); mt7615_mcu_set_roc(phy, vif, NULL, 0); + mt7615_mutex_release(phy->dev); return 0; } -- cgit v1.2.3 From 5cf8f7794d32e3ea7af6f04139a77157c536d4b5 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:53 +0200 Subject: mt76: mt7615: wake device before pulling packets from mac80211 queues Make sure the device is in full-power before pulling frames from mac80211 queues Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 6 +++++- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 20 +++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index e17cba62252f..f340e74c1a71 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1841,9 +1841,13 @@ void mt7615_pm_wake_work(struct work_struct *work) pm.wake_work); mphy = dev->phy.mt76; - if (mt7615_driver_own(dev)) + if (mt7615_driver_own(dev)) { dev_err(mphy->dev->dev, "failed to wake device\n"); + goto out; + } + tasklet_schedule(&dev->mt76.tx_tasklet); +out: complete_all(&dev->pm.wake_cmpl); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 47dca270150d..3ff387f31659 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -638,6 +638,24 @@ static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw, spin_unlock_bh(&dev->mt76.lock); } +static void +mt7615_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq) +{ + struct mt7615_dev *dev = mt7615_hw_dev(hw); + struct mt7615_phy *phy = mt7615_hw_phy(hw); + struct mt76_phy *mphy = phy->mt76; + + if (!test_bit(MT76_STATE_RUNNING, &mphy->state)) + return; + + if (test_bit(MT76_STATE_PM, &mphy->state)) { + queue_work(dev->mt76.wq, &dev->pm.wake_work); + return; + } + + tasklet_schedule(&dev->mt76.tx_tasklet); +} + static void mt7615_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) @@ -1134,7 +1152,7 @@ const struct ieee80211_ops mt7615_ops = { .set_key = mt7615_set_key, .ampdu_action = mt7615_ampdu_action, .set_rts_threshold = mt7615_set_rts_threshold, - .wake_tx_queue = mt76_wake_tx_queue, + .wake_tx_queue = mt7615_wake_tx_queue, .sta_rate_tbl_update = mt7615_sta_rate_tbl_update, .sw_scan_start = mt76_sw_scan, .sw_scan_complete = mt76_sw_scan_complete, -- cgit v1.2.3 From 2b8cdfb28d3402b25fab47ffe70b6d858d26a2c1 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:54 +0200 Subject: mt76: mt7615: wake device before pushing frames in mt7615_tx Queue frames pushed by mac80211 running mt7615_tx if the device is low-power state. Run wake workqueue in order to swicth to full-power before transmitting pending frames Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 25 +++++++++- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 56 +++++++++++++++++++--- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 6 +++ 4 files changed, 81 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index fdc40a1c84c4..02a82cd848c4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -441,6 +441,7 @@ void mt7615_init_device(struct mt7615_dev *dev) INIT_DELAYED_WORK(&dev->pm.ps_work, mt7615_pm_power_save_work); INIT_WORK(&dev->pm.wake_work, mt7615_pm_wake_work); init_completion(&dev->pm.wake_cmpl); + spin_lock_init(&dev->pm.txq_lock); INIT_DELAYED_WORK(&dev->phy.mac_work, mt7615_mac_work); INIT_DELAYED_WORK(&dev->phy.scan_work, mt7615_scan_work); skb_queue_head_init(&dev->phy.scan_event_list); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index f340e74c1a71..09885ab30092 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1836,6 +1836,7 @@ void mt7615_pm_wake_work(struct work_struct *work) { struct mt7615_dev *dev; struct mt76_phy *mphy; + int i; dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, pm.wake_work); @@ -1846,8 +1847,28 @@ void mt7615_pm_wake_work(struct work_struct *work) goto out; } + spin_lock_bh(&dev->pm.txq_lock); + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + struct mt7615_sta *msta = dev->pm.tx_q[i].msta; + struct mt76_wcid *wcid = msta ? &msta->wcid : NULL; + struct ieee80211_sta *sta = NULL; + + if (!dev->pm.tx_q[i].skb) + continue; + + if (msta && wcid->sta) + sta = container_of((void *)msta, struct ieee80211_sta, + drv_priv); + + mt76_tx(mphy, sta, wcid, dev->pm.tx_q[i].skb); + dev->pm.tx_q[i].skb = NULL; + } + spin_unlock_bh(&dev->pm.txq_lock); + tasklet_schedule(&dev->mt76.tx_tasklet); + out: + ieee80211_wake_queues(mphy->hw); complete_all(&dev->pm.wake_cmpl); } @@ -1871,8 +1892,10 @@ int mt7615_pm_wake(struct mt7615_dev *dev) if (queue_work(dev->mt76.wq, &dev->pm.wake_work)) reinit_completion(&dev->pm.wake_cmpl); - if (!wait_for_completion_timeout(&dev->pm.wake_cmpl, 3 * HZ)) + if (!wait_for_completion_timeout(&dev->pm.wake_cmpl, 3 * HZ)) { + ieee80211_wake_queues(mphy->hw); return -ETIMEDOUT; + } return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 3ff387f31659..57d5e3aa9439 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -24,6 +24,22 @@ static bool mt7615_dev_running(struct mt7615_dev *dev) return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state); } +static void mt7615_free_pending_tx_skbs(struct mt7615_dev *dev, + struct mt7615_sta *msta) +{ + int i; + + spin_lock_bh(&dev->pm.txq_lock); + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + if (msta && dev->pm.tx_q[i].msta != msta) + continue; + + dev_kfree_skb(dev->pm.tx_q[i].skb); + dev->pm.tx_q[i].skb = NULL; + } + spin_unlock_bh(&dev->pm.txq_lock); +} + static int mt7615_start(struct ieee80211_hw *hw) { struct mt7615_dev *dev = mt7615_hw_dev(hw); @@ -77,6 +93,8 @@ static void mt7615_stop(struct ieee80211_hw *hw) cancel_delayed_work_sync(&dev->pm.ps_work); cancel_work_sync(&dev->pm.wake_work); + mt7615_free_pending_tx_skbs(dev, NULL); + mt7615_mutex_acquire(dev); mt76_testmode_reset(&dev->mt76, true); @@ -214,6 +232,8 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw, if (vif == phy->monitor_vif) phy->monitor_vif = NULL; + mt7615_free_pending_tx_skbs(dev, msta); + mt7615_mcu_add_dev_info(dev, vif, false); rcu_assign_pointer(dev->mt76.wcid[idx], NULL); @@ -595,6 +615,8 @@ void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; + mt7615_free_pending_tx_skbs(dev, msta); + mt7615_mcu_sta_add(dev, vif, sta, false); mt7615_mac_wtbl_update(dev, msta->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); @@ -665,22 +687,43 @@ static void mt7615_tx(struct ieee80211_hw *hw, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; struct mt76_wcid *wcid = &dev->mt76.global_wcid; + struct mt7615_sta *msta = NULL; + int qid; if (control->sta) { - struct mt7615_sta *sta; - - sta = (struct mt7615_sta *)control->sta->drv_priv; - wcid = &sta->wcid; + msta = (struct mt7615_sta *)control->sta->drv_priv; + wcid = &msta->wcid; } if (vif && !control->sta) { struct mt7615_vif *mvif; mvif = (struct mt7615_vif *)vif->drv_priv; - wcid = &mvif->sta.wcid; + msta = &mvif->sta; + wcid = &msta->wcid; + } + + if (!test_bit(MT76_STATE_PM, &mphy->state)) { + mt76_tx(mphy, control->sta, wcid, skb); + return; + } + + qid = skb_get_queue_mapping(skb); + if (qid >= MT_TXQ_PSD) { + qid = IEEE80211_AC_BE; + skb_set_queue_mapping(skb, qid); } - mt76_tx(mphy, control->sta, wcid, skb); + spin_lock_bh(&dev->pm.txq_lock); + if (!dev->pm.tx_q[qid].skb) { + ieee80211_stop_queues(hw); + dev->pm.tx_q[qid].msta = msta; + dev->pm.tx_q[qid].skb = skb; + queue_work(dev->mt76.wq, &dev->pm.wake_work); + } else { + dev_kfree_skb(skb); + } + spin_unlock_bh(&dev->pm.txq_lock); } static int mt7615_set_rts_threshold(struct ieee80211_hw *hw, u32 val) @@ -1059,6 +1102,7 @@ static int mt7615_suspend(struct ieee80211_hw *hw, int err = 0; cancel_delayed_work_sync(&dev->pm.ps_work); + mt7615_free_pending_tx_skbs(dev, NULL); mt7615_mutex_acquire(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 3c5cd7f0ea1e..cc1f76adc975 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -302,6 +302,12 @@ struct mt7615_dev { struct { bool enable; + spinlock_t txq_lock; + struct { + struct mt7615_sta *msta; + struct sk_buff *skb; + } tx_q[IEEE80211_NUM_ACS]; + struct work_struct wake_work; struct completion wake_cmpl; -- cgit v1.2.3 From 1eae3fb949c146c10476692fb4625290c7060676 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:55 +0200 Subject: mt76: mt7615: run mt7615_pm_wake in mt7615_mac_sta_{add,remove} Run mt7615_pm_wake()/mt7615_pm_power_save_sched() directly in order to wake the device from low power state in mt7615_mac_sta_{add,remove} since they run holding mt76 mutex in common mt76 code Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 57d5e3aa9439..de4230b2d7bb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -583,7 +583,7 @@ int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - int idx; + int idx, err; idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7615_WTBL_STA - 1); if (idx < 0) @@ -595,6 +595,10 @@ int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, msta->wcid.idx = idx; msta->wcid.ext_phy = mvif->band_idx; + err = mt7615_pm_wake(dev); + if (err) + return err; + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { struct mt7615_phy *phy; @@ -605,6 +609,8 @@ int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); mt7615_mcu_sta_add(dev, vif, sta, true); + mt7615_pm_power_save_sched(dev); + return 0; } EXPORT_SYMBOL_GPL(mt7615_mac_sta_add); @@ -616,6 +622,7 @@ void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; mt7615_free_pending_tx_skbs(dev, msta); + mt7615_pm_wake(dev); mt7615_mcu_sta_add(dev, vif, sta, false); mt7615_mac_wtbl_update(dev, msta->wcid.idx, @@ -632,6 +639,8 @@ void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (!list_empty(&msta->poll_list)) list_del_init(&msta->poll_list); spin_unlock_bh(&dev->sta_poll_lock); + + mt7615_pm_power_save_sched(dev); } EXPORT_SYMBOL_GPL(mt7615_mac_sta_remove); -- cgit v1.2.3 From a2b30bd4096e5c95a7fed72102de6fff2b138ff7 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:56 +0200 Subject: mt76: mt7615: check MT76_STATE_PM flag before accessing the device Double-check if the device is in low-power state before accessing registermap in mt7615_sta_rate_tbl_update() and in mt7615_led_set_config() Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 6 ++++-- drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index de4230b2d7bb..0ce76472df2c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -664,8 +664,10 @@ static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw, break; } msta->n_rates = i; - mt7615_mac_set_rates(phy, msta, NULL, msta->rates); - msta->rate_probe = false; + if (!test_bit(MT76_STATE_PM, &phy->mt76->state)) { + mt7615_mac_set_rates(phy, msta, NULL, msta->rates); + msta->rate_probe = false; + } spin_unlock_bh(&dev->mt76.lock); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c index 69cba8609edf..7224a0078211 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c @@ -70,6 +70,10 @@ mt7615_led_set_config(struct led_classdev *led_cdev, mt76 = container_of(led_cdev, struct mt76_dev, led_cdev); dev = container_of(mt76, struct mt7615_dev, mt76); + + if (test_bit(MT76_STATE_PM, &mt76->phy.state)) + return; + val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xffff) | FIELD_PREP(MT_LED_STATUS_OFF, delay_off) | FIELD_PREP(MT_LED_STATUS_ON, delay_on); -- cgit v1.2.3 From 1f549009b5b2f26db01e334dc00db160ee12c0e1 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:57 +0200 Subject: mt76: mt7615: do not request {driver,fw}_own if already granted Check MT76_STATE_PM in mt7615_driver_own/mt7615_firmware_own in order to not requested power ownership if it is already granted Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 21 +++++++++++---------- drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c | 2 ++ 3 files changed, 14 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 02a82cd848c4..b3f0e2cae040 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -442,6 +442,7 @@ void mt7615_init_device(struct mt7615_dev *dev) INIT_WORK(&dev->pm.wake_work, mt7615_pm_wake_work); init_completion(&dev->pm.wake_cmpl); spin_lock_init(&dev->pm.txq_lock); + set_bit(MT76_STATE_PM, &dev->mphy.state); INIT_DELAYED_WORK(&dev->phy.mac_work, mt7615_mac_work); INIT_DELAYED_WORK(&dev->phy.scan_work, mt7615_scan_work); skb_queue_head_init(&dev->phy.scan_event_list); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 72cfc197b936..6118c2eeece8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1894,6 +1894,9 @@ int mt7615_driver_own(struct mt7615_dev *dev) int err = 0; u32 addr; + if (!test_and_clear_bit(MT76_STATE_PM, &mphy->state)) + goto out; + mt7622_trigger_hif_int(dev, true); addr = is_mt7663(mdev) ? MT_PCIE_DOORBELL_PUSH : MT_CFG_LPCR_HOST; @@ -1901,15 +1904,13 @@ int mt7615_driver_own(struct mt7615_dev *dev) addr = is_mt7663(mdev) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST; if (!mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000)) { - dev_err(dev->mt76.dev, "Timeout for driver own\n"); + dev_err(mdev->dev, "Timeout for driver own\n"); + set_bit(MT76_STATE_PM, &mphy->state); err = -EIO; - goto out; } - clear_bit(MT76_STATE_PM, &mphy->state); - -out: mt7622_trigger_hif_int(dev, false); +out: dev->pm.last_activity = jiffies; return err; @@ -1922,22 +1923,22 @@ int mt7615_firmware_own(struct mt7615_dev *dev) int err = 0; u32 addr; - addr = is_mt7663(&dev->mt76) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST; + if (test_and_set_bit(MT76_STATE_PM, &mphy->state)) + return 0; + mt7622_trigger_hif_int(dev, true); + addr = is_mt7663(&dev->mt76) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST; mt76_wr(dev, addr, MT_CFG_LPCR_HOST_FW_OWN); if (is_mt7622(&dev->mt76) && !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, MT_CFG_LPCR_HOST_FW_OWN, 300)) { dev_err(dev->mt76.dev, "Timeout for firmware own\n"); + clear_bit(MT76_STATE_PM, &mphy->state); err = -EIO; - goto out; } - set_bit(MT76_STATE_PM, &mphy->state); - -out: mt7622_trigger_hif_int(dev, false); return err; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c index cd709fd617db..54885ad97891 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c @@ -60,6 +60,8 @@ int mt7663u_mcu_init(struct mt7615_dev *dev) dev->mt76.mcu_ops = &mt7663u_mcu_ops, + /* usb does not support runtime-pm */ + clear_bit(MT76_STATE_PM, &dev->mphy.state); mt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); if (test_and_clear_bit(MT76_STATE_POWER_OFF, &dev->mphy.state)) { -- cgit v1.2.3 From b5b4c7ddf11063dbc231a1ac955eff117d93fd70 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:58 +0200 Subject: mt76: mt7615: add runtime-pm knob in mt7615 debugfs Introduce runtime-pm knob in mt7615 debugfs in order to enable/disable runtime pm available in offload firmware Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7615/debugfs.c | 24 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 17 +++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 1 + 3 files changed, 42 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index 8894a0ab407b..77889becf22e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -51,6 +51,29 @@ mt7615_scs_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(fops_scs, mt7615_scs_get, mt7615_scs_set, "%lld\n"); +static int +mt7615_pm_set(void *data, u64 val) +{ + struct mt7615_dev *dev = data; + + if (!mt7615_wait_for_mcu_init(dev)) + return 0; + + return mt7615_pm_set_enable(dev, val); +} + +static int +mt7615_pm_get(void *data, u64 *val) +{ + struct mt7615_dev *dev = data; + + *val = dev->pm.enable; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_pm, mt7615_pm_get, mt7615_pm_set, "%lld\n"); + static int mt7615_dbdc_set(void *data, u64 val) { @@ -351,6 +374,7 @@ int mt7615_init_debugfs(struct mt7615_dev *dev) debugfs_create_file("scs", 0600, dir, dev, &fops_scs); debugfs_create_file("dbdc", 0600, dir, dev, &fops_dbdc); debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug); + debugfs_create_file("runtime-pm", 0600, dir, dev, &fops_pm); debugfs_create_devm_seqfile(dev->mt76.dev, "radio", dir, mt7615_radio_read); debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 09885ab30092..59f788be7268 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1929,6 +1929,23 @@ void mt7615_pm_power_save_work(struct work_struct *work) MT7615_PM_TIMEOUT); } +int mt7615_pm_set_enable(struct mt7615_dev *dev, bool enable) +{ + if (!mt7615_firmware_offload(dev) || !mt76_is_mmio(&dev->mt76)) + return -EOPNOTSUPP; + + mt7615_mutex_acquire(dev); + + if (dev->pm.enable == enable) + goto out; + + dev->pm.enable = enable; +out: + mt7615_mutex_release(dev); + + return 0; +} + void mt7615_mac_work(struct work_struct *work) { 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 cc1f76adc975..ad7b206ab043 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -443,6 +443,7 @@ bool mt7615_wait_for_mcu_init(struct mt7615_dev *dev); void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, struct ieee80211_tx_rate *probe_rate, struct ieee80211_tx_rate *rates); +int mt7615_pm_set_enable(struct mt7615_dev *dev, bool enable); void mt7615_pm_wake_work(struct work_struct *work); int mt7615_pm_wake(struct mt7615_dev *dev); void mt7615_pm_power_save_sched(struct mt7615_dev *dev); -- cgit v1.2.3 From 83b9f42aea988274195ae31df5af5b4a5328886d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:15:59 +0200 Subject: mt76: mt7615: enable beacon hw filter for runtime-pm In order to reduce number of received interrupts and power consumption, enable hw beacon filter if runtime-pm is enabled Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 26 ++++++++ drivers/net/wireless/mediatek/mt76/mt7615/main.c | 19 ++++++ drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 73 +++++++++++----------- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 2 + 4 files changed, 83 insertions(+), 37 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 59f788be7268..1c86ecf8fcd9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1929,8 +1929,31 @@ void mt7615_pm_power_save_work(struct work_struct *work) MT7615_PM_TIMEOUT); } +static void +mt7615_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + struct mt7615_phy *phy = priv; + struct mt7615_dev *dev = phy->dev; + bool ext_phy = phy != &dev->phy; + + if (mt7615_mcu_set_bss_pm(dev, vif, dev->pm.enable)) + return; + + if (dev->pm.enable) { + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + mt76_set(dev, MT_WF_RFCR(ext_phy), + MT_WF_RFCR_DROP_OTHER_BEACON); + } else { + vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; + mt76_clear(dev, MT_WF_RFCR(ext_phy), + MT_WF_RFCR_DROP_OTHER_BEACON); + } +} + int mt7615_pm_set_enable(struct mt7615_dev *dev, bool enable) { + struct mt76_phy *mphy = dev->phy.mt76; + if (!mt7615_firmware_offload(dev) || !mt76_is_mmio(&dev->mt76)) return -EOPNOTSUPP; @@ -1940,6 +1963,9 @@ int mt7615_pm_set_enable(struct mt7615_dev *dev, bool enable) goto out; dev->pm.enable = enable; + ieee80211_iterate_active_interfaces(mphy->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7615_pm_interface_iter, mphy->priv); out: mt7615_mutex_release(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 0ce76472df2c..b1cfae7c4b55 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -209,6 +209,18 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, } ret = mt7615_mcu_add_dev_info(dev, vif, true); + if (ret) + goto out; + + if (dev->pm.enable) { + ret = mt7615_mcu_set_bss_pm(dev, vif, true); + if (ret) + goto out; + + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + mt76_set(dev, MT_WF_RFCR(ext_phy), + MT_WF_RFCR_DROP_OTHER_BEACON); + } out: mt7615_mutex_release(dev); @@ -234,6 +246,13 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw, mt7615_free_pending_tx_skbs(dev, msta); + if (dev->pm.enable) { + bool ext_phy = phy != &dev->phy; + + mt7615_mcu_set_bss_pm(dev, vif, false); + mt76_clear(dev, MT_WF_RFCR(ext_phy), + MT_WF_RFCR_DROP_OTHER_BEACON); + } mt7615_mcu_add_dev_info(dev, vif, false); rcu_assign_pointer(dev->mt76.wcid[idx], NULL); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 6118c2eeece8..2d1015451699 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -3460,43 +3460,8 @@ out: return ret; } -#ifdef CONFIG_PM -int mt7615_mcu_set_hif_suspend(struct mt7615_dev *dev, bool suspend) -{ - struct { - struct { - u8 hif_type; /* 0x0: HIF_SDIO - * 0x1: HIF_USB - * 0x2: HIF_PCIE - */ - u8 pad[3]; - } __packed hdr; - struct hif_suspend_tlv { - __le16 tag; - __le16 len; - u8 suspend; - } __packed hif_suspend; - } req = { - .hif_suspend = { - .tag = cpu_to_le16(0), /* 0: UNI_HIF_CTRL_BASIC */ - .len = cpu_to_le16(sizeof(struct hif_suspend_tlv)), - .suspend = suspend, - }, - }; - - if (mt76_is_mmio(&dev->mt76)) - req.hdr.hif_type = 2; - else if (mt76_is_usb(&dev->mt76)) - req.hdr.hif_type = 1; - - return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_HIF_CTRL, - &req, sizeof(req), true); -} -EXPORT_SYMBOL_GPL(mt7615_mcu_set_hif_suspend); - -static int -mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, - bool enable) +int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, + bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct { @@ -3536,6 +3501,40 @@ mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, &req, sizeof(req), false); } +#ifdef CONFIG_PM +int mt7615_mcu_set_hif_suspend(struct mt7615_dev *dev, bool suspend) +{ + struct { + struct { + u8 hif_type; /* 0x0: HIF_SDIO + * 0x1: HIF_USB + * 0x2: HIF_PCIE + */ + u8 pad[3]; + } __packed hdr; + struct hif_suspend_tlv { + __le16 tag; + __le16 len; + u8 suspend; + } __packed hif_suspend; + } req = { + .hif_suspend = { + .tag = cpu_to_le16(0), /* 0: UNI_HIF_CTRL_BASIC */ + .len = cpu_to_le16(sizeof(struct hif_suspend_tlv)), + .suspend = suspend, + }, + }; + + if (mt76_is_mmio(&dev->mt76)) + req.hdr.hif_type = 2; + else if (mt76_is_usb(&dev->mt76)) + req.hdr.hif_type = 1; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_HIF_CTRL, + &req, sizeof(req), true); +} +EXPORT_SYMBOL_GPL(mt7615_mcu_set_hif_suspend); + static int mt7615_mcu_set_wow_ctrl(struct mt7615_phy *phy, struct ieee80211_vif *vif, bool suspend, struct cfg80211_wowlan *wowlan) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index ad7b206ab043..9bbfe1168208 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -640,6 +640,8 @@ int mt7615_driver_own(struct mt7615_dev *dev); int mt7615_init_debugfs(struct mt7615_dev *dev); int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq); +int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, + bool enable); int mt7615_mcu_set_hif_suspend(struct mt7615_dev *dev, bool suspend); void mt7615_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif); -- cgit v1.2.3 From ec4b9f380c15933e3dea72bb4723ea5e21d35b13 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:16:00 +0200 Subject: mt76: mt7615: add idle-timeout knob in mt7615 debugfs Introduce idle-timeout knob in mt7615 debugfs in order to configure the idle time to switch to low-power state Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7615/debugfs.c | 25 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/init.c | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 1 + 4 files changed, 29 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index 77889becf22e..88931658a9fb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -74,6 +74,29 @@ mt7615_pm_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(fops_pm, mt7615_pm_get, mt7615_pm_set, "%lld\n"); +static int +mt7615_pm_idle_timeout_set(void *data, u64 val) +{ + struct mt7615_dev *dev = data; + + dev->pm.idle_timeout = msecs_to_jiffies(val); + + return 0; +} + +static int +mt7615_pm_idle_timeout_get(void *data, u64 *val) +{ + struct mt7615_dev *dev = data; + + *val = jiffies_to_msecs(dev->pm.idle_timeout); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_pm_idle_timeout, mt7615_pm_idle_timeout_get, + mt7615_pm_idle_timeout_set, "%lld\n"); + static int mt7615_dbdc_set(void *data, u64 val) { @@ -375,6 +398,8 @@ int mt7615_init_debugfs(struct mt7615_dev *dev) debugfs_create_file("dbdc", 0600, dir, dev, &fops_dbdc); debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug); debugfs_create_file("runtime-pm", 0600, dir, dev, &fops_pm); + debugfs_create_file("idle-timeout", 0600, dir, dev, + &fops_pm_idle_timeout); debugfs_create_devm_seqfile(dev->mt76.dev, "radio", dir, mt7615_radio_read); debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index b3f0e2cae040..fc1ebabfebac 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -456,6 +456,7 @@ void mt7615_init_device(struct mt7615_dev *dev) timer_setup(&dev->phy.roc_timer, mt7615_roc_timer, 0); mt7615_init_wiphy(hw); + dev->pm.idle_timeout = MT7615_PM_TIMEOUT; dev->mphy.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; dev->mphy.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; dev->mphy.sband_5g.sband.vht_cap.cap |= diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 1c86ecf8fcd9..abb81a56e908 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1913,7 +1913,7 @@ void mt7615_pm_power_save_sched(struct mt7615_dev *dev) dev->pm.last_activity = jiffies; if (!test_bit(MT76_STATE_PM, &mphy->state)) queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, - MT7615_PM_TIMEOUT); + dev->pm.idle_timeout); } EXPORT_SYMBOL_GPL(mt7615_pm_power_save_sched); @@ -1926,7 +1926,7 @@ void mt7615_pm_power_save_work(struct work_struct *work) if (mt7615_firmware_own(dev)) queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, - MT7615_PM_TIMEOUT); + dev->pm.idle_timeout); } static void diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 9bbfe1168208..9f258270c435 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -313,6 +313,7 @@ struct mt7615_dev { struct delayed_work ps_work; unsigned long last_activity; + unsigned long idle_timeout; } pm; }; -- cgit v1.2.3 From 894b7767ec2fc21574775c354ab5350e51c2171c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:16:01 +0200 Subject: mt76: mt7615: improve mt7615_driver_own reliability mt7615_driver_own can fail if it runs too close to mt7615_fw_own. In order to improve mt7615_driver_own reliability, retry to get runtime-pm ownership if mt7615_driver_own fails Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 27 ++++++++++++++-------- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 2 ++ 2 files changed, 19 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 2d1015451699..2e9e0002331e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1891,29 +1891,36 @@ int mt7615_driver_own(struct mt7615_dev *dev) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_dev *mdev = &dev->mt76; - int err = 0; - u32 addr; + int i; if (!test_and_clear_bit(MT76_STATE_PM, &mphy->state)) goto out; mt7622_trigger_hif_int(dev, true); - addr = is_mt7663(mdev) ? MT_PCIE_DOORBELL_PUSH : MT_CFG_LPCR_HOST; - mt76_wr(dev, addr, MT_CFG_LPCR_HOST_DRV_OWN); + for (i = 0; i < MT7615_DRV_OWN_RETRY_COUNT; i++) { + u32 addr; - addr = is_mt7663(mdev) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST; - if (!mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000)) { - dev_err(mdev->dev, "Timeout for driver own\n"); - set_bit(MT76_STATE_PM, &mphy->state); - err = -EIO; + addr = is_mt7663(mdev) ? MT_PCIE_DOORBELL_PUSH : MT_CFG_LPCR_HOST; + mt76_wr(dev, addr, MT_CFG_LPCR_HOST_DRV_OWN); + + addr = is_mt7663(mdev) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST; + if (mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 0, 50)) + break; } mt7622_trigger_hif_int(dev, false); + + if (i == MT7615_DRV_OWN_RETRY_COUNT) { + dev_err(mdev->dev, "driver own failed\n"); + set_bit(MT76_STATE_PM, &mphy->state); + return -EIO; + } + out: dev->pm.last_activity = jiffies; - return err; + return 0; } EXPORT_SYMBOL_GPL(mt7615_driver_own); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 9f258270c435..688bd7b68668 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -33,6 +33,8 @@ #define MT7615_RX_RING_SIZE 1024 #define MT7615_RX_MCU_RING_SIZE 512 +#define MT7615_DRV_OWN_RETRY_COUNT 10 + #define MT7615_FIRMWARE_CR4 "mediatek/mt7615_cr4.bin" #define MT7615_FIRMWARE_N9 "mediatek/mt7615_n9.bin" #define MT7615_ROM_PATCH "mediatek/mt7615_rom_patch.bin" -- cgit v1.2.3 From 4bb586bc33b9845d76fc8d4efc2910e37876c399 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Jul 2020 10:17:35 +0200 Subject: mt76: mt7663u: sync probe sampling with rate configuration On usb device rate configuration for sampling is performed relying on a workqueue since it is not possible to access the device in the interrupt context. Move the configuration of the probe_rate flag in the workqueue in order to keep probe sampling in sync with actual rate configuration Fixes: eb99cc95c3b6 ("mt76: mt7615: introduce mt7663u support") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 5 +++- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 4 +--- .../net/wireless/mediatek/mt76/mt7615/pci_mac.c | 1 - drivers/net/wireless/mediatek/mt76/mt7615/usb.c | 28 +++++++++++++--------- 4 files changed, 22 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index abb81a56e908..af5716797475 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -917,6 +917,9 @@ mt7615_mac_queue_rate_update(struct mt7615_phy *phy, struct mt7615_sta *sta, struct mt7615_dev *dev = phy->dev; struct mt7615_wtbl_desc *wd; + if (work_pending(&dev->wtbl_work)) + return -EBUSY; + wd = kzalloc(sizeof(*wd), GFP_ATOMIC); if (!wd) return -ENOMEM; @@ -1023,6 +1026,7 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, sta->rate_count = 2 * MT7615_RATE_RETRY * n_rates; sta->wcid.tx_info |= MT_WCID_TX_INFO_SET; + sta->rate_probe = !!probe_rate; } EXPORT_SYMBOL_GPL(mt7615_mac_set_rates); @@ -1231,7 +1235,6 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta, phy = dev->mt76.phy2->priv; mt7615_mac_set_rates(phy, sta, NULL, sta->rates); - sta->rate_probe = false; } spin_unlock_bh(&dev->mt76.lock); } else { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index b1cfae7c4b55..79453c890f20 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -683,10 +683,8 @@ static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw, break; } msta->n_rates = i; - if (!test_bit(MT76_STATE_PM, &phy->mt76->state)) { + if (!test_bit(MT76_STATE_PM, &phy->mt76->state)) mt7615_mac_set_rates(phy, msta, NULL, msta->rates); - msta->rate_probe = false; - } spin_unlock_bh(&dev->mt76.lock); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c index 7ec91c0856f5..2d67f9a148cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c @@ -155,7 +155,6 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, spin_lock_bh(&dev->mt76.lock); mt7615_mac_set_rates(phy, msta, &info->control.rates[0], msta->rates); - msta->rate_probe = true; spin_unlock_bh(&dev->mt76.lock); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c index a780127377bf..feda5d0c171e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -140,6 +140,8 @@ __mt7663u_mac_set_rates(struct mt7615_dev *dev, mt76_wr(dev, addr + 27 * 4, w27); + sta->rate_probe = sta->rateset[rate->rateset].probe_rate.idx != -1; + mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* TSF read */ val = mt76_rr(dev, MT_LPON_UTTR0); sta->rate_set_tsf = (val & ~BIT(0)) | rate->rateset; @@ -196,17 +198,21 @@ __mt7663u_mac_set_key(struct mt7615_dev *dev, void mt7663u_wtbl_work(struct work_struct *work) { struct mt7615_wtbl_desc *wd, *wd_next; + struct list_head wd_list; struct mt7615_dev *dev; dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, wtbl_work); - mt7615_mutex_acquire(dev); + INIT_LIST_HEAD(&wd_list); + spin_lock_bh(&dev->mt76.lock); + list_splice_init(&dev->wd_head, &wd_list); + spin_unlock_bh(&dev->mt76.lock); - list_for_each_entry_safe(wd, wd_next, &dev->wd_head, node) { - spin_lock_bh(&dev->mt76.lock); + list_for_each_entry_safe(wd, wd_next, &wd_list, node) { list_del(&wd->node); - spin_unlock_bh(&dev->mt76.lock); + + mt7615_mutex_acquire(dev); switch (wd->type) { case MT7615_WTBL_RATE_DESC: @@ -216,10 +222,11 @@ void mt7663u_wtbl_work(struct work_struct *work) __mt7663u_mac_set_key(dev, wd); break; } + + mt7615_mutex_release(dev); + kfree(wd); } - - mt7615_mutex_release(dev); } static void @@ -236,17 +243,16 @@ mt7663u_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 ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); - if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) { - struct mt7615_sta *msta; - - msta = container_of(wcid, struct mt7615_sta, wcid); + if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && + !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], msta->rates); - msta->rate_probe = true; spin_unlock_bh(&dev->mt76.lock); } mt7663u_mac_write_txwi(dev, wcid, qid, sta, tx_info->skb); -- cgit v1.2.3 From e9eb59c60d21ba3433868c89eb2460e70a2101fd Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 7 Jul 2020 23:23:11 +0200 Subject: mt76: mt7615: avoid scheduling runtime-pm during hw scan Do not schedule ps_work during hw scanning or hw scheduled frequency scan Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index af5716797475..1c440ed183ee 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1908,12 +1908,21 @@ void mt7615_pm_power_save_sched(struct mt7615_dev *dev) { struct mt76_phy *mphy = dev->phy.mt76; - if (!mt7615_firmware_offload(dev) || - !dev->pm.enable || !mt76_is_mmio(mphy->dev) || - !test_bit(MT76_STATE_RUNNING, &mphy->state)) + if (!mt7615_firmware_offload(dev)) + return; + + if (!mt76_is_mmio(mphy->dev)) + return; + + if (!dev->pm.enable || !test_bit(MT76_STATE_RUNNING, &mphy->state)) return; dev->pm.last_activity = jiffies; + + if (test_bit(MT76_HW_SCANNING, &mphy->state) || + test_bit(MT76_HW_SCHED_SCANNING, &mphy->state)) + return; + if (!test_bit(MT76_STATE_PM, &mphy->state)) queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, dev->pm.idle_timeout); -- cgit v1.2.3 From d71d67a706352b0111a17fc8d005aeceb9a5ffd1 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 7 Jul 2020 23:27:20 +0200 Subject: mt76: mt7615: reschedule ps work according to last activity Reschedule runtime-pm delayed work if there is a new activity when ps delayed work is already scheduled Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 1c440ed183ee..126c54afefd4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1932,13 +1932,21 @@ EXPORT_SYMBOL_GPL(mt7615_pm_power_save_sched); void mt7615_pm_power_save_work(struct work_struct *work) { struct mt7615_dev *dev; + unsigned long delta; dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, pm.ps_work.work); - if (mt7615_firmware_own(dev)) - queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, - dev->pm.idle_timeout); + delta = dev->pm.idle_timeout; + if (time_is_after_jiffies(dev->pm.last_activity + delta)) { + delta = dev->pm.last_activity + delta - jiffies; + goto out; + } + + if (!mt7615_firmware_own(dev)) + return; +out: + queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta); } static void -- cgit v1.2.3 From 4a850f8dc68b8c4a20333521b31600c9d31ccb5d Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 8 Jul 2020 03:16:46 +0800 Subject: mt76: mt7663u: fix memory leak in set key Fix memory leak in set key. Fixes: eb99cc95c3b6 ("mt76: mt7615: introduce mt7663u support") Signed-off-by: Sean Wang Acked-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/usb.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c index feda5d0c171e..1f1578895ed5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -167,12 +167,16 @@ __mt7663u_mac_set_key(struct mt7615_dev *dev, lockdep_assert_held(&dev->mt76.mutex); - if (!sta) - return -EINVAL; + if (!sta) { + err = -EINVAL; + goto out; + } cipher = mt7615_mac_get_cipher(key->cipher); - if (cipher == MT_CIPHER_NONE) - return -EOPNOTSUPP; + if (cipher == MT_CIPHER_NONE) { + err = -EOPNOTSUPP; + goto out; + } wcid = &wd->sta->wcid; @@ -180,19 +184,22 @@ __mt7663u_mac_set_key(struct mt7615_dev *dev, err = mt7615_mac_wtbl_update_key(dev, wcid, key->key, key->keylen, cipher, key->cmd); if (err < 0) - return err; + goto out; err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, key->keyidx, key->cmd); if (err < 0) - return err; + goto out; if (key->cmd == SET_KEY) wcid->cipher |= BIT(cipher); else wcid->cipher &= ~BIT(cipher); - return 0; +out: + kfree(key->key); + + return err; } void mt7663u_wtbl_work(struct work_struct *work) -- cgit v1.2.3 From c876039e95559350ee101d4b6f6084d9803f2995 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 8 Jul 2020 03:16:47 +0800 Subject: mt76: mt7663u: fix potential memory leak in mcu message handler Fix potential memory leak in mcu message handler on error condition. Fixes: eb99cc95c3b6 ("mt76: mt7615: introduce mt7663u support") Acked-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c index 54885ad97891..39cd7dd95c9c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c @@ -34,7 +34,6 @@ mt7663u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, ret = mt76u_bulk_msg(&dev->mt76, skb->data, skb->len, NULL, 1000, ep); - dev_kfree_skb(skb); if (ret < 0) goto out; @@ -43,6 +42,7 @@ mt7663u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, out: mutex_unlock(&mdev->mcu.mutex); + dev_kfree_skb(skb); return ret; } -- cgit v1.2.3 From 9248c08c3fc4ef816c82aa49d01123f4746d349f Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 8 Jul 2020 03:16:48 +0800 Subject: mt76: mt7615: fix potential memory leak in mcu message handler Fix potential memory leak in mcu message handler on error condition. Fixes: 0e6a29e477f3 ("mt76: mt7615: add support to read temperature from mcu") Acked-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 2e9e0002331e..83e29ee7b08b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -183,8 +183,10 @@ mt7615_mcu_parse_response(struct mt7615_dev *dev, int cmd, struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; int ret = 0; - if (seq != rxd->seq) - return -EAGAIN; + if (seq != rxd->seq) { + ret = -EAGAIN; + goto out; + } switch (cmd) { case MCU_CMD_PATCH_SEM_CONTROL: @@ -215,6 +217,7 @@ mt7615_mcu_parse_response(struct mt7615_dev *dev, int cmd, default: break; } +out: dev_kfree_skb(skb); return ret; -- cgit v1.2.3 From eb744e5df86cf7e377d0acc4e686101b0fd9663a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 9 Jul 2020 14:04:35 +0300 Subject: mt76: mt7915: potential array overflow in mt7915_mcu_tx_rate_report() Smatch complains that "wcidx" value comes from the network and thus cannot be trusted. In this case, it actually seems to come from the firmware. If your wireless firmware is malicious then probably no amount of carefulness can protect you. On the other hand, these days we still try to check the firmware as much as possible. Verifying that the index is within bounds will silence a static checker warning. And it's harmless and a good exercise in kernel hardening. So I suggest that we do add a bounds check. Fixes: e57b7901469f ("mt76: add mac80211 driver for MT7915 PCIe-based chipsets") Signed-off-by: Dan Carpenter Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index fa9f32fa9f2e..93b1439e147b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -505,15 +505,22 @@ static void mt7915_mcu_tx_rate_report(struct mt7915_dev *dev, struct sk_buff *skb) { struct mt7915_mcu_ra_info *ra = (struct mt7915_mcu_ra_info *)skb->data; - u16 wcidx = le16_to_cpu(ra->wlan_idx); - struct mt76_wcid *wcid = rcu_dereference(dev->mt76.wcid[wcidx]); - struct mt7915_sta *msta = container_of(wcid, struct mt7915_sta, wcid); - struct mt7915_sta_stats *stats = &msta->stats; - struct mt76_phy *mphy = &dev->mphy; struct rate_info rate = {}, prob_rate = {}; + u16 probe = le16_to_cpu(ra->prob_up_rate); u16 attempts = le16_to_cpu(ra->attempts); u16 curr = le16_to_cpu(ra->curr_rate); - u16 probe = le16_to_cpu(ra->prob_up_rate); + u16 wcidx = le16_to_cpu(ra->wlan_idx); + struct mt76_phy *mphy = &dev->mphy; + struct mt7915_sta_stats *stats; + struct mt7915_sta *msta; + struct mt76_wcid *wcid; + + if (wcidx >= MT76_N_WCIDS) + return; + + wcid = rcu_dereference(dev->mt76.wcid[wcidx]); + msta = container_of(wcid, struct mt7915_sta, wcid); + stats = &msta->stats; if (msta->wcid.ext_phy && dev->mt76.phy2) mphy = dev->mt76.phy2; -- cgit v1.2.3 From a6e29d8ecd3d4eea8748d81d7b577083b4a7c441 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Mon, 15 Jun 2020 02:23:33 +0800 Subject: mt76: mt7915: add missing CONFIG_MAC80211_DEBUGFS Add CONFIG_MAC80211_DEBUGFS to fix a reported warning. Fixes: ec9742a8f38e ("mt76: mt7915: add .sta_add_debugfs support") Reported-by: kernel test robot Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 95e073c02ce6..38f473d587c9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -391,6 +391,7 @@ int mt7915_init_debugfs(struct mt7915_dev *dev) return 0; } +#ifdef CONFIG_MAC80211_DEBUGFS /** per-station debugfs **/ /* usage: */ @@ -468,3 +469,4 @@ void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, debugfs_create_file("fixed_rate", 0600, dir, sta, &fops_fixed_rate); debugfs_create_file("stats", 0400, dir, sta, &fops_sta_stats); } +#endif -- cgit v1.2.3 From cdcba424814d79e3dbffa06668f72099288a23f6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 15 Jul 2020 14:46:26 +0200 Subject: mt76: mt7615: take into account sdio bus configuring txwi usb and sdio relies on SF architecture. This is a preliminary patch to add SDIO support to mt76 driver Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 126c54afefd4..afac8d81d317 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -529,18 +529,18 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, struct ieee80211_sta *sta, int pid, struct ieee80211_key_conf *key, bool beacon) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rate = &info->control.rates[0]; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY; bool multicast = is_multicast_ether_addr(hdr->addr1); struct ieee80211_vif *vif = info->control.vif; + bool is_mmio = mt76_is_mmio(&dev->mt76); + u32 val, sz_txd = is_mmio ? MT_TXD_SIZE : MT_USB_TXD_SIZE; struct mt76_phy *mphy = &dev->mphy; - bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY; - bool is_usb = mt76_is_usb(&dev->mt76); - int tx_count = 8; - u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; __le16 fc = hdr->frame_control; - u32 val, sz_txd = is_usb ? MT_USB_TXD_SIZE : MT_TXD_SIZE; + int tx_count = 8; u16 seqno = 0; if (vif) { @@ -566,10 +566,10 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, p_fmt = MT_TX_TYPE_FW; q_idx = ext_phy ? MT_LMAC_BCN1 : MT_LMAC_BCN0; } else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) { - p_fmt = is_usb ? MT_TX_TYPE_SF : MT_TX_TYPE_CT; + p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; q_idx = ext_phy ? MT_LMAC_ALTX1 : MT_LMAC_ALTX0; } else { - p_fmt = is_usb ? MT_TX_TYPE_SF : MT_TX_TYPE_CT; + p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; q_idx = wmm_idx * MT7615_MAX_WMM_SETS + mt7615_lmac_mapping(dev, skb_get_queue_mapping(skb)); } @@ -675,7 +675,7 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, txwi[7] = FIELD_PREP(MT_TXD7_TYPE, fc_type) | FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype) | FIELD_PREP(MT_TXD7_SPE_IDX, 0x18); - if (is_usb) + if (!is_mmio) txwi[8] = FIELD_PREP(MT_TXD8_L_TYPE, fc_type) | FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype); -- cgit v1.2.3 From 75b10f0cbd0b9ff5d6a8f0c3ee5ce4193cd0450a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 15 Jul 2020 14:46:27 +0200 Subject: mt76: mt76u: add mt76_skb_adjust_pad utility routine Introduce mt76_skb_adjust_pad to reuse the code adding sdio support to mt7615 driver and remove code duplication. Move 4B header configuration for usb devices out of mt76_skb_adjust_pad Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/usb.c | 8 +++--- .../net/wireless/mediatek/mt76/mt7615/usb_mcu.c | 3 ++- .../net/wireless/mediatek/mt76/mt76x02_usb_core.c | 3 ++- drivers/net/wireless/mediatek/mt76/tx.c | 29 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/usb.c | 29 ---------------------- 6 files changed, 39 insertions(+), 35 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 532267056ff3..8ee159d614ae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1015,7 +1015,7 @@ mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int *actual_len, return usb_bulk_msg(udev, pipe, data, len, actual_len, timeout); } -int mt76u_skb_dma_info(struct sk_buff *skb, u32 info); +int mt76_skb_adjust_pad(struct sk_buff *skb); int mt76u_vendor_request(struct mt76_dev *dev, u8 req, u8 req_type, u16 val, u16 offset, void *buf, size_t len); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c index 1f1578895ed5..aba926f1eeb5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -252,7 +252,8 @@ mt7663u_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, { struct mt7615_sta *msta = container_of(wcid, struct mt7615_sta, wcid); struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); + struct sk_buff *skb = tx_info->skb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && !msta->rate_probe) { @@ -262,9 +263,10 @@ mt7663u_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, msta->rates); spin_unlock_bh(&dev->mt76.lock); } - mt7663u_mac_write_txwi(dev, wcid, qid, sta, tx_info->skb); + mt7663u_mac_write_txwi(dev, wcid, qid, sta, skb); - return mt76u_skb_dma_info(tx_info->skb, tx_info->skb->len); + put_unaligned_le32(skb->len, skb_push(skb, sizeof(skb->len))); + return mt76_skb_adjust_pad(skb); } static bool mt7663u_tx_status_data(struct mt76_dev *mdev, u8 *update) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c index 39cd7dd95c9c..0b33df3e3bfe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c @@ -28,7 +28,8 @@ mt7663u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, else ep = MT_EP_OUT_AC_BE; - ret = mt76u_skb_dma_info(skb, skb->len); + put_unaligned_le32(skb->len, skb_push(skb, sizeof(skb->len))); + ret = mt76_skb_adjust_pad(skb); if (ret < 0) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index 0180b6200b17..37321e656776 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -56,8 +56,9 @@ int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags) */ info = FIELD_PREP(MT_TXD_INFO_LEN, round_up(skb->len, 4)) | FIELD_PREP(MT_TXD_INFO_DPORT, port) | flags; + put_unaligned_le32(info, skb_push(skb, sizeof(info))); - return mt76u_skb_dma_info(skb, info); + return mt76_skb_adjust_pad(skb); } int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data, diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 5adf92d7a9f3..3afd89ecd6c9 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -677,3 +677,32 @@ u8 mt76_ac_to_hwq(u8 ac) return wmm_queue_map[ac]; } EXPORT_SYMBOL_GPL(mt76_ac_to_hwq); + +int mt76_skb_adjust_pad(struct sk_buff *skb) +{ + struct sk_buff *iter, *last = skb; + u32 pad; + + /* Add zero pad of 4 - 7 bytes */ + pad = round_up(skb->len, 4) + 4 - skb->len; + + /* First packet of a A-MSDU burst keeps track of the whole burst + * length, need to update length of it and the last packet. + */ + skb_walk_frags(skb, iter) { + last = iter; + if (!iter->next) { + skb->data_len += pad; + skb->len += pad; + break; + } + } + + if (skb_pad(last, pad)) + return -ENOMEM; + + __skb_put(last, pad); + + return 0; +} +EXPORT_SYMBOL_GPL(mt76_skb_adjust_pad); diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 84e2fd0a4fc1..5f19f9e51d9c 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -904,35 +904,6 @@ mt76u_tx_setup_buffers(struct mt76_dev *dev, struct sk_buff *skb, return urb->num_sgs; } -int mt76u_skb_dma_info(struct sk_buff *skb, u32 info) -{ - struct sk_buff *iter, *last = skb; - u32 pad; - - put_unaligned_le32(info, skb_push(skb, sizeof(info))); - /* Add zero pad of 4 - 7 bytes */ - pad = round_up(skb->len, 4) + 4 - skb->len; - - /* First packet of a A-MSDU burst keeps track of the whole burst - * length, need to update length of it and the last packet. - */ - skb_walk_frags(skb, iter) { - last = iter; - if (!iter->next) { - skb->data_len += pad; - skb->len += pad; - break; - } - } - - if (skb_pad(last, pad)) - return -ENOMEM; - __skb_put(last, pad); - - return 0; -} -EXPORT_SYMBOL_GPL(mt76u_skb_dma_info); - static int mt76u_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid, struct sk_buff *skb, struct mt76_wcid *wcid, -- cgit v1.2.3 From 0fa407c320695f03847872b7a7d96b732901504d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 15 Jul 2020 14:46:28 +0200 Subject: mt76: mt7615: sdio code must access rate/key regs in preocess context As usb, sdio relies on mt76 workqueue to configure tx rate or upload keys to the hw. This is a preliminary patch to add SDIO support to mt76 driver Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index afac8d81d317..3dd8dd28690e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -967,7 +967,7 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, struct mt7615_rate_desc rd; u32 w5, w27, addr; - if (mt76_is_usb(&dev->mt76)) { + if (!mt76_is_mmio(&dev->mt76)) { mt7615_mac_queue_rate_update(phy, sta, probe_rate, rates); return; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 79453c890f20..2d0b1f49fdbc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -417,10 +417,10 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mt76_wcid_key_setup(&dev->mt76, wcid, cmd == SET_KEY ? key : NULL); - if (mt76_is_usb(&dev->mt76)) - err = mt7615_queue_key_update(dev, cmd, msta, key); - else + if (mt76_is_mmio(&dev->mt76)) err = mt7615_mac_wtbl_set_key(dev, wcid, key, cmd); + else + err = mt7615_queue_key_update(dev, cmd, msta, key); mt7615_mutex_release(dev); -- cgit v1.2.3 From 90520afbae5f01c67f6b7ad580e0de90adab21a6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 15 Jul 2020 14:46:29 +0200 Subject: mt76: mt7615: introduce mt7663-usb-sdio-common module Introduce mt7663-usb-sdio-common module as container for shared code between usb and sdio driver. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/Kconfig | 6 +- drivers/net/wireless/mediatek/mt76/mt7615/Makefile | 4 +- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 13 +- drivers/net/wireless/mediatek/mt76/mt7615/usb.c | 255 +------------- .../net/wireless/mediatek/mt76/mt7615/usb_init.c | 145 -------- .../net/wireless/mediatek/mt76/mt7615/usb_sdio.c | 390 +++++++++++++++++++++ 6 files changed, 424 insertions(+), 389 deletions(-) delete mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/usb_init.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig index c094260b0f89..10a4f1ed9194 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig @@ -28,10 +28,14 @@ config MT7622_WMAC which has the same feature set as a MT7615, but limited to 2.4 GHz only. +config MT7663_USB_SDIO_COMMON + tristate + select MT7615_COMMON + config MT7663U tristate "MediaTek MT7663U (USB) support" select MT76_USB - select MT7615_COMMON + select MT7663_USB_SDIO_COMMON depends on MAC80211 depends on USB help diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile index d2ad84cb5244..a1cdaadb5442 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_MT7615_COMMON) += mt7615-common.o obj-$(CONFIG_MT7615E) += mt7615e.o +obj-$(CONFIG_MT7663_USB_SDIO_COMMON) += mt7663-usb-sdio-common.o obj-$(CONFIG_MT7663U) += mt7663u.o CFLAGS_trace.o := -I$(src) @@ -13,4 +14,5 @@ mt7615-common-$(CONFIG_NL80211_TESTMODE) += testmode.o mt7615e-y := pci.o pci_init.o dma.o pci_mac.o mmio.o mt7615e-$(CONFIG_MT7622_WMAC) += soc.o -mt7663u-y := usb.o usb_mcu.o usb_init.o +mt7663-usb-sdio-common-y := usb_sdio.o +mt7663u-y := usb.o usb_mcu.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 688bd7b68668..38628d28b3dd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -409,6 +409,7 @@ extern struct ieee80211_rate mt7615_rates[12]; extern const struct ieee80211_ops mt7615_ops; extern const u32 mt7615e_reg_map[__MT_BASE_MAX]; extern const u32 mt7663e_reg_map[__MT_BASE_MAX]; +extern const u32 mt7663_usb_sdio_reg_map[__MT_BASE_MAX]; extern struct pci_driver mt7615_pci_driver; extern struct platform_driver mt7622_wmac_driver; extern const struct mt76_testmode_ops mt7615_testmode_ops; @@ -657,8 +658,16 @@ int mt7615_mcu_update_arp_filter(struct ieee80211_hw *hw, int __mt7663_load_firmware(struct mt7615_dev *dev); /* usb */ -void mt7663u_wtbl_work(struct work_struct *work); +int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + enum mt76_txq_id qid, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, + struct mt76_tx_info *tx_info); +bool mt7663_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update); +void mt7663_usb_sdio_tx_complete_skb(struct mt76_dev *mdev, + enum mt76_txq_id qid, + struct mt76_queue_entry *e); +void mt7663_usb_sdio_wtbl_work(struct work_struct *work); +int mt7663_usb_sdio_register_device(struct mt7615_dev *dev); int mt7663u_mcu_init(struct mt7615_dev *dev); -int mt7663u_register_device(struct mt7615_dev *dev); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c index aba926f1eeb5..f1b4a6316db3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -15,30 +15,6 @@ #include "mcu.h" #include "regs.h" -static const u32 mt7663u_reg_map[] = { - [MT_TOP_CFG_BASE] = 0x80020000, - [MT_HW_BASE] = 0x80000000, - [MT_DMA_SHDL_BASE] = 0x5000a000, - [MT_HIF_BASE] = 0x50000000, - [MT_CSR_BASE] = 0x40000000, - [MT_EFUSE_ADDR_BASE] = 0x78011000, - [MT_TOP_MISC_BASE] = 0x81020000, - [MT_PLE_BASE] = 0x82060000, - [MT_PSE_BASE] = 0x82068000, - [MT_WTBL_BASE_ADDR] = 0x820e0000, - [MT_CFG_BASE] = 0x820f0000, - [MT_AGG_BASE] = 0x820f2000, - [MT_ARB_BASE] = 0x820f3000, - [MT_TMAC_BASE] = 0x820f4000, - [MT_RMAC_BASE] = 0x820f5000, - [MT_DMA_BASE] = 0x820f7000, - [MT_PF_BASE] = 0x820f8000, - [MT_WTBL_BASE_ON] = 0x820f9000, - [MT_WTBL_BASE_OFF] = 0x820f9800, - [MT_LPON_BASE] = 0x820fb000, - [MT_MIB_BASE] = 0x820fd000, -}; - static const struct usb_device_id mt7615_device_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7663, 0xff, 0xff, 0xff) }, { }, @@ -63,221 +39,19 @@ static void mt7663u_cleanup(struct mt7615_dev *dev) mt76u_queues_deinit(&dev->mt76); } -static void -mt7663u_mac_write_txwi(struct mt7615_dev *dev, struct mt76_wcid *wcid, - enum mt76_txq_id qid, struct ieee80211_sta *sta, - struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_key_conf *key = info->control.hw_key; - __le32 *txwi; - int pid; - - if (!wcid) - wcid = &dev->mt76.global_wcid; - - pid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb); - - txwi = (__le32 *)(skb->data - MT_USB_TXD_SIZE); - memset(txwi, 0, MT_USB_TXD_SIZE); - mt7615_mac_write_txwi(dev, txwi, skb, wcid, sta, pid, key, false); - skb_push(skb, MT_USB_TXD_SIZE); -} - -static int -__mt7663u_mac_set_rates(struct mt7615_dev *dev, - struct mt7615_wtbl_desc *wd) -{ - struct mt7615_rate_desc *rate = &wd->rate; - struct mt7615_sta *sta = wd->sta; - u32 w5, w27, addr, val; - - lockdep_assert_held(&dev->mt76.mutex); - - if (!sta) - return -EINVAL; - - if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) - return -ETIMEDOUT; - - addr = mt7615_mac_wtbl_addr(dev, sta->wcid.idx); - - w27 = mt76_rr(dev, addr + 27 * 4); - w27 &= ~MT_WTBL_W27_CC_BW_SEL; - w27 |= FIELD_PREP(MT_WTBL_W27_CC_BW_SEL, rate->bw); - - w5 = mt76_rr(dev, addr + 5 * 4); - w5 &= ~(MT_WTBL_W5_BW_CAP | MT_WTBL_W5_CHANGE_BW_RATE | - MT_WTBL_W5_MPDU_OK_COUNT | - MT_WTBL_W5_MPDU_FAIL_COUNT | - MT_WTBL_W5_RATE_IDX); - w5 |= FIELD_PREP(MT_WTBL_W5_BW_CAP, rate->bw) | - FIELD_PREP(MT_WTBL_W5_CHANGE_BW_RATE, - rate->bw_idx ? rate->bw_idx - 1 : 7); - - mt76_wr(dev, MT_WTBL_RIUCR0, w5); - - mt76_wr(dev, MT_WTBL_RIUCR1, - FIELD_PREP(MT_WTBL_RIUCR1_RATE0, rate->probe_val) | - FIELD_PREP(MT_WTBL_RIUCR1_RATE1, rate->val[0]) | - FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, rate->val[1])); - - mt76_wr(dev, MT_WTBL_RIUCR2, - FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, rate->val[1] >> 8) | - FIELD_PREP(MT_WTBL_RIUCR2_RATE3, rate->val[1]) | - FIELD_PREP(MT_WTBL_RIUCR2_RATE4, rate->val[2]) | - FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, rate->val[2])); - - mt76_wr(dev, MT_WTBL_RIUCR3, - FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, rate->val[2] >> 4) | - FIELD_PREP(MT_WTBL_RIUCR3_RATE6, rate->val[3]) | - FIELD_PREP(MT_WTBL_RIUCR3_RATE7, rate->val[3])); - - mt76_wr(dev, MT_WTBL_UPDATE, - FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, sta->wcid.idx) | - MT_WTBL_UPDATE_RATE_UPDATE | - MT_WTBL_UPDATE_TX_COUNT_CLEAR); - - mt76_wr(dev, addr + 27 * 4, w27); - - sta->rate_probe = sta->rateset[rate->rateset].probe_rate.idx != -1; - - mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* TSF read */ - val = mt76_rr(dev, MT_LPON_UTTR0); - sta->rate_set_tsf = (val & ~BIT(0)) | rate->rateset; - - if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET)) - mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); - - sta->rate_count = 2 * MT7615_RATE_RETRY * sta->n_rates; - sta->wcid.tx_info |= MT_WCID_TX_INFO_SET; - - return 0; -} - -static int -__mt7663u_mac_set_key(struct mt7615_dev *dev, - struct mt7615_wtbl_desc *wd) -{ - struct mt7615_key_desc *key = &wd->key; - struct mt7615_sta *sta = wd->sta; - enum mt7615_cipher_type cipher; - struct mt76_wcid *wcid; - int err; - - lockdep_assert_held(&dev->mt76.mutex); - - if (!sta) { - err = -EINVAL; - goto out; - } - - cipher = mt7615_mac_get_cipher(key->cipher); - if (cipher == MT_CIPHER_NONE) { - err = -EOPNOTSUPP; - goto out; - } - - wcid = &wd->sta->wcid; - - mt7615_mac_wtbl_update_cipher(dev, wcid, cipher, key->cmd); - err = mt7615_mac_wtbl_update_key(dev, wcid, key->key, key->keylen, - cipher, key->cmd); - if (err < 0) - goto out; - - err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, key->keyidx, - key->cmd); - if (err < 0) - goto out; - - if (key->cmd == SET_KEY) - wcid->cipher |= BIT(cipher); - else - wcid->cipher &= ~BIT(cipher); - -out: - kfree(key->key); - - return err; -} - -void mt7663u_wtbl_work(struct work_struct *work) +static void mt7663u_init_work(struct work_struct *work) { - struct mt7615_wtbl_desc *wd, *wd_next; - struct list_head wd_list; struct mt7615_dev *dev; - dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, - wtbl_work); - - INIT_LIST_HEAD(&wd_list); - spin_lock_bh(&dev->mt76.lock); - list_splice_init(&dev->wd_head, &wd_list); - spin_unlock_bh(&dev->mt76.lock); - - list_for_each_entry_safe(wd, wd_next, &wd_list, node) { - list_del(&wd->node); - - mt7615_mutex_acquire(dev); - - switch (wd->type) { - case MT7615_WTBL_RATE_DESC: - __mt7663u_mac_set_rates(dev, wd); - break; - case MT7615_WTBL_KEY_DESC: - __mt7663u_mac_set_key(dev, wd); - break; - } - - mt7615_mutex_release(dev); - - kfree(wd); - } -} - -static void -mt7663u_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid, - struct mt76_queue_entry *e) -{ - skb_pull(e->skb, MT_USB_HDR_SIZE + MT_USB_TXD_SIZE); - mt76_tx_complete_skb(mdev, e->skb); -} - -static int -mt7663u_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, - enum mt76_txq_id qid, struct mt76_wcid *wcid, - 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); - - if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && - !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], - msta->rates); - spin_unlock_bh(&dev->mt76.lock); - } - mt7663u_mac_write_txwi(dev, wcid, qid, sta, skb); - - put_unaligned_le32(skb->len, skb_push(skb, sizeof(skb->len))); - return mt76_skb_adjust_pad(skb); -} - -static bool mt7663u_tx_status_data(struct mt76_dev *mdev, u8 *update) -{ - struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); - - mt7615_mutex_acquire(dev); - mt7615_mac_sta_poll(dev); - mt7615_mutex_release(dev); + dev = container_of(work, struct mt7615_dev, mcu_work); + if (mt7663u_mcu_init(dev)) + return; - return 0; + mt7615_mcu_set_eeprom(dev); + mt7615_mac_init(dev); + mt7615_phy_init(dev); + mt7615_mcu_del_wtbl_all(dev); + mt7615_check_offload_capability(dev); } static int mt7663u_probe(struct usb_interface *usb_intf, @@ -286,9 +60,9 @@ static int mt7663u_probe(struct usb_interface *usb_intf, static const struct mt76_driver_ops drv_ops = { .txwi_size = MT_USB_TXD_SIZE, .drv_flags = MT_DRV_RX_DMA_HDR | MT_DRV_HW_MGMT_TXQ, - .tx_prepare_skb = mt7663u_tx_prepare_skb, - .tx_complete_skb = mt7663u_tx_complete_skb, - .tx_status_data = mt7663u_tx_status_data, + .tx_prepare_skb = mt7663_usb_sdio_tx_prepare_skb, + .tx_complete_skb = mt7663_usb_sdio_tx_complete_skb, + .tx_status_data = mt7663_usb_sdio_tx_status_data, .rx_skb = mt7615_queue_rx_skb, .sta_ps = mt7615_sta_ps, .sta_add = mt7615_mac_sta_add, @@ -318,7 +92,8 @@ static int mt7663u_probe(struct usb_interface *usb_intf, usb_set_intfdata(usb_intf, dev); - dev->reg_map = mt7663u_reg_map; + INIT_WORK(&dev->mcu_work, mt7663u_init_work); + dev->reg_map = mt7663_usb_sdio_reg_map; dev->ops = ops; ret = mt76u_init(mdev, usb_intf, true); if (ret < 0) @@ -356,7 +131,7 @@ alloc_queues: if (ret) goto error; - ret = mt7663u_register_device(dev); + ret = mt7663_usb_sdio_register_device(dev); if (ret) goto error_freeq; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_init.c deleted file mode 100644 index 1fbc9601391d..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_init.c +++ /dev/null @@ -1,145 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2019 MediaTek Inc. - * - * Author: Felix Fietkau - * Lorenzo Bianconi - * Sean Wang - */ - -#include -#include - -#include "mt7615.h" -#include "mac.h" -#include "regs.h" - -static int mt7663u_dma_sched_init(struct mt7615_dev *dev) -{ - int i; - - mt76_rmw(dev, MT_DMA_SHDL(MT_DMASHDL_PKT_MAX_SIZE), - MT_DMASHDL_PKT_MAX_SIZE_PLE | MT_DMASHDL_PKT_MAX_SIZE_PSE, - FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PLE, 1) | - FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PSE, 8)); - - /* disable refill group 5 - group 15 and raise group 2 - * and 3 as high priority. - */ - mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_REFILL), 0xffe00006); - mt76_clear(dev, MT_DMA_SHDL(MT_DMASHDL_PAGE), BIT(16)); - - for (i = 0; i < 5; i++) - mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_GROUP_QUOTA(i)), - FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MIN, 0x3) | - FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MAX, 0x1ff)); - - mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(0)), 0x42104210); - mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(1)), 0x42104210); - - mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(2)), 0x4444); - - /* group pririority from high to low: - * 15 (cmd groups) > 4 > 3 > 2 > 1 > 0. - */ - mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_SCHED_SET0), 0x6501234f); - mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_SCHED_SET1), 0xedcba987); - mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_OPTIONAL), 0x7004801c); - - mt76_wr(dev, MT_UDMA_WLCFG_1, - FIELD_PREP(MT_WL_TX_TMOUT_LMT, 80000) | - FIELD_PREP(MT_WL_RX_AGG_PKT_LMT, 1)); - - /* setup UDMA Rx Flush */ - mt76_clear(dev, MT_UDMA_WLCFG_0, MT_WL_RX_FLUSH); - /* hif reset */ - mt76_set(dev, MT_HIF_RST, MT_HIF_LOGIC_RST_N); - - mt76_set(dev, MT_UDMA_WLCFG_0, - MT_WL_RX_AGG_EN | MT_WL_RX_EN | MT_WL_TX_EN | - MT_WL_RX_MPSZ_PAD0 | MT_TICK_1US_EN | - MT_WL_TX_TMOUT_FUNC_EN); - mt76_rmw(dev, MT_UDMA_WLCFG_0, MT_WL_RX_AGG_LMT | MT_WL_RX_AGG_TO, - FIELD_PREP(MT_WL_RX_AGG_LMT, 32) | - FIELD_PREP(MT_WL_RX_AGG_TO, 100)); - - return 0; -} - -static int mt7663u_init_hardware(struct mt7615_dev *dev) -{ - int ret, idx; - - ret = mt7615_eeprom_init(dev, MT_EFUSE_BASE); - if (ret < 0) - return ret; - - ret = mt7663u_dma_sched_init(dev); - if (ret) - return ret; - - set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); - - /* Beacon and mgmt frames should occupy wcid 0 */ - idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7615_WTBL_STA - 1); - if (idx) - return -ENOSPC; - - dev->mt76.global_wcid.idx = idx; - dev->mt76.global_wcid.hw_key_idx = -1; - rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); - - return 0; -} - -static void mt7663u_init_work(struct work_struct *work) -{ - struct mt7615_dev *dev; - - dev = container_of(work, struct mt7615_dev, mcu_work); - if (mt7663u_mcu_init(dev)) - return; - - mt7615_mcu_set_eeprom(dev); - mt7615_mac_init(dev); - mt7615_phy_init(dev); - mt7615_mcu_del_wtbl_all(dev); - mt7615_check_offload_capability(dev); -} - -int mt7663u_register_device(struct mt7615_dev *dev) -{ - struct ieee80211_hw *hw = mt76_hw(dev); - int err; - - INIT_WORK(&dev->wtbl_work, mt7663u_wtbl_work); - INIT_WORK(&dev->mcu_work, mt7663u_init_work); - INIT_LIST_HEAD(&dev->wd_head); - mt7615_init_device(dev); - - err = mt7663u_init_hardware(dev); - if (err) - return err; - - hw->extra_tx_headroom += MT_USB_HDR_SIZE + MT_USB_TXD_SIZE; - /* check hw sg support in order to enable AMSDU */ - hw->max_tx_fragments = dev->mt76.usb.sg_en ? MT_HW_TXP_MAX_BUF_NUM : 1; - - err = mt76_register_device(&dev->mt76, true, mt7615_rates, - ARRAY_SIZE(mt7615_rates)); - if (err < 0) - return err; - - if (!dev->mt76.usb.sg_en) { - struct ieee80211_sta_vht_cap *vht_cap; - - /* decrease max A-MSDU size if SG is not supported */ - vht_cap = &dev->mphy.sband_5g.sband.vht_cap; - vht_cap->cap &= ~IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; - } - - ieee80211_queue_work(hw, &dev->mcu_work); - mt7615_init_txpower(dev, &dev->mphy.sband_2g.sband); - mt7615_init_txpower(dev, &dev->mphy.sband_5g.sband); - - return mt7615_init_debugfs(dev); -} diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c new file mode 100644 index 000000000000..610cc1fbec5b --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c @@ -0,0 +1,390 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. + * + * Author: Lorenzo Bianconi + * Sean Wang + */ + +#include +#include +#include + +#include "mt7615.h" +#include "mac.h" +#include "mcu.h" +#include "regs.h" + +const u32 mt7663_usb_sdio_reg_map[] = { + [MT_TOP_CFG_BASE] = 0x80020000, + [MT_HW_BASE] = 0x80000000, + [MT_DMA_SHDL_BASE] = 0x5000a000, + [MT_HIF_BASE] = 0x50000000, + [MT_CSR_BASE] = 0x40000000, + [MT_EFUSE_ADDR_BASE] = 0x78011000, + [MT_TOP_MISC_BASE] = 0x81020000, + [MT_PLE_BASE] = 0x82060000, + [MT_PSE_BASE] = 0x82068000, + [MT_WTBL_BASE_ADDR] = 0x820e0000, + [MT_CFG_BASE] = 0x820f0000, + [MT_AGG_BASE] = 0x820f2000, + [MT_ARB_BASE] = 0x820f3000, + [MT_TMAC_BASE] = 0x820f4000, + [MT_RMAC_BASE] = 0x820f5000, + [MT_DMA_BASE] = 0x820f7000, + [MT_PF_BASE] = 0x820f8000, + [MT_WTBL_BASE_ON] = 0x820f9000, + [MT_WTBL_BASE_OFF] = 0x820f9800, + [MT_LPON_BASE] = 0x820fb000, + [MT_MIB_BASE] = 0x820fd000, +}; +EXPORT_SYMBOL_GPL(mt7663_usb_sdio_reg_map); + +static void +mt7663_usb_sdio_write_txwi(struct mt7615_dev *dev, struct mt76_wcid *wcid, + enum mt76_txq_id qid, struct ieee80211_sta *sta, + struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_key_conf *key = info->control.hw_key; + __le32 *txwi; + int pid; + + if (!wcid) + wcid = &dev->mt76.global_wcid; + + pid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb); + + txwi = (__le32 *)(skb->data - MT_USB_TXD_SIZE); + memset(txwi, 0, MT_USB_TXD_SIZE); + mt7615_mac_write_txwi(dev, txwi, skb, wcid, sta, pid, key, false); + skb_push(skb, MT_USB_TXD_SIZE); +} + +static int +mt7663_usb_sdio_set_rates(struct mt7615_dev *dev, + struct mt7615_wtbl_desc *wd) +{ + struct mt7615_rate_desc *rate = &wd->rate; + struct mt7615_sta *sta = wd->sta; + u32 w5, w27, addr, val; + + lockdep_assert_held(&dev->mt76.mutex); + + if (!sta) + return -EINVAL; + + if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) + return -ETIMEDOUT; + + addr = mt7615_mac_wtbl_addr(dev, sta->wcid.idx); + + w27 = mt76_rr(dev, addr + 27 * 4); + w27 &= ~MT_WTBL_W27_CC_BW_SEL; + w27 |= FIELD_PREP(MT_WTBL_W27_CC_BW_SEL, rate->bw); + + w5 = mt76_rr(dev, addr + 5 * 4); + w5 &= ~(MT_WTBL_W5_BW_CAP | MT_WTBL_W5_CHANGE_BW_RATE | + MT_WTBL_W5_MPDU_OK_COUNT | + MT_WTBL_W5_MPDU_FAIL_COUNT | + MT_WTBL_W5_RATE_IDX); + w5 |= FIELD_PREP(MT_WTBL_W5_BW_CAP, rate->bw) | + FIELD_PREP(MT_WTBL_W5_CHANGE_BW_RATE, + rate->bw_idx ? rate->bw_idx - 1 : 7); + + mt76_wr(dev, MT_WTBL_RIUCR0, w5); + + mt76_wr(dev, MT_WTBL_RIUCR1, + FIELD_PREP(MT_WTBL_RIUCR1_RATE0, rate->probe_val) | + FIELD_PREP(MT_WTBL_RIUCR1_RATE1, rate->val[0]) | + FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, rate->val[1])); + + mt76_wr(dev, MT_WTBL_RIUCR2, + FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, rate->val[1] >> 8) | + FIELD_PREP(MT_WTBL_RIUCR2_RATE3, rate->val[1]) | + FIELD_PREP(MT_WTBL_RIUCR2_RATE4, rate->val[2]) | + FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, rate->val[2])); + + mt76_wr(dev, MT_WTBL_RIUCR3, + FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, rate->val[2] >> 4) | + FIELD_PREP(MT_WTBL_RIUCR3_RATE6, rate->val[3]) | + FIELD_PREP(MT_WTBL_RIUCR3_RATE7, rate->val[3])); + + mt76_wr(dev, MT_WTBL_UPDATE, + FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, sta->wcid.idx) | + MT_WTBL_UPDATE_RATE_UPDATE | + MT_WTBL_UPDATE_TX_COUNT_CLEAR); + + mt76_wr(dev, addr + 27 * 4, w27); + + sta->rate_probe = sta->rateset[rate->rateset].probe_rate.idx != -1; + + mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* TSF read */ + val = mt76_rr(dev, MT_LPON_UTTR0); + sta->rate_set_tsf = (val & ~BIT(0)) | rate->rateset; + + if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET)) + mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); + + sta->rate_count = 2 * MT7615_RATE_RETRY * sta->n_rates; + sta->wcid.tx_info |= MT_WCID_TX_INFO_SET; + + return 0; +} + +static int +mt7663_usb_sdio_set_key(struct mt7615_dev *dev, + struct mt7615_wtbl_desc *wd) +{ + struct mt7615_key_desc *key = &wd->key; + struct mt7615_sta *sta = wd->sta; + enum mt7615_cipher_type cipher; + struct mt76_wcid *wcid; + int err; + + lockdep_assert_held(&dev->mt76.mutex); + + if (!sta) { + err = -EINVAL; + goto out; + } + + cipher = mt7615_mac_get_cipher(key->cipher); + if (cipher == MT_CIPHER_NONE) { + err = -EOPNOTSUPP; + goto out; + } + + wcid = &wd->sta->wcid; + + mt7615_mac_wtbl_update_cipher(dev, wcid, cipher, key->cmd); + err = mt7615_mac_wtbl_update_key(dev, wcid, key->key, key->keylen, + cipher, key->cmd); + if (err < 0) + goto out; + + err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, key->keyidx, + key->cmd); + if (err < 0) + goto out; + + if (key->cmd == SET_KEY) + wcid->cipher |= BIT(cipher); + else + wcid->cipher &= ~BIT(cipher); +out: + kfree(key->key); + + return err; +} + +void mt7663_usb_sdio_wtbl_work(struct work_struct *work) +{ + struct mt7615_wtbl_desc *wd, *wd_next; + struct list_head wd_list; + struct mt7615_dev *dev; + + dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, + wtbl_work); + + INIT_LIST_HEAD(&wd_list); + spin_lock_bh(&dev->mt76.lock); + list_splice_init(&dev->wd_head, &wd_list); + spin_unlock_bh(&dev->mt76.lock); + + list_for_each_entry_safe(wd, wd_next, &wd_list, node) { + list_del(&wd->node); + + mt7615_mutex_acquire(dev); + + switch (wd->type) { + case MT7615_WTBL_RATE_DESC: + mt7663_usb_sdio_set_rates(dev, wd); + break; + case MT7615_WTBL_KEY_DESC: + mt7663_usb_sdio_set_key(dev, wd); + break; + } + + mt7615_mutex_release(dev); + + kfree(wd); + } +} +EXPORT_SYMBOL_GPL(mt7663_usb_sdio_wtbl_work); + +bool mt7663_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + + mt7615_mutex_acquire(dev); + mt7615_mac_sta_poll(dev); + mt7615_mutex_release(dev); + + return 0; +} +EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_status_data); + +void mt7663_usb_sdio_tx_complete_skb(struct mt76_dev *mdev, + enum mt76_txq_id qid, + struct mt76_queue_entry *e) +{ + unsigned int headroom = MT_USB_TXD_SIZE; + + if (mt76_is_usb(mdev)) + headroom += MT_USB_HDR_SIZE; + skb_pull(e->skb, headroom); + + mt76_tx_complete_skb(mdev, e->skb); +} +EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_complete_skb); + +int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + enum mt76_txq_id qid, struct mt76_wcid *wcid, + 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); + + if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && + !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], + msta->rates); + spin_unlock_bh(&dev->mt76.lock); + } + + mt7663_usb_sdio_write_txwi(dev, wcid, qid, sta, skb); + if (mt76_is_usb(mdev)) + put_unaligned_le32(skb->len, skb_push(skb, sizeof(skb->len))); + + return mt76_skb_adjust_pad(skb); +} +EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_prepare_skb); + +static int mt7663u_dma_sched_init(struct mt7615_dev *dev) +{ + int i; + + mt76_rmw(dev, MT_DMA_SHDL(MT_DMASHDL_PKT_MAX_SIZE), + MT_DMASHDL_PKT_MAX_SIZE_PLE | MT_DMASHDL_PKT_MAX_SIZE_PSE, + FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PLE, 1) | + FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PSE, 8)); + + /* disable refill group 5 - group 15 and raise group 2 + * and 3 as high priority. + */ + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_REFILL), 0xffe00006); + mt76_clear(dev, MT_DMA_SHDL(MT_DMASHDL_PAGE), BIT(16)); + + for (i = 0; i < 5; i++) + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_GROUP_QUOTA(i)), + FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MIN, 0x3) | + FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MAX, 0x1ff)); + + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(0)), 0x42104210); + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(1)), 0x42104210); + + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(2)), 0x4444); + + /* group pririority from high to low: + * 15 (cmd groups) > 4 > 3 > 2 > 1 > 0. + */ + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_SCHED_SET0), 0x6501234f); + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_SCHED_SET1), 0xedcba987); + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_OPTIONAL), 0x7004801c); + + mt76_wr(dev, MT_UDMA_WLCFG_1, + FIELD_PREP(MT_WL_TX_TMOUT_LMT, 80000) | + FIELD_PREP(MT_WL_RX_AGG_PKT_LMT, 1)); + + /* setup UDMA Rx Flush */ + mt76_clear(dev, MT_UDMA_WLCFG_0, MT_WL_RX_FLUSH); + /* hif reset */ + mt76_set(dev, MT_HIF_RST, MT_HIF_LOGIC_RST_N); + + mt76_set(dev, MT_UDMA_WLCFG_0, + MT_WL_RX_AGG_EN | MT_WL_RX_EN | MT_WL_TX_EN | + MT_WL_RX_MPSZ_PAD0 | MT_TICK_1US_EN | + MT_WL_TX_TMOUT_FUNC_EN); + mt76_rmw(dev, MT_UDMA_WLCFG_0, MT_WL_RX_AGG_LMT | MT_WL_RX_AGG_TO, + FIELD_PREP(MT_WL_RX_AGG_LMT, 32) | + FIELD_PREP(MT_WL_RX_AGG_TO, 100)); + + return 0; +} + +static int mt7663_usb_sdio_init_hardware(struct mt7615_dev *dev) +{ + int ret, idx; + + ret = mt7615_eeprom_init(dev, MT_EFUSE_BASE); + if (ret < 0) + return ret; + + if (mt76_is_usb(&dev->mt76)) { + ret = mt7663u_dma_sched_init(dev); + if (ret) + return ret; + } + + set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); + + /* Beacon and mgmt frames should occupy wcid 0 */ + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7615_WTBL_STA - 1); + if (idx) + return -ENOSPC; + + dev->mt76.global_wcid.idx = idx; + dev->mt76.global_wcid.hw_key_idx = -1; + rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); + + return 0; +} + +int mt7663_usb_sdio_register_device(struct mt7615_dev *dev) +{ + struct ieee80211_hw *hw = mt76_hw(dev); + int err; + + INIT_WORK(&dev->wtbl_work, mt7663_usb_sdio_wtbl_work); + INIT_LIST_HEAD(&dev->wd_head); + mt7615_init_device(dev); + + err = mt7663_usb_sdio_init_hardware(dev); + if (err) + return err; + + /* check hw sg support in order to enable AMSDU */ + hw->max_tx_fragments = dev->mt76.usb.sg_en ? MT_HW_TXP_MAX_BUF_NUM : 1; + hw->extra_tx_headroom += MT_USB_TXD_SIZE; + if (mt76_is_usb(&dev->mt76)) + hw->extra_tx_headroom += MT_USB_HDR_SIZE; + + err = mt76_register_device(&dev->mt76, true, mt7615_rates, + ARRAY_SIZE(mt7615_rates)); + if (err < 0) + return err; + + if (!dev->mt76.usb.sg_en) { + struct ieee80211_sta_vht_cap *vht_cap; + + /* decrease max A-MSDU size if SG is not supported */ + vht_cap = &dev->mphy.sband_5g.sband.vht_cap; + vht_cap->cap &= ~IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; + } + + ieee80211_queue_work(hw, &dev->mcu_work); + mt7615_init_txpower(dev, &dev->mphy.sband_2g.sband); + mt7615_init_txpower(dev, &dev->mphy.sband_5g.sband); + + return mt7615_init_debugfs(dev); +} +EXPORT_SYMBOL_GPL(mt7663_usb_sdio_register_device); + +MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_AUTHOR("Sean Wang "); +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From d39b52e31aa641c79d0a1177f9d02e71d1b7fd64 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 15 Jul 2020 14:46:30 +0200 Subject: mt76: introduce mt76_sdio module Introduce mt76_sdio module as common layer to add mt7663s support 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/Kconfig | 4 + drivers/net/wireless/mediatek/mt76/Makefile | 2 + drivers/net/wireless/mediatek/mt76/mac80211.c | 6 +- drivers/net/wireless/mediatek/mt76/mt76.h | 30 ++ .../net/wireless/mediatek/mt76/mt7615/usb_sdio.c | 5 +- drivers/net/wireless/mediatek/mt76/sdio.c | 363 +++++++++++++++++++++ 6 files changed, 408 insertions(+), 2 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/sdio.c (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/Kconfig b/drivers/net/wireless/mediatek/mt76/Kconfig index 41533a0e1720..31015d2a8e7d 100644 --- a/drivers/net/wireless/mediatek/mt76/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/Kconfig @@ -12,6 +12,10 @@ config MT76_USB tristate depends on MT76_CORE +config MT76_SDIO + tristate + depends on MT76_CORE + config MT76x02_LIB tristate select MT76_CORE diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index 949b3c8ffa1b..e53584db0756 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_MT76_CORE) += mt76.o obj-$(CONFIG_MT76_USB) += mt76-usb.o +obj-$(CONFIG_MT76_SDIO) += mt76-sdio.o obj-$(CONFIG_MT76x02_LIB) += mt76x02-lib.o obj-$(CONFIG_MT76x02_USB) += mt76x02-usb.o @@ -12,6 +13,7 @@ mt76-$(CONFIG_PCI) += pci.o mt76-$(CONFIG_NL80211_TESTMODE) += testmode.o mt76-usb-y := usb.o usb_trace.o +mt76-sdio-y := sdio.o CFLAGS_trace.o := -I$(src) CFLAGS_usb_trace.o := -I$(src) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index f340af40f8f4..3d4bf72700a5 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -305,7 +305,11 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw) ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); ieee80211_hw_set(hw, TX_AMSDU); - ieee80211_hw_set(hw, TX_FRAG_LIST); + + /* TODO: avoid linearization for SDIO */ + if (!mt76_is_sdio(dev)) + ieee80211_hw_set(hw, TX_FRAG_LIST); + ieee80211_hw_set(hw, MFP_CAPABLE); ieee80211_hw_set(hw, AP_LINK_PS); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 8ee159d614ae..af35bc388ae2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -34,6 +34,7 @@ struct mt76_reg_pair { enum mt76_bus_type { MT76_BUS_MMIO, MT76_BUS_USB, + MT76_BUS_SDIO, }; struct mt76_bus_ops { @@ -53,6 +54,7 @@ struct mt76_bus_ops { #define mt76_is_usb(dev) ((dev)->bus->type == MT76_BUS_USB) #define mt76_is_mmio(dev) ((dev)->bus->type == MT76_BUS_MMIO) +#define mt76_is_sdio(dev) ((dev)->bus->type == MT76_BUS_SDIO) enum mt76_txq_id { MT_TXQ_VO = IEEE80211_AC_VO, @@ -95,6 +97,7 @@ struct mt76_queue_entry { union { struct mt76_txwi_cache *txwi; struct urb *urb; + int buf_sz; }; enum mt76_txq_id qid; bool skip_buf0:1; @@ -147,6 +150,8 @@ struct mt76_mcu_ops { int len, bool wait_resp); int (*mcu_skb_send_msg)(struct mt76_dev *dev, struct sk_buff *skb, int cmd, bool wait_resp); + u32 (*mcu_rr)(struct mt76_dev *dev, u32 offset); + void (*mcu_wr)(struct mt76_dev *dev, u32 offset, u32 val); int (*mcu_wr_rp)(struct mt76_dev *dev, u32 base, const struct mt76_reg_pair *rp, int len); int (*mcu_rd_rp)(struct mt76_dev *dev, u32 base, @@ -440,6 +445,24 @@ struct mt76_usb { } mcu; }; +struct mt76_sdio { + struct task_struct *tx_kthread; + struct task_struct *kthread; + struct work_struct stat_work; + + unsigned long state; + + struct sdio_func *func; + + struct { + struct mutex lock; + int pse_data_quota; + int ple_data_quota; + int pse_mcu_quota; + int deficit; + } sched; +}; + struct mt76_mmio { void __iomem *regs; spinlock_t irq_lock; @@ -626,6 +649,7 @@ struct mt76_dev { union { struct mt76_mmio mmio; struct mt76_usb usb; + struct mt76_sdio sdio; }; }; @@ -1030,6 +1054,12 @@ void mt76u_stop_rx(struct mt76_dev *dev); int mt76u_resume_rx(struct mt76_dev *dev); void mt76u_queues_deinit(struct mt76_dev *dev); +int mt76s_init(struct mt76_dev *dev, struct sdio_func *func, + const struct mt76_bus_ops *bus_ops); +int mt76s_alloc_queues(struct mt76_dev *dev); +void mt76s_stop_txrx(struct mt76_dev *dev); +void mt76s_deinit(struct mt76_dev *dev); + struct sk_buff * mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data, int data_len); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c index 610cc1fbec5b..50009bc5ee8d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c @@ -359,7 +359,10 @@ int mt7663_usb_sdio_register_device(struct mt7615_dev *dev) return err; /* check hw sg support in order to enable AMSDU */ - hw->max_tx_fragments = dev->mt76.usb.sg_en ? MT_HW_TXP_MAX_BUF_NUM : 1; + if (dev->mt76.usb.sg_en || mt76_is_sdio(&dev->mt76)) + hw->max_tx_fragments = MT_HW_TXP_MAX_BUF_NUM; + else + hw->max_tx_fragments = 1; hw->extra_tx_headroom += MT_USB_TXD_SIZE; if (mt76_is_usb(&dev->mt76)) hw->extra_tx_headroom += MT_USB_HDR_SIZE; diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c new file mode 100644 index 000000000000..a6f3255c4d84 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/sdio.c @@ -0,0 +1,363 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. + * + * This file is written based on mt76/usb.c. + * + * Author: Felix Fietkau + * Lorenzo Bianconi + * Sean Wang + */ + +#include +#include +#include +#include +#include +#include + +#include "mt76.h" + +static int +mt76s_alloc_rx_queue(struct mt76_dev *dev, enum mt76_rxq_id qid) +{ + struct mt76_queue *q = &dev->q_rx[qid]; + + spin_lock_init(&q->lock); + q->entry = devm_kcalloc(dev->dev, + MT_NUM_RX_ENTRIES, sizeof(*q->entry), + GFP_KERNEL); + if (!q->entry) + return -ENOMEM; + + q->ndesc = MT_NUM_RX_ENTRIES; + q->head = q->tail = 0; + q->queued = 0; + + return 0; +} + +static int mt76s_alloc_tx(struct mt76_dev *dev) +{ + struct mt76_queue *q; + int i; + + for (i = 0; i < MT_TXQ_MCU_WA; i++) { + INIT_LIST_HEAD(&dev->q_tx[i].swq); + + q = devm_kzalloc(dev->dev, sizeof(*q), GFP_KERNEL); + if (!q) + return -ENOMEM; + + spin_lock_init(&q->lock); + q->hw_idx = i; + dev->q_tx[i].q = q; + + q->entry = devm_kcalloc(dev->dev, + MT_NUM_TX_ENTRIES, sizeof(*q->entry), + GFP_KERNEL); + if (!q->entry) + return -ENOMEM; + + q->ndesc = MT_NUM_TX_ENTRIES; + } + + return 0; +} + +void mt76s_stop_txrx(struct mt76_dev *dev) +{ + struct mt76_sdio *sdio = &dev->sdio; + + cancel_work_sync(&sdio->stat_work); + clear_bit(MT76_READING_STATS, &dev->phy.state); + + mt76_tx_status_check(dev, NULL, true); +} +EXPORT_SYMBOL_GPL(mt76s_stop_txrx); + +int mt76s_alloc_queues(struct mt76_dev *dev) +{ + int err; + + err = mt76s_alloc_rx_queue(dev, MT_RXQ_MAIN); + if (err < 0) + return err; + + return mt76s_alloc_tx(dev); +} +EXPORT_SYMBOL_GPL(mt76s_alloc_queues); + +static struct mt76_queue_entry * +mt76s_get_next_rx_entry(struct mt76_queue *q) +{ + struct mt76_queue_entry *e = NULL; + + spin_lock_bh(&q->lock); + if (q->queued > 0) { + e = &q->entry[q->head]; + q->head = (q->head + 1) % q->ndesc; + q->queued--; + } + spin_unlock_bh(&q->lock); + + return e; +} + +static int +mt76s_process_rx_queue(struct mt76_dev *dev, struct mt76_queue *q) +{ + int qid = q - &dev->q_rx[MT_RXQ_MAIN]; + int nframes = 0; + + while (true) { + struct mt76_queue_entry *e; + + if (!test_bit(MT76_STATE_INITIALIZED, &dev->phy.state)) + break; + + e = mt76s_get_next_rx_entry(q); + if (!e || !e->skb) + break; + + dev->drv->rx_skb(dev, MT_RXQ_MAIN, e->skb); + e->skb = NULL; + nframes++; + } + if (qid == MT_RXQ_MAIN) + mt76_rx_poll_complete(dev, MT_RXQ_MAIN, NULL); + + return nframes; +} + +static int mt76s_process_tx_queue(struct mt76_dev *dev, enum mt76_txq_id qid) +{ + struct mt76_sw_queue *sq = &dev->q_tx[qid]; + u32 n_dequeued = 0, n_sw_dequeued = 0; + struct mt76_queue_entry entry; + struct mt76_queue *q = sq->q; + bool wake; + + while (q->queued > n_dequeued) { + if (q->entry[q->head].schedule) { + q->entry[q->head].schedule = false; + n_sw_dequeued++; + } + + entry = q->entry[q->head]; + q->entry[q->head].done = false; + q->head = (q->head + 1) % q->ndesc; + n_dequeued++; + + if (qid == MT_TXQ_MCU) + dev_kfree_skb(entry.skb); + else + dev->drv->tx_complete_skb(dev, qid, &entry); + } + + spin_lock_bh(&q->lock); + + sq->swq_queued -= n_sw_dequeued; + q->queued -= n_dequeued; + + wake = q->stopped && q->queued < q->ndesc - 8; + if (wake) + q->stopped = false; + + if (!q->queued) + wake_up(&dev->tx_wait); + + spin_unlock_bh(&q->lock); + + if (qid == MT_TXQ_MCU) + goto out; + + mt76_txq_schedule(&dev->phy, qid); + + if (wake) + ieee80211_wake_queue(dev->hw, qid); + + wake_up_process(dev->sdio.tx_kthread); +out: + return n_dequeued; +} + +static void mt76s_tx_status_data(struct work_struct *work) +{ + struct mt76_sdio *sdio; + struct mt76_dev *dev; + u8 update = 1; + u16 count = 0; + + sdio = container_of(work, struct mt76_sdio, stat_work); + dev = container_of(sdio, struct mt76_dev, sdio); + + while (true) { + if (test_bit(MT76_REMOVED, &dev->phy.state)) + break; + + if (!dev->drv->tx_status_data(dev, &update)) + break; + count++; + } + + if (count && test_bit(MT76_STATE_RUNNING, &dev->phy.state)) + queue_work(dev->wq, &sdio->stat_work); + else + clear_bit(MT76_READING_STATS, &dev->phy.state); +} + +static int +mt76s_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_sta *sta) +{ + struct mt76_queue *q = dev->q_tx[qid].q; + struct mt76_tx_info tx_info = { + .skb = skb, + }; + int err, len = skb->len; + u16 idx = q->tail; + + if (q->queued == q->ndesc) + return -ENOSPC; + + skb->prev = skb->next = NULL; + err = dev->drv->tx_prepare_skb(dev, NULL, qid, wcid, sta, &tx_info); + if (err < 0) + return err; + + q->entry[q->tail].skb = tx_info.skb; + q->entry[q->tail].buf_sz = len; + q->tail = (q->tail + 1) % q->ndesc; + + return idx; +} + +static int +mt76s_tx_queue_skb_raw(struct mt76_dev *dev, enum mt76_txq_id qid, + struct sk_buff *skb, u32 tx_info) +{ + struct mt76_queue *q = dev->q_tx[qid].q; + int ret = -ENOSPC, len = skb->len; + + spin_lock_bh(&q->lock); + if (q->queued == q->ndesc) + goto out; + + ret = mt76_skb_adjust_pad(skb); + if (ret) + goto out; + + q->entry[q->tail].buf_sz = len; + q->entry[q->tail].skb = skb; + q->tail = (q->tail + 1) % q->ndesc; + +out: + spin_unlock_bh(&q->lock); + + return ret; +} + +static void mt76s_tx_kick(struct mt76_dev *dev, struct mt76_queue *q) +{ + struct mt76_sdio *sdio = &dev->sdio; + + wake_up_process(sdio->tx_kthread); +} + +static const struct mt76_queue_ops sdio_queue_ops = { + .tx_queue_skb = mt76s_tx_queue_skb, + .kick = mt76s_tx_kick, + .tx_queue_skb_raw = mt76s_tx_queue_skb_raw, +}; + +static int mt76s_kthread_run(void *data) +{ + struct mt76_dev *dev = data; + struct mt76_phy *mphy = &dev->phy; + + while (!kthread_should_stop()) { + int i, nframes = 0; + + cond_resched(); + + /* rx processing */ + local_bh_disable(); + rcu_read_lock(); + + mt76_for_each_q_rx(dev, i) + nframes += mt76s_process_rx_queue(dev, &dev->q_rx[i]); + + rcu_read_unlock(); + local_bh_enable(); + + /* tx processing */ + for (i = 0; i < MT_TXQ_MCU_WA; i++) + nframes += mt76s_process_tx_queue(dev, i); + + if (dev->drv->tx_status_data && + !test_and_set_bit(MT76_READING_STATS, &mphy->state)) + queue_work(dev->wq, &dev->sdio.stat_work); + + if (!nframes || !test_bit(MT76_STATE_RUNNING, &mphy->state)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } + } + + return 0; +} + +void mt76s_deinit(struct mt76_dev *dev) +{ + struct mt76_sdio *sdio = &dev->sdio; + int i; + + kthread_stop(sdio->kthread); + kthread_stop(sdio->tx_kthread); + mt76s_stop_txrx(dev); + + sdio_claim_host(sdio->func); + sdio_release_irq(sdio->func); + sdio_release_host(sdio->func); + + mt76_for_each_q_rx(dev, i) { + struct mt76_queue *q = &dev->q_rx[i]; + int j; + + for (j = 0; j < q->ndesc; j++) { + struct mt76_queue_entry *e = &q->entry[j]; + + if (!e->skb) + continue; + + dev_kfree_skb(e->skb); + e->skb = NULL; + } + } +} +EXPORT_SYMBOL_GPL(mt76s_deinit); + +int mt76s_init(struct mt76_dev *dev, struct sdio_func *func, + const struct mt76_bus_ops *bus_ops) +{ + struct mt76_sdio *sdio = &dev->sdio; + + sdio->kthread = kthread_create(mt76s_kthread_run, dev, "mt76s"); + if (IS_ERR(sdio->kthread)) + return PTR_ERR(sdio->kthread); + + INIT_WORK(&sdio->stat_work, mt76s_tx_status_data); + + mutex_init(&sdio->sched.lock); + dev->queue_ops = &sdio_queue_ops; + dev->bus = bus_ops; + dev->sdio.func = func; + + return 0; +} +EXPORT_SYMBOL_GPL(mt76s_init); + +MODULE_AUTHOR("Sean Wang "); +MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From a66cbdd6573db8515735d37793c22605432c346d Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 15 Jul 2020 14:46:31 +0200 Subject: mt76: mt7615: introduce mt7663s support Introduce support for mt7663s 802.11ac 2x2:2 chipset to mt7615 driver. 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/mt7615/Kconfig | 11 + drivers/net/wireless/mediatek/mt76/mt7615/Makefile | 2 + drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 42 +- drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 10 + drivers/net/wireless/mediatek/mt76/mt7615/mmio.c | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 10 + drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 12 + drivers/net/wireless/mediatek/mt76/mt7615/sdio.c | 478 +++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/sdio.h | 115 +++++ .../net/wireless/mediatek/mt76/mt7615/sdio_mcu.c | 162 +++++++ .../net/wireless/mediatek/mt76/mt7615/sdio_txrx.c | 271 ++++++++++++ .../net/wireless/mediatek/mt76/mt7615/usb_sdio.c | 1 + 12 files changed, 1114 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/sdio.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/sdio.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig index 10a4f1ed9194..f372fb629caf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig @@ -42,3 +42,14 @@ config MT7663U This adds support for MT7663U 802.11ac 2x2:2 wireless devices. To compile this driver as a module, choose M here. + +config MT7663S + tristate "MediaTek MT7663S (SDIO) support" + select MT76_SDIO + select MT7663_USB_SDIO_COMMON + depends on MAC80211 + depends on MMC + help + This adds support for MT7663S 802.11ac 2x2:2 wireless devices. + + To compile this driver as a module, choose M here. diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile index a1cdaadb5442..e8fc4a7ae9bc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_MT7615_COMMON) += mt7615-common.o obj-$(CONFIG_MT7615E) += mt7615e.o obj-$(CONFIG_MT7663_USB_SDIO_COMMON) += mt7663-usb-sdio-common.o obj-$(CONFIG_MT7663U) += mt7663u.o +obj-$(CONFIG_MT7663S) += mt7663s.o CFLAGS_trace.o := -I$(src) @@ -16,3 +17,4 @@ mt7615e-$(CONFIG_MT7622_WMAC) += soc.o mt7663-usb-sdio-common-y := usb_sdio.o mt7663u-y := usb.o usb_mcu.o +mt7663s-y := sdio.o sdio_mcu.o sdio_txrx.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 83e29ee7b08b..2e0928db0aad 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -146,7 +146,10 @@ void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb, mcu_txd->cid = mcu_cmd; break; case MCU_CE_PREFIX: - mcu_txd->set_query = MCU_Q_SET; + if (cmd & MCU_QUERY_MASK) + mcu_txd->set_query = MCU_Q_QUERY; + else + mcu_txd->set_query = MCU_Q_SET; mcu_txd->cid = mcu_cmd; break; default: @@ -214,6 +217,14 @@ mt7615_mcu_parse_response(struct mt7615_dev *dev, int cmd, ret = le32_to_cpu(event->status); break; } + case MCU_CMD_REG_READ: { + struct mt7615_mcu_reg_event *event; + + skb_pull(skb, sizeof(*rxd)); + event = (struct mt7615_mcu_reg_event *)skb->data; + ret = (int)le32_to_cpu(event->val); + break; + } default: break; } @@ -3885,3 +3896,32 @@ int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw, return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_P2P_OPPPS, &req, sizeof(req), false); } + +u32 mt7615_mcu_reg_rr(struct mt76_dev *dev, u32 offset) +{ + struct { + __le32 addr; + __le32 val; + } __packed req = { + .addr = cpu_to_le32(offset), + }; + + return __mt76_mcu_send_msg(dev, MCU_CMD_REG_READ, + &req, sizeof(req), true); +} +EXPORT_SYMBOL_GPL(mt7615_mcu_reg_rr); + +void mt7615_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val) +{ + struct { + __le32 addr; + __le32 val; + } __packed req = { + .addr = cpu_to_le32(offset), + .val = cpu_to_le32(val), + }; + + __mt76_mcu_send_msg(dev, MCU_CMD_REG_WRITE, + &req, sizeof(req), false); +} +EXPORT_SYMBOL_GPL(mt7615_mcu_reg_wr); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index e8c7aa5c35ce..7b856e9eee1e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -81,6 +81,7 @@ enum { MCU_EVENT_GENERIC = 0x01, MCU_EVENT_ACCESS_REG = 0x02, MCU_EVENT_MT_PATCH_SEM = 0x04, + MCU_EVENT_REG_ACCESS = 0x05, MCU_EVENT_SCAN_DONE = 0x0d, MCU_EVENT_ROC = 0x10, MCU_EVENT_BSS_ABSENCE = 0x11, @@ -242,6 +243,8 @@ enum { #define MCU_CMD_MASK ~(MCU_FW_PREFIX | MCU_UNI_PREFIX | \ MCU_CE_PREFIX | MCU_QUERY_PREFIX) +#define MCU_QUERY_MASK BIT(16) + enum { MCU_CMD_TARGET_ADDRESS_LEN_REQ = MCU_FW_PREFIX | 0x01, MCU_CMD_FW_START_REQ = MCU_FW_PREFIX | 0x02, @@ -429,6 +432,11 @@ struct nt7615_sched_scan_done { __le16 pad; } __packed; +struct mt7615_mcu_reg_event { + __le32 reg; + __le32 val; +} __packed; + struct mt7615_mcu_bss_event { u8 bss_idx; u8 is_absent; @@ -581,6 +589,8 @@ enum { MCU_CMD_SET_P2P_OPPPS = MCU_CE_PREFIX | 0x33, MCU_CMD_SCHED_SCAN_ENABLE = MCU_CE_PREFIX | 0x61, MCU_CMD_SCHED_SCAN_REQ = MCU_CE_PREFIX | 0x62, + MCU_CMD_REG_WRITE = MCU_CE_PREFIX | 0xc0, + MCU_CMD_REG_READ = MCU_CE_PREFIX | MCU_QUERY_MASK | 0xc0, }; #define MCU_CMD_ACK BIT(0) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c index 461ac6c42271..133f93a6ed1b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c @@ -43,6 +43,7 @@ const u32 mt7663e_reg_map[] = { [MT_CSR_BASE] = 0x07000, [MT_PLE_BASE] = 0x08000, [MT_PSE_BASE] = 0x0c000, + [MT_PP_BASE] = 0x0e000, [MT_CFG_BASE] = 0x20000, [MT_AGG_BASE] = 0x22000, [MT_TMAC_BASE] = 0x24000, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 38628d28b3dd..571eadc033a3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -656,6 +656,8 @@ int mt7615_mcu_update_arp_filter(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info); int __mt7663_load_firmware(struct mt7615_dev *dev); +u32 mt7615_mcu_reg_rr(struct mt76_dev *dev, u32 offset); +void mt7615_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val); /* usb */ int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, @@ -670,4 +672,12 @@ void mt7663_usb_sdio_wtbl_work(struct work_struct *work); int mt7663_usb_sdio_register_device(struct mt7615_dev *dev); int mt7663u_mcu_init(struct mt7615_dev *dev); +/* sdio */ +u32 mt7663s_read_pcr(struct mt7615_dev *dev); +int mt7663s_mcu_init(struct mt7615_dev *dev); +int mt7663s_driver_own(struct mt7615_dev *dev); +int mt7663s_firmware_own(struct mt7615_dev *dev); +int mt7663s_kthread_run(void *data); +void mt7663s_sdio_irq(struct sdio_func *func); + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 32216bfef4b9..9137d9e6b51d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -28,6 +28,7 @@ enum mt7615_reg_base { MT_PCIE_REMAP_BASE2, MT_TOP_MISC_BASE, MT_EFUSE_ADDR_BASE, + MT_PP_BASE, __MT_BASE_MAX, }; @@ -152,6 +153,8 @@ enum mt7615_reg_base { #define MT_PLE(ofs) ((dev)->reg_map[MT_PLE_BASE] + (ofs)) +#define MT_PLE_PG_HIF0_GROUP MT_PLE(0x110) +#define MT_HIF0_MIN_QUOTA GENMASK(11, 0) #define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0) #define MT_PLE_FL_Q1_CTRL MT_PLE(0x1b4) #define MT_PLE_FL_Q2_CTRL MT_PLE(0x1b8) @@ -161,6 +164,10 @@ enum mt7615_reg_base { ((n) << 2)) #define MT_PSE(ofs) ((dev)->reg_map[MT_PSE_BASE] + (ofs)) +#define MT_PSE_PG_HIF0_GROUP MT_PSE(0x110) +#define MT_HIF0_MIN_QUOTA GENMASK(11, 0) +#define MT_PSE_PG_HIF1_GROUP MT_PSE(0x118) +#define MT_HIF1_MIN_QUOTA GENMASK(11, 0) #define MT_PSE_QUEUE_EMPTY MT_PSE(0x0b4) #define MT_HIF_0_EMPTY_MASK BIT(16) #define MT_HIF_1_EMPTY_MASK BIT(17) @@ -168,6 +175,11 @@ enum mt7615_reg_base { #define MT_PSE_PG_INFO MT_PSE(0x194) #define MT_PSE_SRC_CNT GENMASK(27, 16) +#define MT_PP(ofs) ((dev)->reg_map[MT_PP_BASE] + (ofs)) +#define MT_PP_TXDWCNT MT_PP(0x0) +#define MT_PP_TXDWCNT_TX0_ADD_DW_CNT GENMASK(7, 0) +#define MT_PP_TXDWCNT_TX1_ADD_DW_CNT GENMASK(15, 8) + #define MT_WF_PHY_BASE 0x82070000 #define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c new file mode 100644 index 000000000000..dabce51117b0 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c @@ -0,0 +1,478 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. + * + * Author: Felix Fietkau + * Lorenzo Bianconi + * Sean Wang + */ + +#include +#include +#include + +#include +#include +#include + +#include "mt7615.h" +#include "sdio.h" +#include "mac.h" + +static const struct sdio_device_id mt7663s_table[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7603) }, + { } /* Terminating entry */ +}; + +static u32 mt7663s_read_whisr(struct mt76_dev *dev) +{ + return sdio_readl(dev->sdio.func, MCR_WHISR, NULL); +} + +u32 mt7663s_read_pcr(struct mt7615_dev *dev) +{ + struct mt76_sdio *sdio = &dev->mt76.sdio; + + return sdio_readl(sdio->func, MCR_WHLPCR, NULL); +} + +static u32 mt7663s_read_mailbox(struct mt76_dev *dev, u32 offset) +{ + struct sdio_func *func = dev->sdio.func; + u32 val = ~0, status; + int err; + + sdio_claim_host(func); + + sdio_writel(func, offset, MCR_H2DSM0R, &err); + if (err < 0) { + dev_err(dev->dev, "failed setting address [err=%d]\n", err); + goto out; + } + + sdio_writel(func, H2D_SW_INT_READ, MCR_WSICR, &err); + if (err < 0) { + dev_err(dev->dev, "failed setting read mode [err=%d]\n", err); + goto out; + } + + err = readx_poll_timeout(mt7663s_read_whisr, dev, status, + status & H2D_SW_INT_READ, 0, 1000000); + if (err < 0) { + dev_err(dev->dev, "query whisr timeout\n"); + goto out; + } + + sdio_writel(func, H2D_SW_INT_READ, MCR_WHISR, &err); + if (err < 0) { + dev_err(dev->dev, "failed setting read mode [err=%d]\n", err); + goto out; + } + + val = sdio_readl(func, MCR_H2DSM0R, &err); + if (err < 0) { + dev_err(dev->dev, "failed reading h2dsm0r [err=%d]\n", err); + goto out; + } + + if (val != offset) { + dev_err(dev->dev, "register mismatch\n"); + val = ~0; + goto out; + } + + val = sdio_readl(func, MCR_D2HRM1R, &err); + if (err < 0) + dev_err(dev->dev, "failed reading d2hrm1r [err=%d]\n", err); + +out: + sdio_release_host(func); + + return val; +} + +static void mt7663s_write_mailbox(struct mt76_dev *dev, u32 offset, u32 val) +{ + struct sdio_func *func = dev->sdio.func; + u32 status; + int err; + + sdio_claim_host(func); + + sdio_writel(func, offset, MCR_H2DSM0R, &err); + if (err < 0) { + dev_err(dev->dev, "failed setting address [err=%d]\n", err); + goto out; + } + + sdio_writel(func, val, MCR_H2DSM1R, &err); + if (err < 0) { + dev_err(dev->dev, + "failed setting write value [err=%d]\n", err); + goto out; + } + + sdio_writel(func, H2D_SW_INT_WRITE, MCR_WSICR, &err); + if (err < 0) { + dev_err(dev->dev, "failed setting write mode [err=%d]\n", err); + goto out; + } + + err = readx_poll_timeout(mt7663s_read_whisr, dev, status, + status & H2D_SW_INT_WRITE, 0, 1000000); + if (err < 0) { + dev_err(dev->dev, "query whisr timeout\n"); + goto out; + } + + sdio_writel(func, H2D_SW_INT_WRITE, MCR_WHISR, &err); + if (err < 0) { + dev_err(dev->dev, "failed setting write mode [err=%d]\n", err); + goto out; + } + + val = sdio_readl(func, MCR_H2DSM0R, &err); + if (err < 0) { + dev_err(dev->dev, "failed reading h2dsm0r [err=%d]\n", err); + goto out; + } + + if (val != offset) + dev_err(dev->dev, "register mismatch\n"); + +out: + sdio_release_host(func); +} + +static u32 mt7663s_rr(struct mt76_dev *dev, u32 offset) +{ + if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) + return dev->mcu_ops->mcu_rr(dev, offset); + else + return mt7663s_read_mailbox(dev, offset); +} + +static void mt7663s_wr(struct mt76_dev *dev, u32 offset, u32 val) +{ + if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) + dev->mcu_ops->mcu_wr(dev, offset, val); + else + mt7663s_write_mailbox(dev, offset, val); +} + +static u32 mt7663s_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val) +{ + val |= mt7663s_rr(dev, offset) & ~mask; + mt7663s_wr(dev, offset, val); + + return val; +} + +static void mt7663s_write_copy(struct mt76_dev *dev, u32 offset, + const void *data, int len) +{ + const u32 *val = data; + int i; + + for (i = 0; i < len / sizeof(u32); i++) { + mt7663s_wr(dev, offset, val[i]); + offset += sizeof(u32); + } +} + +static void mt7663s_read_copy(struct mt76_dev *dev, u32 offset, + void *data, int len) +{ + u32 *val = data; + int i; + + for (i = 0; i < len / sizeof(u32); i++) { + val[i] = mt7663s_rr(dev, offset); + offset += sizeof(u32); + } +} + +static int mt7663s_wr_rp(struct mt76_dev *dev, u32 base, + const struct mt76_reg_pair *data, + int len) +{ + int i; + + for (i = 0; i < len; i++) { + mt7663s_wr(dev, data->reg, data->value); + data++; + } + + return 0; +} + +static int mt7663s_rd_rp(struct mt76_dev *dev, u32 base, + struct mt76_reg_pair *data, + int len) +{ + int i; + + for (i = 0; i < len; i++) { + data->value = mt7663s_rr(dev, data->reg); + data++; + } + + return 0; +} + +static void mt7663s_init_work(struct work_struct *work) +{ + struct mt7615_dev *dev; + + dev = container_of(work, struct mt7615_dev, mcu_work); + if (mt7663s_mcu_init(dev)) + return; + + mt7615_mcu_set_eeprom(dev); + mt7615_mac_init(dev); + mt7615_phy_init(dev); + mt7615_mcu_del_wtbl_all(dev); + mt7615_check_offload_capability(dev); +} + +static int mt7663s_hw_init(struct mt7615_dev *dev, struct sdio_func *func) +{ + u32 status, ctrl; + int ret; + + sdio_claim_host(func); + + ret = sdio_enable_func(func); + if (ret < 0) + goto release; + + /* Get ownership from the device */ + sdio_writel(func, WHLPCR_INT_EN_CLR | WHLPCR_FW_OWN_REQ_CLR, + MCR_WHLPCR, &ret); + if (ret < 0) + goto disable_func; + + ret = readx_poll_timeout(mt7663s_read_pcr, dev, status, + status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000); + if (ret < 0) { + dev_err(dev->mt76.dev, "Cannot get ownership from device"); + goto disable_func; + } + + ret = sdio_set_block_size(func, 512); + if (ret < 0) + goto disable_func; + + /* Enable interrupt */ + sdio_writel(func, WHLPCR_INT_EN_SET, MCR_WHLPCR, &ret); + if (ret < 0) + goto disable_func; + + ctrl = WHIER_RX0_DONE_INT_EN | WHIER_TX_DONE_INT_EN; + sdio_writel(func, ctrl, MCR_WHIER, &ret); + if (ret < 0) + goto disable_func; + + /* set WHISR as read clear and Rx aggregation number as 16 */ + ctrl = FIELD_PREP(MAX_HIF_RX_LEN_NUM, 16); + sdio_writel(func, ctrl, MCR_WHCR, &ret); + if (ret < 0) + goto disable_func; + + ret = sdio_claim_irq(func, mt7663s_sdio_irq); + if (ret < 0) + goto disable_func; + + sdio_release_host(func); + + return 0; + +disable_func: + sdio_disable_func(func); +release: + sdio_release_host(func); + + return ret; +} + +static int mt7663s_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + struct mt76_sdio *sdio = &mdev->sdio; + u32 pse, ple; + int err; + + err = mt7615_mac_sta_add(mdev, vif, sta); + if (err < 0) + return err; + + /* init sched data quota */ + pse = mt76_get_field(dev, MT_PSE_PG_HIF0_GROUP, MT_HIF0_MIN_QUOTA); + ple = mt76_get_field(dev, MT_PLE_PG_HIF0_GROUP, MT_HIF0_MIN_QUOTA); + + mutex_lock(&sdio->sched.lock); + sdio->sched.pse_data_quota = pse; + sdio->sched.ple_data_quota = ple; + mutex_unlock(&sdio->sched.lock); + + return 0; +} + +static int mt7663s_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + static const struct mt76_driver_ops drv_ops = { + .txwi_size = MT_USB_TXD_SIZE, + .drv_flags = MT_DRV_RX_DMA_HDR | MT_DRV_HW_MGMT_TXQ, + .tx_prepare_skb = mt7663_usb_sdio_tx_prepare_skb, + .tx_complete_skb = mt7663_usb_sdio_tx_complete_skb, + .tx_status_data = mt7663_usb_sdio_tx_status_data, + .rx_skb = mt7615_queue_rx_skb, + .sta_ps = mt7615_sta_ps, + .sta_add = mt7663s_sta_add, + .sta_remove = mt7615_mac_sta_remove, + .update_survey = mt7615_update_channel, + }; + static const struct mt76_bus_ops mt7663s_ops = { + .rr = mt7663s_rr, + .rmw = mt7663s_rmw, + .wr = mt7663s_wr, + .write_copy = mt7663s_write_copy, + .read_copy = mt7663s_read_copy, + .wr_rp = mt7663s_wr_rp, + .rd_rp = mt7663s_rd_rp, + .type = MT76_BUS_SDIO, + }; + struct ieee80211_ops *ops; + struct mt7615_dev *dev; + struct mt76_dev *mdev; + int ret; + + ops = devm_kmemdup(&func->dev, &mt7615_ops, sizeof(mt7615_ops), + GFP_KERNEL); + if (!ops) + return -ENOMEM; + + mdev = mt76_alloc_device(&func->dev, sizeof(*dev), ops, &drv_ops); + if (!mdev) + return -ENOMEM; + + dev = container_of(mdev, struct mt7615_dev, mt76); + + INIT_WORK(&dev->mcu_work, mt7663s_init_work); + dev->reg_map = mt7663_usb_sdio_reg_map; + dev->ops = ops; + sdio_set_drvdata(func, dev); + + mdev->sdio.tx_kthread = kthread_create(mt7663s_kthread_run, dev, + "mt7663s_tx"); + if (IS_ERR(mdev->sdio.tx_kthread)) + return PTR_ERR(mdev->sdio.tx_kthread); + + ret = mt76s_init(mdev, func, &mt7663s_ops); + if (ret < 0) + goto err_free; + + ret = mt7663s_hw_init(dev, func); + if (ret) + goto err_free; + + mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) | + (mt76_rr(dev, MT_HW_REV) & 0xff); + dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev); + + ret = mt76s_alloc_queues(&dev->mt76); + if (ret) + goto err_deinit; + + ret = mt7663_usb_sdio_register_device(dev); + if (ret) + goto err_deinit; + + return 0; + +err_deinit: + mt76s_deinit(&dev->mt76); +err_free: + mt76_free_device(&dev->mt76); + + return ret; +} + +static void mt7663s_remove(struct sdio_func *func) +{ + struct mt7615_dev *dev = sdio_get_drvdata(func); + + if (!test_and_clear_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) + return; + + ieee80211_unregister_hw(dev->mt76.hw); + mt76s_deinit(&dev->mt76); + mt76_free_device(&dev->mt76); +} + +#ifdef CONFIG_PM +static int mt7663s_suspend(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct mt7615_dev *mdev = sdio_get_drvdata(func); + + if (!test_bit(MT76_STATE_SUSPEND, &mdev->mphy.state) && + mt7615_firmware_offload(mdev)) { + int err; + + err = mt7615_mcu_set_hif_suspend(mdev, true); + if (err < 0) + return err; + } + + mt76s_stop_txrx(&mdev->mt76); + + return mt7663s_firmware_own(mdev); +} + +static int mt7663s_resume(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct mt7615_dev *mdev = sdio_get_drvdata(func); + int err; + + err = mt7663s_driver_own(mdev); + if (err) + return err; + + if (!test_bit(MT76_STATE_SUSPEND, &mdev->mphy.state) && + mt7615_firmware_offload(mdev)) + err = mt7615_mcu_set_hif_suspend(mdev, false); + + return err; +} + +static const struct dev_pm_ops mt7663s_pm_ops = { + .suspend = mt7663s_suspend, + .resume = mt7663s_resume, +}; +#endif + +MODULE_DEVICE_TABLE(sdio, mt7663s_table); +MODULE_FIRMWARE(MT7663_OFFLOAD_FIRMWARE_N9); +MODULE_FIRMWARE(MT7663_OFFLOAD_ROM_PATCH); +MODULE_FIRMWARE(MT7663_FIRMWARE_N9); +MODULE_FIRMWARE(MT7663_ROM_PATCH); + +static struct sdio_driver mt7663s_driver = { + .name = KBUILD_MODNAME, + .probe = mt7663s_probe, + .remove = mt7663s_remove, + .id_table = mt7663s_table, +#ifdef CONFIG_PM + .drv = { + .pm = &mt7663s_pm_ops, + } +#endif +}; +module_sdio_driver(mt7663s_driver); + +MODULE_AUTHOR("Sean Wang "); +MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h new file mode 100644 index 000000000000..05180971de84 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. + * + * Author: Sean Wang + */ + +#ifndef __MT76S_H +#define __MT76S_H + +#define MT_PSE_PAGE_SZ 128 + +#define MCR_WCIR 0x0000 +#define MCR_WHLPCR 0x0004 +#define WHLPCR_FW_OWN_REQ_CLR BIT(9) +#define WHLPCR_FW_OWN_REQ_SET BIT(8) +#define WHLPCR_IS_DRIVER_OWN BIT(8) +#define WHLPCR_INT_EN_CLR BIT(1) +#define WHLPCR_INT_EN_SET BIT(0) + +#define MCR_WSDIOCSR 0x0008 +#define MCR_WHCR 0x000C +#define W_INT_CLR_CTRL BIT(1) +#define RECV_MAILBOX_RD_CLR_EN BIT(2) +#define MAX_HIF_RX_LEN_NUM GENMASK(13, 8) +#define RX_ENHANCE_MODE BIT(16) + +#define MCR_WHISR 0x0010 +#define MCR_WHIER 0x0014 +#define WHIER_D2H_SW_INT GENMASK(31, 8) +#define WHIER_FW_OWN_BACK_INT_EN BIT(7) +#define WHIER_ABNORMAL_INT_EN BIT(6) +#define WHIER_RX1_DONE_INT_EN BIT(2) +#define WHIER_RX0_DONE_INT_EN BIT(1) +#define WHIER_TX_DONE_INT_EN BIT(0) +#define WHIER_DEFAULT (WHIER_RX0_DONE_INT_EN | \ + WHIER_RX1_DONE_INT_EN | \ + WHIER_TX_DONE_INT_EN | \ + WHIER_ABNORMAL_INT_EN | \ + WHIER_D2H_SW_INT) + +#define MCR_WASR 0x0020 +#define MCR_WSICR 0x0024 +#define MCR_WTSR0 0x0028 +#define TQ0_CNT GENMASK(7, 0) +#define TQ1_CNT GENMASK(15, 8) +#define TQ2_CNT GENMASK(23, 16) +#define TQ3_CNT GENMASK(31, 24) + +#define MCR_WTSR1 0x002c +#define TQ4_CNT GENMASK(7, 0) +#define TQ5_CNT GENMASK(15, 8) +#define TQ6_CNT GENMASK(23, 16) +#define TQ7_CNT GENMASK(31, 24) + +#define MCR_WTDR1 0x0034 +#define MCR_WRDR0 0x0050 +#define MCR_WRDR1 0x0054 +#define MCR_WRDR(p) (0x0050 + 4 * (p)) +#define MCR_H2DSM0R 0x0070 +#define H2D_SW_INT_READ BIT(16) +#define H2D_SW_INT_WRITE BIT(17) + +#define MCR_H2DSM1R 0x0074 +#define MCR_D2HRM0R 0x0078 +#define MCR_D2HRM1R 0x007c +#define MCR_D2HRM2R 0x0080 +#define MCR_WRPLR 0x0090 +#define RX0_PACKET_LENGTH GENMASK(15, 0) +#define RX1_PACKET_LENGTH GENMASK(31, 16) + +#define MCR_WTMDR 0x00b0 +#define MCR_WTMCR 0x00b4 +#define MCR_WTMDPCR0 0x00b8 +#define MCR_WTMDPCR1 0x00bc +#define MCR_WPLRCR 0x00d4 +#define MCR_WSR 0x00D8 +#define MCR_CLKIOCR 0x0100 +#define MCR_CMDIOCR 0x0104 +#define MCR_DAT0IOCR 0x0108 +#define MCR_DAT1IOCR 0x010C +#define MCR_DAT2IOCR 0x0110 +#define MCR_DAT3IOCR 0x0114 +#define MCR_CLKDLYCR 0x0118 +#define MCR_CMDDLYCR 0x011C +#define MCR_ODATDLYCR 0x0120 +#define MCR_IDATDLYCR1 0x0124 +#define MCR_IDATDLYCR2 0x0128 +#define MCR_ILCHCR 0x012C +#define MCR_WTQCR0 0x0130 +#define MCR_WTQCR1 0x0134 +#define MCR_WTQCR2 0x0138 +#define MCR_WTQCR3 0x013C +#define MCR_WTQCR4 0x0140 +#define MCR_WTQCR5 0x0144 +#define MCR_WTQCR6 0x0148 +#define MCR_WTQCR7 0x014C +#define MCR_WTQCR(x) (0x130 + 4 * (x)) +#define TXQ_CNT_L GENMASK(15, 0) +#define TXQ_CNT_H GENMASK(31, 16) + +#define MCR_SWPCDBGR 0x0154 + +struct mt76s_intr { + u32 isr; + struct { + u32 wtqcr[8]; + } tx; + struct { + u16 num[2]; + u16 len[2][16]; + } rx; + u32 rec_mb[2]; +} __packed; + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c new file mode 100644 index 000000000000..28b86bec7fc2 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2020 MediaTek Inc. + * + * Author: Felix Fietkau + * Lorenzo Bianconi + * Sean Wang + */ +#include +#include +#include +#include + +#include "mt7615.h" +#include "mac.h" +#include "mcu.h" +#include "regs.h" +#include "sdio.h" + +static int mt7663s_mcu_init_sched(struct mt7615_dev *dev) +{ + struct mt76_sdio *sdio = &dev->mt76.sdio; + u32 pse0, ple, pse1, txdwcnt; + + pse0 = mt76_get_field(dev, MT_PSE_PG_HIF0_GROUP, MT_HIF0_MIN_QUOTA); + pse1 = mt76_get_field(dev, MT_PSE_PG_HIF1_GROUP, MT_HIF1_MIN_QUOTA); + ple = mt76_get_field(dev, MT_PLE_PG_HIF0_GROUP, MT_HIF0_MIN_QUOTA); + txdwcnt = mt76_get_field(dev, MT_PP_TXDWCNT, + MT_PP_TXDWCNT_TX1_ADD_DW_CNT); + + mutex_lock(&sdio->sched.lock); + + sdio->sched.pse_data_quota = pse0; + sdio->sched.ple_data_quota = ple; + sdio->sched.pse_mcu_quota = pse1; + sdio->sched.deficit = txdwcnt << 2; + + mutex_unlock(&sdio->sched.lock); + + return 0; +} + +static int +mt7663s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, + int cmd, bool wait_resp) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + int ret, seq; + + mutex_lock(&mdev->mcu.mutex); + + mt7615_mcu_fill_msg(dev, skb, cmd, &seq); + ret = mt76_tx_queue_skb_raw(dev, MT_TXQ_MCU, skb, 0); + if (ret) + goto out; + + mt76_queue_kick(dev, mdev->q_tx[MT_TXQ_MCU].q); + if (wait_resp) + ret = mt7615_mcu_wait_response(dev, cmd, seq); + +out: + mutex_unlock(&mdev->mcu.mutex); + + return ret; +} + +int mt7663s_driver_own(struct mt7615_dev *dev) +{ + struct sdio_func *func = dev->mt76.sdio.func; + struct mt76_phy *mphy = &dev->mt76.phy; + u32 status; + int ret; + + if (!test_and_clear_bit(MT76_STATE_PM, &mphy->state)) + goto out; + + sdio_claim_host(func); + + sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, 0); + + ret = readx_poll_timeout(mt7663s_read_pcr, dev, status, + status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000); + 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; + } + + sdio_release_host(func); + +out: + dev->pm.last_activity = jiffies; + + return 0; +} + +int mt7663s_firmware_own(struct mt7615_dev *dev) +{ + struct sdio_func *func = dev->mt76.sdio.func; + struct mt76_phy *mphy = &dev->mt76.phy; + u32 status; + int ret; + + if (test_and_set_bit(MT76_STATE_PM, &mphy->state)) + return 0; + + sdio_claim_host(func); + + sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, 0); + + ret = readx_poll_timeout(mt7663s_read_pcr, dev, status, + !(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000); + if (ret < 0) { + dev_err(dev->mt76.dev, "Cannot set ownership to device"); + clear_bit(MT76_STATE_PM, &mphy->state); + } + + sdio_release_host(func); + + return ret; +} + +int mt7663s_mcu_init(struct mt7615_dev *dev) +{ + static const struct mt76_mcu_ops mt7663s_mcu_ops = { + .headroom = sizeof(struct mt7615_mcu_txd), + .tailroom = MT_USB_TAIL_SIZE, + .mcu_skb_send_msg = mt7663s_mcu_send_message, + .mcu_send_msg = mt7615_mcu_msg_send, + .mcu_restart = mt7615_mcu_restart, + .mcu_rr = mt7615_mcu_reg_rr, + .mcu_wr = mt7615_mcu_reg_wr, + }; + int ret; + + ret = mt7663s_driver_own(dev); + if (ret) + return ret; + + dev->mt76.mcu_ops = &mt7663s_mcu_ops, + + ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); + if (ret) { + mt7615_mcu_restart(&dev->mt76); + if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, + MT_TOP_MISC2_FW_N9_RDY, 0, 500)) + return -EIO; + } + + ret = __mt7663_load_firmware(dev); + if (ret) + return ret; + + ret = mt7663s_mcu_init_sched(dev); + if (ret) + return ret; + + set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); + + return 0; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c new file mode 100644 index 000000000000..156666a94eb7 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. + * + * Author: Felix Fietkau + * Lorenzo Bianconi + * Sean Wang + */ + +#include +#include +#include + +#include +#include +#include + +#include "../trace.h" +#include "mt7615.h" +#include "sdio.h" +#include "mac.h" + +static void mt7663s_refill_sched_quota(struct mt7615_dev *dev, u32 *data) +{ + struct mt76_sdio *sdio = &dev->mt76.sdio; + + mutex_lock(&sdio->sched.lock); + sdio->sched.pse_data_quota += FIELD_GET(TXQ_CNT_L, data[0]) + /* BK */ + FIELD_GET(TXQ_CNT_H, data[0]) + /* BE */ + FIELD_GET(TXQ_CNT_L, data[1]) + /* VI */ + FIELD_GET(TXQ_CNT_H, data[1]); /* VO */ + sdio->sched.ple_data_quota += FIELD_GET(TXQ_CNT_H, data[2]) + /* BK */ + FIELD_GET(TXQ_CNT_L, data[3]) + /* BE */ + FIELD_GET(TXQ_CNT_H, data[3]) + /* VI */ + FIELD_GET(TXQ_CNT_L, data[4]); /* VO */ + sdio->sched.pse_mcu_quota += FIELD_GET(TXQ_CNT_L, data[2]); + mutex_unlock(&sdio->sched.lock); +} + +static struct sk_buff *mt7663s_build_rx_skb(void *data, int data_len, + int buf_len) +{ + int len = min_t(int, data_len, MT_SKB_HEAD_LEN); + struct sk_buff *skb; + + skb = alloc_skb(len, GFP_KERNEL); + if (!skb) + return NULL; + + skb_put_data(skb, data, len); + if (data_len > len) { + struct page *page; + + data += len; + page = virt_to_head_page(data); + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, + page, data - page_address(page), + data_len - len, buf_len); + get_page(page); + } + + return skb; +} + +static int mt7663s_rx_run_queue(struct mt7615_dev *dev, enum mt76_rxq_id qid, + struct mt76s_intr *intr) +{ + struct mt76_queue *q = &dev->mt76.q_rx[qid]; + struct mt76_sdio *sdio = &dev->mt76.sdio; + int len = 0, err, i, order; + struct page *page; + u8 *buf; + + for (i = 0; i < intr->rx.num[qid]; i++) + len += round_up(intr->rx.len[qid][i] + 4, 4); + + if (!len) + return 0; + + if (len > sdio->func->cur_blksize) + len = roundup(len, sdio->func->cur_blksize); + + order = get_order(len); + page = __dev_alloc_pages(GFP_KERNEL, order); + if (!page) + return -ENOMEM; + + buf = page_address(page); + + err = sdio_readsb(sdio->func, buf, MCR_WRDR(qid), len); + if (err < 0) { + dev_err(dev->mt76.dev, "sdio read data failed:%d\n", err); + __free_pages(page, order); + return err; + } + + for (i = 0; i < intr->rx.num[qid]; i++) { + int index = (q->tail + i) % q->ndesc; + struct mt76_queue_entry *e = &q->entry[index]; + + len = intr->rx.len[qid][i]; + e->skb = mt7663s_build_rx_skb(buf, len, round_up(len + 4, 4)); + if (!e->skb) + break; + + buf += round_up(len + 4, 4); + if (q->queued + i + 1 == q->ndesc) + break; + } + __free_pages(page, order); + + spin_lock_bh(&q->lock); + q->tail = (q->tail + i) % q->ndesc; + q->queued += i; + spin_unlock_bh(&q->lock); + + return err; +} + +static int mt7663s_tx_update_sched(struct mt7615_dev *dev, + struct mt76_queue_entry *e, + bool mcu) +{ + struct mt76_sdio *sdio = &dev->mt76.sdio; + struct mt76_phy *mphy = &dev->mt76.phy; + struct ieee80211_hdr *hdr; + int size, ret = -EBUSY; + + size = DIV_ROUND_UP(e->buf_sz + sdio->sched.deficit, MT_PSE_PAGE_SZ); + + if (mcu) { + if (!test_bit(MT76_STATE_MCU_RUNNING, &mphy->state)) + return 0; + + mutex_lock(&sdio->sched.lock); + if (sdio->sched.pse_mcu_quota > size) { + sdio->sched.pse_mcu_quota -= size; + ret = 0; + } + mutex_unlock(&sdio->sched.lock); + + return ret; + } + + hdr = (struct ieee80211_hdr *)(e->skb->data + MT_USB_TXD_SIZE); + if (ieee80211_is_ctl(hdr->frame_control)) + return 0; + + mutex_lock(&sdio->sched.lock); + if (sdio->sched.pse_data_quota > size && + sdio->sched.ple_data_quota > 0) { + sdio->sched.pse_data_quota -= size; + sdio->sched.ple_data_quota--; + ret = 0; + } + mutex_unlock(&sdio->sched.lock); + + return ret; +} + +static int mt7663s_tx_run_queue(struct mt7615_dev *dev, struct mt76_queue *q) +{ + bool mcu = q == dev->mt76.q_tx[MT_TXQ_MCU].q; + struct mt76_sdio *sdio = &dev->mt76.sdio; + int nframes = 0; + + while (q->first != q->tail) { + struct mt76_queue_entry *e = &q->entry[q->first]; + int err, len = e->skb->len; + + if (mt7663s_tx_update_sched(dev, e, mcu)) + break; + + if (len > sdio->func->cur_blksize) + len = roundup(len, sdio->func->cur_blksize); + + /* TODO: skb_walk_frags and then write to SDIO port */ + err = sdio_writesb(sdio->func, MCR_WTDR1, e->skb->data, len); + if (err) { + dev_err(dev->mt76.dev, "sdio write failed: %d\n", err); + return -EIO; + } + + q->first = (q->first + 1) % q->ndesc; + nframes++; + } + + spin_lock_bh(&q->lock); + q->queued += nframes; + spin_unlock_bh(&q->lock); + + return nframes; +} + +static int mt7663s_tx_run_queues(struct mt7615_dev *dev) +{ + int i, nframes = 0; + + for (i = 0; i < MT_TXQ_MCU_WA; i++) { + int ret; + + ret = mt7663s_tx_run_queue(dev, dev->mt76.q_tx[i].q); + if (ret < 0) + return ret; + + nframes += ret; + } + + return nframes; +} + +int mt7663s_kthread_run(void *data) +{ + struct mt7615_dev *dev = data; + struct mt76_phy *mphy = &dev->mt76.phy; + + while (!kthread_should_stop()) { + int ret; + + cond_resched(); + + sdio_claim_host(dev->mt76.sdio.func); + ret = mt7663s_tx_run_queues(dev); + sdio_release_host(dev->mt76.sdio.func); + + if (ret <= 0 || !test_bit(MT76_STATE_RUNNING, &mphy->state)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } else { + wake_up_process(dev->mt76.sdio.kthread); + } + } + + return 0; +} + +void mt7663s_sdio_irq(struct sdio_func *func) +{ + struct mt7615_dev *dev = sdio_get_drvdata(func); + struct mt76_sdio *sdio = &dev->mt76.sdio; + struct mt76s_intr intr; + + /* disable interrupt */ + sdio_writel(func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, 0); + + do { + sdio_readsb(func, &intr, MCR_WHISR, sizeof(struct mt76s_intr)); + trace_dev_irq(&dev->mt76, intr.isr, 0); + + if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.phy.state)) + goto out; + + if (intr.isr & WHIER_RX0_DONE_INT_EN) { + mt7663s_rx_run_queue(dev, 0, &intr); + wake_up_process(sdio->kthread); + } + + if (intr.isr & WHIER_RX1_DONE_INT_EN) { + mt7663s_rx_run_queue(dev, 1, &intr); + wake_up_process(sdio->kthread); + } + + if (intr.isr & WHIER_TX_DONE_INT_EN) { + mt7663s_refill_sched_quota(dev, intr.tx.wtqcr); + mt7663s_tx_run_queues(dev); + wake_up_process(sdio->kthread); + } + } while (intr.isr); +out: + /* enable interrupt */ + sdio_writel(func, WHLPCR_INT_EN_SET, MCR_WHLPCR, 0); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c index 50009bc5ee8d..6dffdaaa9ad5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c @@ -24,6 +24,7 @@ const u32 mt7663_usb_sdio_reg_map[] = { [MT_TOP_MISC_BASE] = 0x81020000, [MT_PLE_BASE] = 0x82060000, [MT_PSE_BASE] = 0x82068000, + [MT_PP_BASE] = 0x8206c000, [MT_WTBL_BASE_ADDR] = 0x820e0000, [MT_CFG_BASE] = 0x820f0000, [MT_AGG_BASE] = 0x820f2000, -- cgit v1.2.3 From 1f8284150dbc6a6995d8647be025944ebc29ad26 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 17 Jul 2020 10:57:39 +0200 Subject: mt76: mt76s: move queue accounting in mt76s_tx_queue_skb In order to avoid possible overflows, move tx queue accounting from mt7663s_tx_run_queue() to mt76s_tx_queue_skb_raw()/mt76s_tx_queue_skb() Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c | 5 +---- drivers/net/wireless/mediatek/mt76/sdio.c | 5 +++++ 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c index 156666a94eb7..443a4ecdad3a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c @@ -180,14 +180,11 @@ static int mt7663s_tx_run_queue(struct mt7615_dev *dev, struct mt76_queue *q) return -EIO; } + e->done = true; q->first = (q->first + 1) % q->ndesc; nframes++; } - spin_lock_bh(&q->lock); - q->queued += nframes; - spin_unlock_bh(&q->lock); - return nframes; } diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c index a6f3255c4d84..d2b38ed7f3b4 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/sdio.c @@ -138,6 +138,9 @@ static int mt76s_process_tx_queue(struct mt76_dev *dev, enum mt76_txq_id qid) bool wake; while (q->queued > n_dequeued) { + if (!q->entry[q->head].done) + break; + if (q->entry[q->head].schedule) { q->entry[q->head].schedule = false; n_sw_dequeued++; @@ -229,6 +232,7 @@ mt76s_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid, q->entry[q->tail].skb = tx_info.skb; q->entry[q->tail].buf_sz = len; q->tail = (q->tail + 1) % q->ndesc; + q->queued++; return idx; } @@ -251,6 +255,7 @@ mt76s_tx_queue_skb_raw(struct mt76_dev *dev, enum mt76_txq_id qid, q->entry[q->tail].buf_sz = len; q->entry[q->tail].skb = skb; q->tail = (q->tail + 1) % q->ndesc; + q->queued++; out: spin_unlock_bh(&q->lock); -- cgit v1.2.3 From 4c7e1711cf4cdaf7124d3794c42c1b29af72740b Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sun, 12 Jul 2020 01:25:51 +0800 Subject: mt76: mt7915: fix potential memory leak in mcu message handler Fix potential memory leak in mcu message handler on error condition. Fixes: c6b002bcdfa6 ("mt76: add mac80211 driver for MT7915 PCIe-based chipsets") Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 93b1439e147b..eaed5ef05401 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -312,8 +312,10 @@ mt7915_mcu_parse_response(struct mt7915_dev *dev, int cmd, struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; int ret = 0; - if (seq != rxd->seq) - return -EAGAIN; + if (seq != rxd->seq) { + ret = -EAGAIN; + goto out; + } switch (cmd) { case -MCU_CMD_PATCH_SEM_CONTROL: @@ -330,6 +332,7 @@ mt7915_mcu_parse_response(struct mt7915_dev *dev, int cmd, default: break; } +out: dev_kfree_skb(skb); return ret; -- cgit v1.2.3 From 2bccc8415883c1cd5ae8836548d9783dbbd84999 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 21 Jul 2020 10:19:22 +0200 Subject: mt76: mt7615: fix possible memory leak in mt7615_mcu_wtbl_sta_add Free the second mcu skb if __mt76_mcu_skb_send_msg() fails to transmit the first one in mt7615_mcu_wtbl_sta_add(). Fixes: 99c457d902cf9 ("mt76: mt7615: move mt7615_mcu_set_bmc to mt7615_mcu_ops") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 2e0928db0aad..d0cbb283982f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1293,8 +1293,12 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_dev *dev, struct ieee80211_vif *vif, skb = enable ? wskb : sskb; err = __mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true); - if (err < 0) + if (err < 0) { + skb = enable ? sskb : wskb; + dev_kfree_skb(skb); + return err; + } cmd = enable ? MCU_EXT_CMD_STA_REC_UPDATE : MCU_EXT_CMD_WTBL_UPDATE; skb = enable ? sskb : wskb; -- cgit v1.2.3 From 5648d1c9cadb0a6afb29dd8891159906dadf5c77 Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Sat, 18 Jul 2020 00:47:26 -0500 Subject: mt76: mt76u: add missing release on skb in __mt76x02u_mcu_send_msg In the implementation of __mt76x02u_mcu_send_msg() the skb is consumed all execution paths except one. Release skb before returning if test_bit() fails. Signed-off-by: Navid Emamdoost Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c index a30bb536fc8a..e43d13d7c988 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c @@ -87,8 +87,10 @@ __mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, u32 info; int ret; - if (test_bit(MT76_REMOVED, &dev->phy.state)) - return 0; + if (test_bit(MT76_REMOVED, &dev->phy.state)) { + ret = 0; + goto out; + } if (wait_resp) { seq = ++dev->mcu.msg_seq & 0xf; @@ -111,6 +113,7 @@ __mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, if (wait_resp) ret = mt76x02u_mcu_wait_resp(dev, seq); +out: consume_skb(skb); return ret; -- cgit v1.2.3 From 56b06d4da8128a73dd1568cf65cb57725cc71968 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 23 Jul 2020 17:32:14 +0100 Subject: rtlwifi: btcoex: remove redundant initialization of variables ant_num and single_ant_path The variables ant_num and single_ant_path are being initialized with a value that is never read and are being updated later with a new value. The initializations are redundant and can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200723163214.995226-1-colin.king@canonical.com --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index a4940a3842de..4949f99844b5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -1318,7 +1318,7 @@ bool exhalbtc_bind_bt_coex_withadapter(void *adapter) { struct rtl_priv *rtlpriv = adapter; struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); - u8 ant_num = 2, chip_type, single_ant_path = 0; + u8 ant_num, chip_type, single_ant_path; if (!btcoexist) return false; -- cgit v1.2.3 From 1751a7352b632991600c3e7e604be3920a82b386 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 30 Jul 2020 18:40:26 +0300 Subject: rtlwifi: btcoex: use %*ph to print small buffer Use %*ph format to print small buffer as hex string. Signed-off-by: Andy Shevchenko Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200730154026.39901-1-andriy.shevchenko@linux.intel.com --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index 4949f99844b5..2b140c1e8e8d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -894,11 +894,9 @@ static void halbtc_display_wifi_status(struct btc_coexist *btcoexist, (low_power ? ", 32k" : "")); seq_printf(m, - "\n %-35s = %02x %02x %02x %02x %02x %02x (0x%x/0x%x)", + "\n %-35s = %6ph (0x%x/0x%x)", "Power mode cmd(lps/rpwm)", - btcoexist->pwr_mode_val[0], btcoexist->pwr_mode_val[1], - btcoexist->pwr_mode_val[2], btcoexist->pwr_mode_val[3], - btcoexist->pwr_mode_val[4], btcoexist->pwr_mode_val[5], + btcoexist->pwr_mode_val, btcoexist->bt_info.lps_val, btcoexist->bt_info.rpwm_val); } -- cgit v1.2.3 From 614946480f8f7de9ad077bca36e0c433e426a3dd Mon Sep 17 00:00:00 2001 From: Xu Wang Date: Mon, 27 Jul 2020 02:04:05 +0000 Subject: mwifiex: 11n_rxreorder: Remove unnecessary cast in kfree() Remove unnecassary casts in the argument to kfree. Signed-off-by: Xu Wang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200727020405.8476-1-vulab@iscas.ac.cn --- drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c index 0bdafe9f66db..1046b59647f5 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c @@ -398,7 +398,7 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, new_node->rx_reorder_ptr = kcalloc(win_size, sizeof(void *), GFP_KERNEL); if (!new_node->rx_reorder_ptr) { - kfree((u8 *) new_node); + kfree(new_node); mwifiex_dbg(priv->adapter, ERROR, "%s: failed to alloc reorder_ptr\n", __func__); return; -- cgit v1.2.3 From ba78405ecaac382d65d16dcd6798d8c64e264432 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 22 Jul 2020 12:27:07 +0200 Subject: p54: switch from 'pci_' to 'dma_' API The wrappers in include/linux/pci-dma-compat.h should go away. The patch has been generated with the coccinelle script below and has been hand modified to replace GFP_ with a correct flag. It has been compile tested. When memory is allocated in 'p54p_probe()', GFP_KERNEL can be used because it is the probe function and no spin_lock is taken in the between. @@ @@ - PCI_DMA_BIDIRECTIONAL + DMA_BIDIRECTIONAL @@ @@ - PCI_DMA_TODEVICE + DMA_TO_DEVICE @@ @@ - PCI_DMA_FROMDEVICE + DMA_FROM_DEVICE @@ @@ - PCI_DMA_NONE + DMA_NONE @@ expression e1, e2, e3; @@ - pci_alloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3; @@ - pci_zalloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3, e4; @@ - pci_free_consistent(e1, e2, e3, e4) + dma_free_coherent(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_single(e1, e2, e3, e4) + dma_map_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_single(e1, e2, e3, e4) + dma_unmap_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4, e5; @@ - pci_map_page(e1, e2, e3, e4, e5) + dma_map_page(&e1->dev, e2, e3, e4, e5) @@ expression e1, e2, e3, e4; @@ - pci_unmap_page(e1, e2, e3, e4) + dma_unmap_page(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_sg(e1, e2, e3, e4) + dma_map_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_sg(e1, e2, e3, e4) + dma_unmap_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_cpu(e1, e2, e3, e4) + dma_sync_single_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_device(e1, e2, e3, e4) + dma_sync_single_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_cpu(e1, e2, e3, e4) + dma_sync_sg_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_device(e1, e2, e3, e4) + dma_sync_sg_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2; @@ - pci_dma_mapping_error(e1, e2) + dma_mapping_error(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_dma_mask(e1, e2) + dma_set_mask(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_consistent_dma_mask(e1, e2) + dma_set_coherent_mask(&e1->dev, e2) Signed-off-by: Christophe JAILLET Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200722102707.27486-1-christophe.jaillet@wanadoo.fr --- drivers/net/wireless/intersil/p54/p54pci.c | 65 ++++++++++++++++-------------- 1 file changed, 35 insertions(+), 30 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intersil/p54/p54pci.c b/drivers/net/wireless/intersil/p54/p54pci.c index 80ad0b7eaef4..9d96c8b8409d 100644 --- a/drivers/net/wireless/intersil/p54/p54pci.c +++ b/drivers/net/wireless/intersil/p54/p54pci.c @@ -153,12 +153,12 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev, if (!skb) break; - mapping = pci_map_single(priv->pdev, + mapping = dma_map_single(&priv->pdev->dev, skb_tail_pointer(skb), priv->common.rx_mtu + 32, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); - if (pci_dma_mapping_error(priv->pdev, mapping)) { + if (dma_mapping_error(&priv->pdev->dev, mapping)) { dev_kfree_skb_any(skb); dev_err(&priv->pdev->dev, "RX DMA Mapping error\n"); @@ -215,19 +215,22 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index, len = priv->common.rx_mtu; } dma_addr = le32_to_cpu(desc->host_addr); - pci_dma_sync_single_for_cpu(priv->pdev, dma_addr, - priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE); + dma_sync_single_for_cpu(&priv->pdev->dev, dma_addr, + priv->common.rx_mtu + 32, + DMA_FROM_DEVICE); skb_put(skb, len); if (p54_rx(dev, skb)) { - pci_unmap_single(priv->pdev, dma_addr, - priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pdev->dev, dma_addr, + priv->common.rx_mtu + 32, + DMA_FROM_DEVICE); rx_buf[i] = NULL; desc->host_addr = cpu_to_le32(0); } else { skb_trim(skb, 0); - pci_dma_sync_single_for_device(priv->pdev, dma_addr, - priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE); + dma_sync_single_for_device(&priv->pdev->dev, dma_addr, + priv->common.rx_mtu + 32, + DMA_FROM_DEVICE); desc->len = cpu_to_le16(priv->common.rx_mtu + 32); } @@ -258,8 +261,9 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, skb = tx_buf[i]; tx_buf[i] = NULL; - pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), - le16_to_cpu(desc->len), PCI_DMA_TODEVICE); + dma_unmap_single(&priv->pdev->dev, + le32_to_cpu(desc->host_addr), + le16_to_cpu(desc->len), DMA_TO_DEVICE); desc->host_addr = 0; desc->device_addr = 0; @@ -334,9 +338,9 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb) idx = le32_to_cpu(ring_control->host_idx[1]); i = idx % ARRAY_SIZE(ring_control->tx_data); - mapping = pci_map_single(priv->pdev, skb->data, skb->len, - PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(priv->pdev, mapping)) { + mapping = dma_map_single(&priv->pdev->dev, skb->data, skb->len, + DMA_TO_DEVICE); + if (dma_mapping_error(&priv->pdev->dev, mapping)) { spin_unlock_irqrestore(&priv->lock, flags); p54_free_skb(dev, skb); dev_err(&priv->pdev->dev, "TX DMA mapping error\n"); @@ -378,10 +382,10 @@ static void p54p_stop(struct ieee80211_hw *dev) for (i = 0; i < ARRAY_SIZE(priv->rx_buf_data); i++) { desc = &ring_control->rx_data[i]; if (desc->host_addr) - pci_unmap_single(priv->pdev, + dma_unmap_single(&priv->pdev->dev, le32_to_cpu(desc->host_addr), priv->common.rx_mtu + 32, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); kfree_skb(priv->rx_buf_data[i]); priv->rx_buf_data[i] = NULL; } @@ -389,10 +393,10 @@ static void p54p_stop(struct ieee80211_hw *dev) for (i = 0; i < ARRAY_SIZE(priv->rx_buf_mgmt); i++) { desc = &ring_control->rx_mgmt[i]; if (desc->host_addr) - pci_unmap_single(priv->pdev, + dma_unmap_single(&priv->pdev->dev, le32_to_cpu(desc->host_addr), priv->common.rx_mtu + 32, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); kfree_skb(priv->rx_buf_mgmt[i]); priv->rx_buf_mgmt[i] = NULL; } @@ -400,10 +404,10 @@ static void p54p_stop(struct ieee80211_hw *dev) for (i = 0; i < ARRAY_SIZE(priv->tx_buf_data); i++) { desc = &ring_control->tx_data[i]; if (desc->host_addr) - pci_unmap_single(priv->pdev, + dma_unmap_single(&priv->pdev->dev, le32_to_cpu(desc->host_addr), le16_to_cpu(desc->len), - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); p54_free_skb(dev, priv->tx_buf_data[i]); priv->tx_buf_data[i] = NULL; @@ -412,10 +416,10 @@ static void p54p_stop(struct ieee80211_hw *dev) for (i = 0; i < ARRAY_SIZE(priv->tx_buf_mgmt); i++) { desc = &ring_control->tx_mgmt[i]; if (desc->host_addr) - pci_unmap_single(priv->pdev, + dma_unmap_single(&priv->pdev->dev, le32_to_cpu(desc->host_addr), le16_to_cpu(desc->len), - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); p54_free_skb(dev, priv->tx_buf_mgmt[i]); priv->tx_buf_mgmt[i] = NULL; @@ -568,9 +572,9 @@ static int p54p_probe(struct pci_dev *pdev, goto err_disable_dev; } - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (err) { dev_err(&pdev->dev, "No suitable DMA available\n"); goto err_free_reg; @@ -603,8 +607,9 @@ static int p54p_probe(struct pci_dev *pdev, goto err_free_dev; } - priv->ring_control = pci_alloc_consistent(pdev, sizeof(*priv->ring_control), - &priv->ring_control_dma); + priv->ring_control = dma_alloc_coherent(&pdev->dev, + sizeof(*priv->ring_control), + &priv->ring_control_dma, GFP_KERNEL); if (!priv->ring_control) { dev_err(&pdev->dev, "Cannot allocate rings\n"); err = -ENOMEM; @@ -623,8 +628,8 @@ static int p54p_probe(struct pci_dev *pdev, if (!err) return 0; - pci_free_consistent(pdev, sizeof(*priv->ring_control), - priv->ring_control, priv->ring_control_dma); + dma_free_coherent(&pdev->dev, sizeof(*priv->ring_control), + priv->ring_control, priv->ring_control_dma); err_iounmap: iounmap(priv->map); @@ -653,8 +658,8 @@ static void p54p_remove(struct pci_dev *pdev) wait_for_completion(&priv->fw_loaded); p54_unregister_common(dev); release_firmware(priv->firmware); - pci_free_consistent(pdev, sizeof(*priv->ring_control), - priv->ring_control, priv->ring_control_dma); + dma_free_coherent(&pdev->dev, sizeof(*priv->ring_control), + priv->ring_control, priv->ring_control_dma); iounmap(priv->map); pci_release_regions(pdev); pci_disable_device(pdev); -- cgit v1.2.3 From 87b589a19901552a6d4b9976c17530d73e3c2dcf Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Sun, 19 Jul 2020 14:12:24 +0200 Subject: prism54: Replace HTTP links with HTTPS ones Rationale: Reduces attack surface on kernel devs opening the links for MITM as HTTPS traffic is much harder to manipulate. Deterministic algorithm: For each file: If not .svg: For each line: If doesn't contain `\bxmlns\b`: For each link, `\bhttp://[^# \t\r\n]*(?:\w|/)`: If neither `\bgnu\.org/license`, nor `\bmozilla\.org/MPL\b`: If both the HTTP and HTTPS versions return 200 OK and serve the same content: Replace HTTP with HTTPS. Signed-off-by: Alexander A. Klimov Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200719121224.58581-1-grandmaster@al2klimov.de --- drivers/net/wireless/intersil/prism54/isl_oid.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intersil/prism54/isl_oid.h b/drivers/net/wireless/intersil/prism54/isl_oid.h index 1afc2ccf94ca..b889bb73a485 100644 --- a/drivers/net/wireless/intersil/prism54/isl_oid.h +++ b/drivers/net/wireless/intersil/prism54/isl_oid.h @@ -143,7 +143,7 @@ enum dot11_priv_t { * together with a CSMA contention. Without this all frames are * sent with a CSMA contention. * Bibliography: - * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Papers/Packet.Frame.Grouping.html + * https://www.hpl.hp.com/personal/Jean_Tourrilhes/Papers/Packet.Frame.Grouping.html */ enum dot11_maxframeburst_t { /* Values for DOT11_OID_MAXFRAMEBURST */ -- cgit v1.2.3 From 81cf72b74671ab945bed00ef8da78078c04998ce Mon Sep 17 00:00:00 2001 From: Vaibhav Gupta Date: Tue, 21 Jul 2020 18:25:15 +0530 Subject: prism54: islpci_hotplug: use generic power management Drivers using legacy power management .suspen()/.resume() callbacks have to manage PCI states and device's PM states themselves. They also need to take care of standard configuration registers. Switch to generic power management framework using a single "struct dev_pm_ops" variable to take the unnecessary load from the driver. This also avoids the need for the driver to directly call most of the PCI helper functions and device power state control functions as through the generic framework, PCI Core takes care of the necessary operations, and drivers are required to do only device-specific jobs. Signed-off-by: Vaibhav Gupta Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200721125514.145607-1-vaibhavgupta40@gmail.com --- .../net/wireless/intersil/prism54/islpci_hotplug.c | 34 +++++++--------------- 1 file changed, 11 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intersil/prism54/islpci_hotplug.c b/drivers/net/wireless/intersil/prism54/islpci_hotplug.c index 20291c0d962d..e8369befe100 100644 --- a/drivers/net/wireless/intersil/prism54/islpci_hotplug.c +++ b/drivers/net/wireless/intersil/prism54/islpci_hotplug.c @@ -63,16 +63,17 @@ MODULE_DEVICE_TABLE(pci, prism54_id_tbl); static int prism54_probe(struct pci_dev *, const struct pci_device_id *); static void prism54_remove(struct pci_dev *); -static int prism54_suspend(struct pci_dev *, pm_message_t state); -static int prism54_resume(struct pci_dev *); +static int __maybe_unused prism54_suspend(struct device *); +static int __maybe_unused prism54_resume(struct device *); + +static SIMPLE_DEV_PM_OPS(prism54_pm_ops, prism54_suspend, prism54_resume); static struct pci_driver prism54_driver = { .name = DRV_NAME, .id_table = prism54_id_tbl, .probe = prism54_probe, .remove = prism54_remove, - .suspend = prism54_suspend, - .resume = prism54_resume, + .driver.pm = &prism54_pm_ops, }; /****************************************************************************** @@ -243,16 +244,13 @@ prism54_remove(struct pci_dev *pdev) pci_disable_device(pdev); } -static int -prism54_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused +prism54_suspend(struct device *dev) { - struct net_device *ndev = pci_get_drvdata(pdev); + struct net_device *ndev = dev_get_drvdata(dev); islpci_private *priv = ndev ? netdev_priv(ndev) : NULL; BUG_ON(!priv); - - pci_save_state(pdev); - /* tell the device not to trigger interrupts for now... */ isl38xx_disable_interrupts(priv->device_base); @@ -266,26 +264,16 @@ prism54_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } -static int -prism54_resume(struct pci_dev *pdev) +static int __maybe_unused +prism54_resume(struct device *dev) { - struct net_device *ndev = pci_get_drvdata(pdev); + struct net_device *ndev = dev_get_drvdata(dev); islpci_private *priv = ndev ? netdev_priv(ndev) : NULL; - int err; BUG_ON(!priv); printk(KERN_NOTICE "%s: got resume request\n", ndev->name); - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR "%s: pci_enable_device failed on resume\n", - ndev->name); - return err; - } - - pci_restore_state(pdev); - /* alright let's go into the PREBOOT state */ islpci_reset(priv, 1); -- cgit v1.2.3 From 84d47961a02c4568774b0a4e4b1373377786691c Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 22 Jul 2020 12:45:34 +0200 Subject: prism54: switch from 'pci_' to 'dma_' API The wrappers in include/linux/pci-dma-compat.h should go away. The patch has been generated with the coccinelle script below and has been hand modified to replace GFP_ with a correct flag. It has been compile tested. When memory is allocated in 'islpci_alloc_memory()' (islpci_dev.c), GFP_KERNEL can be used because it is only called from a probe function and no spin_lock is taken in the between. The call chain is: prism54_probe (probe function, in 'islpci_hotplug.c') --> islpci_setup (in 'islpci_dev.c') --> islpci_alloc_memory (in 'islpci_dev.c') @@ @@ - PCI_DMA_BIDIRECTIONAL + DMA_BIDIRECTIONAL @@ @@ - PCI_DMA_TODEVICE + DMA_TO_DEVICE @@ @@ - PCI_DMA_FROMDEVICE + DMA_FROM_DEVICE @@ @@ - PCI_DMA_NONE + DMA_NONE @@ expression e1, e2, e3; @@ - pci_alloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3; @@ - pci_zalloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3, e4; @@ - pci_free_consistent(e1, e2, e3, e4) + dma_free_coherent(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_single(e1, e2, e3, e4) + dma_map_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_single(e1, e2, e3, e4) + dma_unmap_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4, e5; @@ - pci_map_page(e1, e2, e3, e4, e5) + dma_map_page(&e1->dev, e2, e3, e4, e5) @@ expression e1, e2, e3, e4; @@ - pci_unmap_page(e1, e2, e3, e4) + dma_unmap_page(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_sg(e1, e2, e3, e4) + dma_map_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_sg(e1, e2, e3, e4) + dma_unmap_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_cpu(e1, e2, e3, e4) + dma_sync_single_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_device(e1, e2, e3, e4) + dma_sync_single_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_cpu(e1, e2, e3, e4) + dma_sync_sg_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_device(e1, e2, e3, e4) + dma_sync_sg_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2; @@ - pci_dma_mapping_error(e1, e2) + dma_mapping_error(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_dma_mask(e1, e2) + dma_set_mask(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_consistent_dma_mask(e1, e2) + dma_set_coherent_mask(&e1->dev, e2) Signed-off-by: Christophe JAILLET Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200722104534.30760-1-christophe.jaillet@wanadoo.fr --- drivers/net/wireless/intersil/prism54/islpci_dev.c | 30 ++++++++++------------ drivers/net/wireless/intersil/prism54/islpci_eth.c | 24 ++++++++--------- .../net/wireless/intersil/prism54/islpci_hotplug.c | 2 +- drivers/net/wireless/intersil/prism54/islpci_mgt.c | 21 +++++++-------- 4 files changed, 36 insertions(+), 41 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intersil/prism54/islpci_dev.c b/drivers/net/wireless/intersil/prism54/islpci_dev.c index a9bae69222dc..efd64e555bb5 100644 --- a/drivers/net/wireless/intersil/prism54/islpci_dev.c +++ b/drivers/net/wireless/intersil/prism54/islpci_dev.c @@ -636,10 +636,10 @@ islpci_alloc_memory(islpci_private *priv) */ /* perform the allocation */ - priv->driver_mem_address = pci_alloc_consistent(priv->pdev, - HOST_MEM_BLOCK, - &priv-> - device_host_address); + priv->driver_mem_address = dma_alloc_coherent(&priv->pdev->dev, + HOST_MEM_BLOCK, + &priv->device_host_address, + GFP_KERNEL); if (!priv->driver_mem_address) { /* error allocating the block of PCI memory */ @@ -692,11 +692,9 @@ islpci_alloc_memory(islpci_private *priv) /* map the allocated skb data area to pci */ priv->pci_map_rx_address[counter] = - pci_map_single(priv->pdev, (void *) skb->data, - MAX_FRAGMENT_SIZE_RX + 2, - PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(priv->pdev, - priv->pci_map_rx_address[counter])) { + dma_map_single(&priv->pdev->dev, (void *)skb->data, + MAX_FRAGMENT_SIZE_RX + 2, DMA_FROM_DEVICE); + if (dma_mapping_error(&priv->pdev->dev, priv->pci_map_rx_address[counter])) { priv->pci_map_rx_address[counter] = 0; /* error mapping the buffer to device accessible memory address */ @@ -727,9 +725,9 @@ islpci_free_memory(islpci_private *priv) /* free consistent DMA area... */ if (priv->driver_mem_address) - pci_free_consistent(priv->pdev, HOST_MEM_BLOCK, - priv->driver_mem_address, - priv->device_host_address); + dma_free_coherent(&priv->pdev->dev, HOST_MEM_BLOCK, + priv->driver_mem_address, + priv->device_host_address); /* clear some dangling pointers */ priv->driver_mem_address = NULL; @@ -741,8 +739,8 @@ islpci_free_memory(islpci_private *priv) for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) { struct islpci_membuf *buf = &priv->mgmt_rx[counter]; if (buf->pci_addr) - pci_unmap_single(priv->pdev, buf->pci_addr, - buf->size, PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pdev->dev, buf->pci_addr, + buf->size, DMA_FROM_DEVICE); buf->pci_addr = 0; kfree(buf->mem); buf->size = 0; @@ -752,10 +750,10 @@ islpci_free_memory(islpci_private *priv) /* clean up data rx buffers */ for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { if (priv->pci_map_rx_address[counter]) - pci_unmap_single(priv->pdev, + dma_unmap_single(&priv->pdev->dev, priv->pci_map_rx_address[counter], MAX_FRAGMENT_SIZE_RX + 2, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); priv->pci_map_rx_address[counter] = 0; if (priv->data_low_rx[counter]) diff --git a/drivers/net/wireless/intersil/prism54/islpci_eth.c b/drivers/net/wireless/intersil/prism54/islpci_eth.c index 8d680250a281..74dd65716afd 100644 --- a/drivers/net/wireless/intersil/prism54/islpci_eth.c +++ b/drivers/net/wireless/intersil/prism54/islpci_eth.c @@ -50,9 +50,9 @@ islpci_eth_cleanup_transmit(islpci_private *priv, skb, skb->data, skb->len, skb->truesize); #endif - pci_unmap_single(priv->pdev, + dma_unmap_single(&priv->pdev->dev, priv->pci_map_tx_address[index], - skb->len, PCI_DMA_TODEVICE); + skb->len, DMA_TO_DEVICE); dev_kfree_skb_irq(skb); skb = NULL; } @@ -176,10 +176,9 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) #endif /* map the skb buffer to pci memory for DMA operation */ - pci_map_address = pci_map_single(priv->pdev, - (void *) skb->data, skb->len, - PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(priv->pdev, pci_map_address)) { + pci_map_address = dma_map_single(&priv->pdev->dev, (void *)skb->data, + skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(&priv->pdev->dev, pci_map_address)) { printk(KERN_WARNING "%s: cannot map buffer to PCI\n", ndev->name); goto drop_free; @@ -323,9 +322,8 @@ islpci_eth_receive(islpci_private *priv) #endif /* delete the streaming DMA mapping before processing the skb */ - pci_unmap_single(priv->pdev, - priv->pci_map_rx_address[index], - MAX_FRAGMENT_SIZE_RX + 2, PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pdev->dev, priv->pci_map_rx_address[index], + MAX_FRAGMENT_SIZE_RX + 2, DMA_FROM_DEVICE); /* update the skb structure and align the buffer */ skb_put(skb, size); @@ -431,11 +429,9 @@ islpci_eth_receive(islpci_private *priv) /* set the streaming DMA mapping for proper PCI bus operation */ priv->pci_map_rx_address[index] = - pci_map_single(priv->pdev, (void *) skb->data, - MAX_FRAGMENT_SIZE_RX + 2, - PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(priv->pdev, - priv->pci_map_rx_address[index])) { + dma_map_single(&priv->pdev->dev, (void *)skb->data, + MAX_FRAGMENT_SIZE_RX + 2, DMA_FROM_DEVICE); + if (dma_mapping_error(&priv->pdev->dev, priv->pci_map_rx_address[index])) { /* error mapping the buffer to device accessible memory address */ DEBUG(SHOW_ERROR_MESSAGES, "Error mapping DMA address\n"); diff --git a/drivers/net/wireless/intersil/prism54/islpci_hotplug.c b/drivers/net/wireless/intersil/prism54/islpci_hotplug.c index e8369befe100..f30a79a0b9c7 100644 --- a/drivers/net/wireless/intersil/prism54/islpci_hotplug.c +++ b/drivers/net/wireless/intersil/prism54/islpci_hotplug.c @@ -107,7 +107,7 @@ prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) } /* enable PCI DMA */ - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { printk(KERN_ERR "%s: 32-bit PCI DMA not supported", DRV_NAME); goto do_pci_disable_device; } diff --git a/drivers/net/wireless/intersil/prism54/islpci_mgt.c b/drivers/net/wireless/intersil/prism54/islpci_mgt.c index e336eb106429..0c7fb76c7d1c 100644 --- a/drivers/net/wireless/intersil/prism54/islpci_mgt.c +++ b/drivers/net/wireless/intersil/prism54/islpci_mgt.c @@ -115,10 +115,11 @@ islpci_mgmt_rx_fill(struct net_device *ndev) buf->size = MGMT_FRAME_SIZE; } if (buf->pci_addr == 0) { - buf->pci_addr = pci_map_single(priv->pdev, buf->mem, + buf->pci_addr = dma_map_single(&priv->pdev->dev, + buf->mem, MGMT_FRAME_SIZE, - PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(priv->pdev, buf->pci_addr)) { + DMA_FROM_DEVICE); + if (dma_mapping_error(&priv->pdev->dev, buf->pci_addr)) { printk(KERN_WARNING "Failed to make memory DMA'able.\n"); return -ENOMEM; @@ -203,9 +204,9 @@ islpci_mgt_transmit(struct net_device *ndev, int operation, unsigned long oid, #endif err = -ENOMEM; - buf.pci_addr = pci_map_single(priv->pdev, buf.mem, frag_len, - PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(priv->pdev, buf.pci_addr)) { + buf.pci_addr = dma_map_single(&priv->pdev->dev, buf.mem, frag_len, + DMA_TO_DEVICE); + if (dma_mapping_error(&priv->pdev->dev, buf.pci_addr)) { printk(KERN_WARNING "%s: cannot map PCI memory for mgmt\n", ndev->name); goto error_free; @@ -302,8 +303,8 @@ islpci_mgt_receive(struct net_device *ndev) } /* Ensure the results of device DMA are visible to the CPU. */ - pci_dma_sync_single_for_cpu(priv->pdev, buf->pci_addr, - buf->size, PCI_DMA_FROMDEVICE); + dma_sync_single_for_cpu(&priv->pdev->dev, buf->pci_addr, + buf->size, DMA_FROM_DEVICE); /* Perform endianess conversion for PIMFOR header in-place. */ header = pimfor_decode_header(buf->mem, frag_len); @@ -414,8 +415,8 @@ islpci_mgt_cleanup_transmit(struct net_device *ndev) for (; priv->index_mgmt_tx < curr_frag; priv->index_mgmt_tx++) { int index = priv->index_mgmt_tx % ISL38XX_CB_MGMT_QSIZE; struct islpci_membuf *buf = &priv->mgmt_tx[index]; - pci_unmap_single(priv->pdev, buf->pci_addr, buf->size, - PCI_DMA_TODEVICE); + dma_unmap_single(&priv->pdev->dev, buf->pci_addr, buf->size, + DMA_TO_DEVICE); buf->pci_addr = 0; kfree(buf->mem); buf->mem = NULL; -- cgit v1.2.3 From ae44fa993e8e6c1a1d22e5ca03d9eadd53b2745b Mon Sep 17 00:00:00 2001 From: Tsang-Shian Lin Date: Fri, 17 Jul 2020 14:49:31 +0800 Subject: rtw88: fix LDPC field for RA info Convert the type of LDPC field to boolen because LDPC field of RA info H2C command to firmware is only one bit. Fixes: e3037485c68e ("rtw88: new Realtek 802.11ac driver") Signed-off-by: Tsang-Shian Lin Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200717064937.27966-2-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 6478fd7a78f6..13e79482f6d5 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -456,7 +456,7 @@ void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si) SET_RA_INFO_INIT_RA_LVL(h2c_pkt, si->init_ra_lv); SET_RA_INFO_SGI_EN(h2c_pkt, si->sgi_enable); SET_RA_INFO_BW_MODE(h2c_pkt, si->bw_mode); - SET_RA_INFO_LDPC(h2c_pkt, si->ldpc_en); + SET_RA_INFO_LDPC(h2c_pkt, !!si->ldpc_en); SET_RA_INFO_NO_UPDATE(h2c_pkt, no_update); SET_RA_INFO_VHT_EN(h2c_pkt, si->vht_enable); SET_RA_INFO_DIS_PT(h2c_pkt, disable_pt); -- cgit v1.2.3 From 4dd86b901d1373ef8446ecb50a7ca009f3475211 Mon Sep 17 00:00:00 2001 From: Tsang-Shian Lin Date: Fri, 17 Jul 2020 14:49:32 +0800 Subject: rtw88: fix short GI capability based on current bandwidth Fix the transmission is not sent with short GI under some conditions even if the receiver supports short GI. If VHT capability IE exists in the beacon, the original code uses the short GI for 80M field as driver's short GI setting for transmission, even the current bandwidth is not 80MHz. Short GI supported fields for 20M/40M are informed in HT capability information element, and short GI supported field for 80M is informed in VHT capability information element. These three fields may be set to different values. Driver needs to record each short GI support field for each bandwidth, and send correct info depends on current bandwidth to the WiFi firmware. Fixes: e3037485c68e ("rtw88: new Realtek 802.11ac driver") Signed-off-by: Tsang-Shian Lin Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200717064937.27966-3-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/main.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 7304e8bc5e31..54044abf30d7 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -722,8 +722,6 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si) stbc_en = VHT_STBC_EN; if (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC) ldpc_en = VHT_LDPC_EN; - if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80) - is_support_sgi = true; } else if (sta->ht_cap.ht_supported) { ra_mask |= (sta->ht_cap.mcs.rx_mask[1] << 20) | (sta->ht_cap.mcs.rx_mask[0] << 12); @@ -731,9 +729,6 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si) stbc_en = HT_STBC_EN; if (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING) ldpc_en = HT_LDPC_EN; - if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20 || - sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) - is_support_sgi = true; } if (efuse->hw_cap.nss == 1) @@ -775,12 +770,18 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si) switch (sta->bandwidth) { case IEEE80211_STA_RX_BW_80: bw_mode = RTW_CHANNEL_WIDTH_80; + is_support_sgi = sta->vht_cap.vht_supported && + (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80); break; case IEEE80211_STA_RX_BW_40: bw_mode = RTW_CHANNEL_WIDTH_40; + is_support_sgi = sta->ht_cap.ht_supported && + (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40); break; default: bw_mode = RTW_CHANNEL_WIDTH_20; + is_support_sgi = sta->ht_cap.ht_supported && + (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20); break; } -- cgit v1.2.3 From d8e030c74e8394a9a452b34e3a8d95d9236b45c3 Mon Sep 17 00:00:00 2001 From: Tzu-En Huang Date: Fri, 17 Jul 2020 14:49:33 +0800 Subject: rtw88: update tx descriptor of mgmt and reserved page packets Previous settings for TX descriptors of and reserved page packets are insufficient. For the sequence number of packets downloaded to reserved page, it should be filled by hardware. And for ps-poll packets in reserved page, to prevent AID being changed by hardware, NAVUSEHDR should be set. Additionally, the rate should be adjusted based on the current band for mgmt and reserved page packets. Signed-off-by: Tzu-En Huang Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200717064937.27966-4-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/fw.c | 10 +-- drivers/net/wireless/realtek/rtw88/main.h | 2 + drivers/net/wireless/realtek/rtw88/tx.c | 104 +++++++++++++++++++++--------- drivers/net/wireless/realtek/rtw88/tx.h | 13 +++- 4 files changed, 90 insertions(+), 39 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 13e79482f6d5..c922b4bb8d72 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -915,14 +915,14 @@ static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw, return skb_new; } -static void rtw_fill_rsvd_page_desc(struct rtw_dev *rtwdev, struct sk_buff *skb) +static void rtw_fill_rsvd_page_desc(struct rtw_dev *rtwdev, struct sk_buff *skb, + enum rtw_rsvd_packet_type type) { - struct rtw_tx_pkt_info pkt_info; + struct rtw_tx_pkt_info pkt_info = {0}; struct rtw_chip_info *chip = rtwdev->chip; u8 *pkt_desc; - memset(&pkt_info, 0, sizeof(pkt_info)); - rtw_rsvd_page_pkt_info_update(rtwdev, &pkt_info, skb); + rtw_tx_rsvd_page_pkt_info_update(rtwdev, &pkt_info, skb, type); pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz); memset(pkt_desc, 0, chip->tx_pkt_desc_sz); rtw_tx_fill_tx_desc(&pkt_info, skb); @@ -1261,7 +1261,7 @@ static u8 *rtw_build_rsvd_page(struct rtw_dev *rtwdev, u32 *size) * And iter->len will be added with size of tx_desc_sz. */ if (rsvd_pkt->add_txdesc) - rtw_fill_rsvd_page_desc(rtwdev, iter); + rtw_fill_rsvd_page_desc(rtwdev, iter, rsvd_pkt->type); rsvd_pkt->skb = iter; rsvd_pkt->page = total_page; diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 45ebc5a70b1e..276b5d381467 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -592,6 +592,8 @@ struct rtw_tx_pkt_info { bool dis_qselseq; bool en_hwseq; u8 hw_ssn_sel; + bool nav_use_hdr; + bool bt_null; }; struct rtw_rx_pkt_stat { diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index 79c42118825f..7fcc992b01a8 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -61,6 +61,8 @@ void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb) SET_TX_DESC_DISQSELSEQ(txdesc, pkt_info->dis_qselseq); SET_TX_DESC_EN_HWSEQ(txdesc, pkt_info->en_hwseq); SET_TX_DESC_HW_SSN_SEL(txdesc, pkt_info->hw_ssn_sel); + SET_TX_DESC_NAVUSEHDR(txdesc, pkt_info->nav_use_hdr); + SET_TX_DESC_BT_NULL(txdesc, pkt_info->bt_null); } EXPORT_SYMBOL(rtw_tx_fill_tx_desc); @@ -227,17 +229,58 @@ void rtw_tx_report_handle(struct rtw_dev *rtwdev, struct sk_buff *skb, int src) spin_unlock_irqrestore(&tx_report->q_lock, flags); } -static void rtw_tx_mgmt_pkt_info_update(struct rtw_dev *rtwdev, +static void rtw_tx_pkt_info_update_rate(struct rtw_dev *rtwdev, struct rtw_tx_pkt_info *pkt_info, - struct ieee80211_sta *sta, struct sk_buff *skb) { + if (rtwdev->hal.current_band_type == RTW_BAND_2G) { + pkt_info->rate_id = RTW_RATEID_B_20M; + pkt_info->rate = DESC_RATE1M; + } else { + pkt_info->rate_id = RTW_RATEID_G; + pkt_info->rate = DESC_RATE6M; + } pkt_info->use_rate = true; - pkt_info->rate_id = 6; pkt_info->dis_rate_fallback = true; +} + +static void rtw_tx_pkt_info_update_sec(struct rtw_dev *rtwdev, + struct rtw_tx_pkt_info *pkt_info, + struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + u8 sec_type = 0; + + if (info && info->control.hw_key) { + struct ieee80211_key_conf *key = info->control.hw_key; + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + case WLAN_CIPHER_SUITE_TKIP: + sec_type = 0x01; + break; + case WLAN_CIPHER_SUITE_CCMP: + sec_type = 0x03; + break; + default: + break; + } + } + + pkt_info->sec_type = sec_type; +} + +static void rtw_tx_mgmt_pkt_info_update(struct rtw_dev *rtwdev, + struct rtw_tx_pkt_info *pkt_info, + struct ieee80211_sta *sta, + struct sk_buff *skb) +{ + rtw_tx_pkt_info_update_rate(rtwdev, pkt_info, skb); pkt_info->dis_qselseq = true; pkt_info->en_hwseq = true; pkt_info->hw_ssn_sel = 0; + /* TODO: need to change hw port and hw ssn sel for multiple vifs */ } static void rtw_tx_data_pkt_info_update(struct rtw_dev *rtwdev, @@ -312,7 +355,6 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, struct rtw_sta_info *si; struct ieee80211_vif *vif = NULL; __le16 fc = hdr->frame_control; - u8 sec_type = 0; bool bmc; if (sta) { @@ -325,23 +367,6 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, else if (ieee80211_is_data(fc)) rtw_tx_data_pkt_info_update(rtwdev, pkt_info, sta, skb); - if (info->control.hw_key) { - struct ieee80211_key_conf *key = info->control.hw_key; - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - case WLAN_CIPHER_SUITE_TKIP: - sec_type = 0x01; - break; - case WLAN_CIPHER_SUITE_CCMP: - sec_type = 0x03; - break; - default: - break; - } - } - bmc = is_broadcast_ether_addr(hdr->addr1) || is_multicast_ether_addr(hdr->addr1); @@ -349,7 +374,7 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, rtw_tx_report_enable(rtwdev, pkt_info); pkt_info->bmc = bmc; - pkt_info->sec_type = sec_type; + rtw_tx_pkt_info_update_sec(rtwdev, pkt_info, skb); pkt_info->tx_pkt_size = skb->len; pkt_info->offset = chip->tx_pkt_desc_sz; pkt_info->qsel = skb->priority; @@ -359,24 +384,42 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, rtw_tx_stats(rtwdev, vif, skb); } -void rtw_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev, - struct rtw_tx_pkt_info *pkt_info, - struct sk_buff *skb) +void rtw_tx_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev, + struct rtw_tx_pkt_info *pkt_info, + struct sk_buff *skb, + enum rtw_rsvd_packet_type type) { struct rtw_chip_info *chip = rtwdev->chip; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; bool bmc; + /* A beacon or dummy reserved page packet indicates that it is the first + * reserved page, and the qsel of it will be set in each hci. + */ + if (type != RSVD_BEACON && type != RSVD_DUMMY) + pkt_info->qsel = TX_DESC_QSEL_MGMT; + + rtw_tx_pkt_info_update_rate(rtwdev, pkt_info, skb); + bmc = is_broadcast_ether_addr(hdr->addr1) || is_multicast_ether_addr(hdr->addr1); - pkt_info->use_rate = true; - pkt_info->rate_id = 6; - pkt_info->dis_rate_fallback = true; pkt_info->bmc = bmc; pkt_info->tx_pkt_size = skb->len; pkt_info->offset = chip->tx_pkt_desc_sz; - pkt_info->qsel = TX_DESC_QSEL_MGMT; pkt_info->ls = true; + if (type == RSVD_PS_POLL) { + pkt_info->nav_use_hdr = true; + } else { + pkt_info->dis_qselseq = true; + pkt_info->en_hwseq = true; + pkt_info->hw_ssn_sel = 0; + } + if (type == RSVD_QOS_NULL) + pkt_info->bt_null = true; + + rtw_tx_pkt_info_update_sec(rtwdev, pkt_info, skb); + + /* TODO: need to change hw port and hw ssn sel for multiple vifs */ } struct sk_buff * @@ -399,8 +442,7 @@ rtw_tx_write_data_rsvd_page_get(struct rtw_dev *rtwdev, skb_reserve(skb, tx_pkt_desc_sz); skb_put_data(skb, buf, size); - pkt_info->tx_pkt_size = size; - pkt_info->offset = tx_pkt_desc_sz; + rtw_tx_rsvd_page_pkt_info_update(rtwdev, pkt_info, skb, RSVD_BEACON); return skb; } diff --git a/drivers/net/wireless/realtek/rtw88/tx.h b/drivers/net/wireless/realtek/rtw88/tx.h index 72dfd4059f03..cfe84eef5923 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.h +++ b/drivers/net/wireless/realtek/rtw88/tx.h @@ -59,6 +59,10 @@ le32p_replace_bits((__le32 *)(txdesc) + 0x08, value, BIT(15)) #define SET_TX_DESC_HW_SSN_SEL(txdesc, value) \ le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, GENMASK(7, 6)) +#define SET_TX_DESC_NAVUSEHDR(txdesc, value) \ + le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, BIT(15)) +#define SET_TX_DESC_BT_NULL(txdesc, value) \ + le32p_replace_bits((__le32 *)(txdesc) + 0x02, value, BIT(23)) enum rtw_tx_desc_queue_select { TX_DESC_QSEL_TID0 = 0, @@ -83,6 +87,8 @@ enum rtw_tx_desc_queue_select { TX_DESC_QSEL_H2C = 19, }; +enum rtw_rsvd_packet_type; + void rtw_tx(struct rtw_dev *rtwdev, struct ieee80211_tx_control *control, struct sk_buff *skb); @@ -96,9 +102,10 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb); void rtw_tx_report_enqueue(struct rtw_dev *rtwdev, struct sk_buff *skb, u8 sn); void rtw_tx_report_handle(struct rtw_dev *rtwdev, struct sk_buff *skb, int src); -void rtw_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev, - struct rtw_tx_pkt_info *pkt_info, - struct sk_buff *skb); +void rtw_tx_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev, + struct rtw_tx_pkt_info *pkt_info, + struct sk_buff *skb, + enum rtw_rsvd_packet_type type); struct sk_buff * rtw_tx_write_data_rsvd_page_get(struct rtw_dev *rtwdev, struct rtw_tx_pkt_info *pkt_info, -- cgit v1.2.3 From 3f194bd4ca1cd9b8eef34d37d562279dbeb80319 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Fri, 17 Jul 2020 14:49:34 +0800 Subject: rtw88: coex: only skip coex triggered by BT info The coex mechanism used to skip upon the freeze flag is raised. That will cause the coex mechanism being skipped unexpectedly. Coex only wanted to keep the TDMA table from being changed by BT side. So, check the freeze and reason, if the coex reason is coming from BT info, skip it, to make sure the coex triggered by Wifi itself can work. This is required for the AP mode, while the control flow is different with STA mode. When starting an AP mode, the AP mode needs to start working immedaitely after leaving IPS, and the freeze flag could be raised. If the coex info is skipped, then the AP mode will not set the antenna owner, leads to TX stuck. Fixes: 4136214f7c46 ("rtw88: add BT co-existence support") Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200717064937.27966-5-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/coex.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c index 3abae32341c4..aa08fd7d9fcd 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.c +++ b/drivers/net/wireless/realtek/rtw88/coex.c @@ -1962,7 +1962,8 @@ static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason) if (coex_stat->wl_under_ips) return; - if (coex->freeze && !coex_stat->bt_setup_link) + if (coex->freeze && coex_dm->reason == COEX_RSN_BTINFO && + !coex_stat->bt_setup_link) return; coex_stat->cnt_wl[COEX_CNT_WL_COEXRUN]++; -- cgit v1.2.3 From 40b788d15832f5947b6d4e4ff3afea9af267bac6 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Fri, 17 Jul 2020 14:49:35 +0800 Subject: rtw88: add ieee80211_ops::change_interface Sometimes mac80211 will just ask driver to change the interface instead of to remove and then add a new one. And for driver, to change the interface is just simply to remove and add a new one but change the type of it. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200717064937.27966-6-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/mac80211.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index c412bc54efde..bb82b044ff82 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -231,6 +231,23 @@ static void rtw_ops_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&rtwdev->mutex); } +static int rtw_ops_change_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum nl80211_iftype type, bool p2p) +{ + struct rtw_dev *rtwdev = hw->priv; + + rtw_info(rtwdev, "change vif %pM (%d)->(%d), p2p (%d)->(%d)\n", + vif->addr, vif->type, type, vif->p2p, p2p); + + rtw_ops_remove_interface(hw, vif); + + vif->type = type; + vif->p2p = p2p; + + return rtw_ops_add_interface(hw, vif); +} + static void rtw_ops_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, @@ -827,6 +844,7 @@ const struct ieee80211_ops rtw_ops = { .config = rtw_ops_config, .add_interface = rtw_ops_add_interface, .remove_interface = rtw_ops_remove_interface, + .change_interface = rtw_ops_change_interface, .configure_filter = rtw_ops_configure_filter, .bss_info_changed = rtw_ops_bss_info_changed, .conf_tx = rtw_ops_conf_tx, -- cgit v1.2.3 From 752310ed2b406831d71aeaf493b488f90c673a3c Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Fri, 17 Jul 2020 14:49:36 +0800 Subject: rtw88: allows driver to enable/disable beacon Enable/disable beacon accordingly when the BSS info changed. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200717064937.27966-7-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/mac80211.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index bb82b044ff82..6b199152abcf 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -390,6 +390,15 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BEACON) rtw_fw_download_rsvd_page(rtwdev); + if (changed & BSS_CHANGED_BEACON_ENABLED) { + if (conf->enable_beacon) + rtw_write32_set(rtwdev, REG_FWHW_TXQ_CTRL, + BIT_EN_BCNQ_DL); + else + rtw_write32_clr(rtwdev, REG_FWHW_TXQ_CTRL, + BIT_EN_BCNQ_DL); + } + if (changed & BSS_CHANGED_MU_GROUPS) rtw_chip_set_gid_table(rtwdev, vif, conf); -- cgit v1.2.3 From c376c1fc87b77ae06ed6fa18d424ab548ac3a8fc Mon Sep 17 00:00:00 2001 From: Tzu-En Huang Date: Fri, 17 Jul 2020 14:49:37 +0800 Subject: rtw88: add h2c command in debugfs It's very useful to send H2C command for debug usage. Add an entry for sending H2C command to firmware. usage example: echo 42,00,00,43,02,00,00,00 > /sys/kernel/debug/ieee80211/phyX/rtw88 Signed-off-by: Tzu-En Huang Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200717064937.27966-8-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/debug.c | 30 ++++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/fw.c | 5 +++++ drivers/net/wireless/realtek/rtw88/fw.h | 2 ++ 3 files changed, 37 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c index 09f04feb8fe1..f769c982cc91 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.c +++ b/drivers/net/wireless/realtek/rtw88/debug.c @@ -344,6 +344,31 @@ static ssize_t rtw_debugfs_set_write_reg(struct file *filp, return count; } +static ssize_t rtw_debugfs_set_h2c(struct file *filp, + const char __user *buffer, + size_t count, loff_t *loff) +{ + struct rtw_debugfs_priv *debugfs_priv = filp->private_data; + struct rtw_dev *rtwdev = debugfs_priv->rtwdev; + char tmp[32 + 1]; + u8 param[8]; + int num; + + rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 3); + + num = sscanf(tmp, "%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx", + ¶m[0], ¶m[1], ¶m[2], ¶m[3], + ¶m[4], ¶m[5], ¶m[6], ¶m[7]); + if (num != 8) { + rtw_info(rtwdev, "invalid H2C command format for debug\n"); + return -EINVAL; + } + + rtw_fw_h2c_cmd_dbg(rtwdev, param); + + return count; +} + static ssize_t rtw_debugfs_set_rf_write(struct file *filp, const char __user *buffer, size_t count, loff_t *loff) @@ -808,6 +833,10 @@ static struct rtw_debugfs_priv rtw_debug_priv_write_reg = { .cb_write = rtw_debugfs_set_write_reg, }; +static struct rtw_debugfs_priv rtw_debug_priv_h2c = { + .cb_write = rtw_debugfs_set_h2c, +}; + static struct rtw_debugfs_priv rtw_debug_priv_rf_write = { .cb_write = rtw_debugfs_set_rf_write, }; @@ -877,6 +906,7 @@ void rtw_debugfs_init(struct rtw_dev *rtwdev) rtw_debugfs_add_r(phy_info); rtw_debugfs_add_r(coex_info); rtw_debugfs_add_rw(coex_enable); + rtw_debugfs_add_w(h2c); rtw_debugfs_add_r(mac_0); rtw_debugfs_add_r(mac_1); rtw_debugfs_add_r(mac_2); diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index c922b4bb8d72..63b00bc19000 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -253,6 +253,11 @@ out: spin_unlock(&rtwdev->h2c.lock); } +void rtw_fw_h2c_cmd_dbg(struct rtw_dev *rtwdev, u8 *h2c) +{ + rtw_fw_send_h2c_command(rtwdev, h2c); +} + static void rtw_fw_send_h2c_packet(struct rtw_dev *rtwdev, u8 *h2c_pkt) { int ret; diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h index 470e1809645a..686dcd3bbda6 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.h +++ b/drivers/net/wireless/realtek/rtw88/fw.h @@ -563,4 +563,6 @@ void rtw_fw_set_nlo_info(struct rtw_dev *rtwdev, bool enable); void rtw_fw_update_pkt_probe_req(struct rtw_dev *rtwdev, struct cfg80211_ssid *ssid); void rtw_fw_channel_switch(struct rtw_dev *rtwdev, bool enable); +void rtw_fw_h2c_cmd_dbg(struct rtw_dev *rtwdev, u8 *h2c); + #endif -- cgit v1.2.3 From 9de6959f8584064de8c1d7392e3a6bb50a4a9c18 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 21 Jul 2020 21:49:01 +0800 Subject: rtw88: 8821c: make symbol 'rtw8821c_rtw_pwr_track_tbl' static The sparse tool complains as follows: drivers/net/wireless/realtek/rtw88/rtw8821c.c:1374:32: warning: symbol 'rtw8821c_rtw_pwr_track_tbl' was not declared. Should it be static? This variable is not used outside of rtw8821c.c, so this commit marks it static. Fixes: 3a4312828ce1 ("rtw88: 8821c: add power tracking") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200721134901.33968-1-weiyongjun1@huawei.com --- drivers/net/wireless/realtek/rtw88/rtw8821c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c index c41c61ee2fb6..5fef19f19ac1 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c @@ -1371,7 +1371,7 @@ static const u8 rtw8821c_pwrtrk_2g_cck_a_p[] = { 5, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9 }; -const struct rtw_pwr_track_tbl rtw8821c_rtw_pwr_track_tbl = { +static const struct rtw_pwr_track_tbl rtw8821c_rtw_pwr_track_tbl = { .pwrtrk_5gb_n[0] = rtw8821c_pwrtrk_5gb_n[0], .pwrtrk_5gb_n[1] = rtw8821c_pwrtrk_5gb_n[1], .pwrtrk_5gb_n[2] = rtw8821c_pwrtrk_5gb_n[2], -- cgit v1.2.3 From 7b080e085943eb9b2862a04b0450afe17e286a21 Mon Sep 17 00:00:00 2001 From: Ping-Cheng Chen Date: Fri, 24 Jul 2020 13:42:08 +0800 Subject: rtw88: 8821c: coex: add functions and parameters Without this patch, RTL8821CE will not have coex support, and will crash the system because of the NULL pointers for the coex functions. While RTL8822C series are WiFi + BT combo chips, it needs the co-existence mechanism for the device to work on both WiFi and BT without interfering each other. And the coex support has already been added before, most of the mechanisms are implemented. The driver should just add corresponding functions to operate on different types of chips and its coex parameters. Fixes: f745eb9ca5bf ("rtw88: 8821c: Add 8821CE to Kconfig and Makefile") Signed-off-by: Ping-Cheng Chen Signed-off-by: Tzu-En Huang Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200724054208.31115-1-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/reg.h | 1 + drivers/net/wireless/realtek/rtw88/rtw8821c.c | 403 ++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/rtw8821c.h | 26 ++ 3 files changed, 430 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h index f1275757f6b4..8f468d6b5f78 100644 --- a/drivers/net/wireless/realtek/rtw88/reg.h +++ b/drivers/net/wireless/realtek/rtw88/reg.h @@ -61,6 +61,7 @@ #define BIT_FSPI_EN BIT(19) #define BIT_EN_SIC BIT(12) #define BIT_BT_AOD_GPIO3 BIT(9) +#define BIT_PO_BT_PTA_PINS BIT(9) #define BIT_BT_PTA_EN BIT(5) #define BIT_WLRFE_4_5_EN BIT(2) diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c index 5fef19f19ac1..d8863d8a5468 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c @@ -649,6 +649,197 @@ static void rtw8821c_phy_calibration(struct rtw_dev *rtwdev) rtw8821c_do_iqk(rtwdev); } +/* for coex */ +static void rtw8821c_coex_cfg_init(struct rtw_dev *rtwdev) +{ + /* enable TBTT nterrupt */ + rtw_write8_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION); + + /* BT report packet sample rate */ + rtw_write8_mask(rtwdev, REG_BT_TDMA_TIME, SAMPLE_RATE_MASK, + SAMPLE_RATE); + + /* enable BT counter statistics */ + rtw_write8(rtwdev, REG_BT_STAT_CTRL, BT_CNT_ENABLE); + + /* enable PTA (3-wire function form BT side) */ + rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_BT_PTA_EN); + rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_PO_BT_PTA_PINS); + + /* enable PTA (tx/rx signal form WiFi side) */ + rtw_write8_set(rtwdev, REG_QUEUE_CTRL, BIT_PTA_WL_TX_EN); + /* wl tx signal to PTA not case EDCCA */ + rtw_write8_clr(rtwdev, REG_QUEUE_CTRL, BIT_PTA_EDCCA_EN); + /* GNT_BT=1 while select both */ + rtw_write16_set(rtwdev, REG_BT_COEX_V2, BIT_GNT_BT_POLARITY); + + /* beacon queue always hi-pri */ + rtw_write8_mask(rtwdev, REG_BT_COEX_TABLE_H + 3, BIT_BCN_QUEUE, + BCN_PRI_EN); +} + +static void rtw8821c_coex_cfg_ant_switch(struct rtw_dev *rtwdev, u8 ctrl_type, + u8 pos_type) +{ + struct rtw_coex *coex = &rtwdev->coex; + struct rtw_coex_dm *coex_dm = &coex->dm; + struct rtw_coex_rfe *coex_rfe = &coex->rfe; + u32 switch_status = FIELD_PREP(CTRL_TYPE_MASK, ctrl_type) | pos_type; + bool polarity_inverse; + u8 regval = 0; + + if (switch_status == coex_dm->cur_switch_status) + return; + + coex_dm->cur_switch_status = switch_status; + + if (coex_rfe->ant_switch_diversity && + ctrl_type == COEX_SWITCH_CTRL_BY_BBSW) + ctrl_type = COEX_SWITCH_CTRL_BY_ANTDIV; + + polarity_inverse = (coex_rfe->ant_switch_polarity == 1); + + switch (ctrl_type) { + default: + case COEX_SWITCH_CTRL_BY_BBSW: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + /* BB SW, DPDT use RFE_ctrl8 and RFE_ctrl9 as ctrl pin */ + rtw_write8_mask(rtwdev, REG_RFE_CTRL8, BIT_MASK_RFE_SEL89, + DPDT_CTRL_PIN); + + if (pos_type == COEX_SWITCH_TO_WLG_BT) { + if (coex_rfe->rfe_module_type != 0x4 && + coex_rfe->rfe_module_type != 0x2) + regval = 0x3; + else + regval = (!polarity_inverse ? 0x2 : 0x1); + } else if (pos_type == COEX_SWITCH_TO_WLG) { + regval = (!polarity_inverse ? 0x2 : 0x1); + } else { + regval = (!polarity_inverse ? 0x1 : 0x2); + } + + rtw_write8_mask(rtwdev, REG_RFE_CTRL8, BIT_MASK_R_RFE_SEL_15, + regval); + break; + case COEX_SWITCH_CTRL_BY_PTA: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + /* PTA, DPDT use RFE_ctrl8 and RFE_ctrl9 as ctrl pin */ + rtw_write8_mask(rtwdev, REG_RFE_CTRL8, BIT_MASK_RFE_SEL89, + PTA_CTRL_PIN); + + regval = (!polarity_inverse ? 0x2 : 0x1); + rtw_write8_mask(rtwdev, REG_RFE_CTRL8, BIT_MASK_R_RFE_SEL_15, + regval); + break; + case COEX_SWITCH_CTRL_BY_ANTDIV: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + rtw_write8_mask(rtwdev, REG_RFE_CTRL8, BIT_MASK_RFE_SEL89, + ANTDIC_CTRL_PIN); + break; + case COEX_SWITCH_CTRL_BY_MAC: + rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + + regval = (!polarity_inverse ? 0x0 : 0x1); + rtw_write8_mask(rtwdev, REG_PAD_CTRL1, BIT_SW_DPDT_SEL_DATA, + regval); + break; + case COEX_SWITCH_CTRL_BY_FW: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + break; + case COEX_SWITCH_CTRL_BY_BT: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + break; + } + + if (ctrl_type == COEX_SWITCH_CTRL_BY_BT) { + rtw_write32_clr(rtwdev, REG_CTRL_TYPE, BIT_CTRL_TYPE1); + rtw_write32_clr(rtwdev, REG_CTRL_TYPE, BIT_CTRL_TYPE2); + } else { + rtw_write32_set(rtwdev, REG_CTRL_TYPE, BIT_CTRL_TYPE1); + rtw_write32_set(rtwdev, REG_CTRL_TYPE, BIT_CTRL_TYPE2); + } +} + +static void rtw8821c_coex_cfg_gnt_fix(struct rtw_dev *rtwdev) +{} + +static void rtw8821c_coex_cfg_gnt_debug(struct rtw_dev *rtwdev) +{ + rtw_write32_clr(rtwdev, REG_PAD_CTRL1, BIT_BTGP_SPI_EN); + rtw_write32_clr(rtwdev, REG_PAD_CTRL1, BIT_BTGP_JTAG_EN); + rtw_write32_clr(rtwdev, REG_GPIO_MUXCFG, BIT_FSPI_EN); + rtw_write32_clr(rtwdev, REG_PAD_CTRL1, BIT_LED1DIS); + rtw_write32_clr(rtwdev, REG_SYS_SDIO_CTRL, BIT_SDIO_INT); + rtw_write32_clr(rtwdev, REG_SYS_SDIO_CTRL, BIT_DBG_GNT_WL_BT); +} + +static void rtw8821c_coex_cfg_rfe_type(struct rtw_dev *rtwdev) +{ + struct rtw_coex *coex = &rtwdev->coex; + struct rtw_coex_rfe *coex_rfe = &coex->rfe; + struct rtw_efuse *efuse = &rtwdev->efuse; + + coex_rfe->rfe_module_type = efuse->rfe_option; + coex_rfe->ant_switch_polarity = 0; + coex_rfe->ant_switch_exist = true; + coex_rfe->wlg_at_btg = false; + + switch (coex_rfe->rfe_module_type) { + case 0: + case 8: + case 1: + case 9: /* 1-Ant, Main, WLG */ + default: /* 2-Ant, DPDT, WLG */ + break; + case 2: + case 10: /* 1-Ant, Main, BTG */ + case 7: + case 15: /* 2-Ant, DPDT, BTG */ + coex_rfe->wlg_at_btg = true; + break; + case 3: + case 11: /* 1-Ant, Aux, WLG */ + coex_rfe->ant_switch_polarity = 1; + break; + case 4: + case 12: /* 1-Ant, Aux, BTG */ + coex_rfe->wlg_at_btg = true; + coex_rfe->ant_switch_polarity = 1; + break; + case 5: + case 13: /* 2-Ant, no switch, WLG */ + case 6: + case 14: /* 2-Ant, no antenna switch, WLG */ + coex_rfe->ant_switch_exist = false; + break; + } +} + +static void rtw8821c_coex_cfg_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr) +{ + struct rtw_coex *coex = &rtwdev->coex; + struct rtw_coex_dm *coex_dm = &coex->dm; + struct rtw_efuse *efuse = &rtwdev->efuse; + bool share_ant = efuse->share_ant; + + if (share_ant) + return; + + if (wl_pwr == coex_dm->cur_wl_pwr_lvl) + return; + + coex_dm->cur_wl_pwr_lvl = wl_pwr; +} + +static void rtw8821c_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain) +{} + static void rtw8821c_txagc_swing_offset(struct rtw_dev *rtwdev, u8 pwr_idx_offset, s8 pwr_idx_offset_lower, @@ -1293,8 +1484,166 @@ static struct rtw_chip_ops rtw8821c_ops = { .config_bfee = rtw8821c_bf_config_bfee, .set_gid_table = rtw_bf_set_gid_table, .cfg_csi_rate = rtw_bf_cfg_csi_rate, + + .coex_set_init = rtw8821c_coex_cfg_init, + .coex_set_ant_switch = rtw8821c_coex_cfg_ant_switch, + .coex_set_gnt_fix = rtw8821c_coex_cfg_gnt_fix, + .coex_set_gnt_debug = rtw8821c_coex_cfg_gnt_debug, + .coex_set_rfe_type = rtw8821c_coex_cfg_rfe_type, + .coex_set_wl_tx_power = rtw8821c_coex_cfg_wl_tx_power, + .coex_set_wl_rx_gain = rtw8821c_coex_cfg_wl_rx_gain, +}; + +/* rssi in percentage % (dbm = % - 100) */ +static const u8 wl_rssi_step_8821c[] = {101, 45, 101, 40}; +static const u8 bt_rssi_step_8821c[] = {101, 101, 101, 101}; + +/* Shared-Antenna Coex Table */ +static const struct coex_table_para table_sant_8821c[] = { + {0x55555555, 0x55555555}, /* case-0 */ + {0x55555555, 0x55555555}, + {0x66555555, 0x66555555}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0x5a5a5a5a, 0x5a5a5a5a}, + {0xfafafafa, 0xfafafafa}, /* case-5 */ + {0x6a5a5555, 0xaaaaaaaa}, + {0x6a5a56aa, 0x6a5a56aa}, + {0x6a5a5a5a, 0x6a5a5a5a}, + {0x66555555, 0x5a5a5a5a}, + {0x66555555, 0x6a5a5a5a}, /* case-10 */ + {0x66555555, 0xaaaaaaaa}, + {0x66555555, 0x6a5a5aaa}, + {0x66555555, 0x6aaa6aaa}, + {0x66555555, 0x6a5a5aaa}, + {0x66555555, 0xaaaaaaaa}, /* case-15 */ + {0xffff55ff, 0xfafafafa}, + {0xffff55ff, 0x6afa5afa}, + {0xaaffffaa, 0xfafafafa}, + {0xaa5555aa, 0x5a5a5a5a}, + {0xaa5555aa, 0x6a5a5a5a}, /* case-20 */ + {0xaa5555aa, 0xaaaaaaaa}, + {0xffffffff, 0x55555555}, + {0xffffffff, 0x5a5a5a5a}, + {0xffffffff, 0x5a5a5a5a}, + {0xffffffff, 0x5a5a5aaa}, /* case-25 */ + {0x55555555, 0x5a5a5a5a}, + {0x55555555, 0xaaaaaaaa}, + {0x66555555, 0x6a5a6a5a}, + {0x66556655, 0x66556655}, + {0x66556aaa, 0x6a5a6aaa}, /* case-30 */ + {0xffffffff, 0x5aaa5aaa}, + {0x56555555, 0x5a5a5aaa} +}; + +/* Non-Shared-Antenna Coex Table */ +static const struct coex_table_para table_nsant_8821c[] = { + {0xffffffff, 0xffffffff}, /* case-100 */ + {0xffff55ff, 0xfafafafa}, + {0x66555555, 0x66555555}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0x5a5a5a5a, 0x5a5a5a5a}, + {0xffffffff, 0xffffffff}, /* case-105 */ + {0x5afa5afa, 0x5afa5afa}, + {0x55555555, 0xfafafafa}, + {0x66555555, 0xfafafafa}, + {0x66555555, 0x5a5a5a5a}, + {0x66555555, 0x6a5a5a5a}, /* case-110 */ + {0x66555555, 0xaaaaaaaa}, + {0xffff55ff, 0xfafafafa}, + {0xffff55ff, 0x5afa5afa}, + {0xffff55ff, 0xaaaaaaaa}, + {0xffff55ff, 0xffff55ff}, /* case-115 */ + {0xaaffffaa, 0x5afa5afa}, + {0xaaffffaa, 0xaaaaaaaa}, + {0xffffffff, 0xfafafafa}, + {0xffff55ff, 0xfafafafa}, + {0xffffffff, 0xaaaaaaaa}, /* case-120 */ + {0xffff55ff, 0x5afa5afa}, + {0xffff55ff, 0x5afa5afa}, + {0x55ff55ff, 0x55ff55ff} +}; + +/* Shared-Antenna TDMA */ +static const struct coex_tdma_para tdma_sant_8821c[] = { + { {0x00, 0x00, 0x00, 0x00, 0x00} }, /* case-0 */ + { {0x61, 0x45, 0x03, 0x11, 0x11} }, /* case-1 */ + { {0x61, 0x3a, 0x03, 0x11, 0x11} }, + { {0x61, 0x35, 0x03, 0x11, 0x11} }, + { {0x61, 0x20, 0x03, 0x11, 0x11} }, + { {0x61, 0x3a, 0x03, 0x11, 0x11} }, /* case-5 */ + { {0x61, 0x45, 0x03, 0x11, 0x10} }, + { {0x61, 0x35, 0x03, 0x11, 0x10} }, + { {0x61, 0x30, 0x03, 0x11, 0x10} }, + { {0x61, 0x20, 0x03, 0x11, 0x10} }, + { {0x61, 0x10, 0x03, 0x11, 0x10} }, /* case-10 */ + { {0x61, 0x08, 0x03, 0x11, 0x15} }, + { {0x61, 0x08, 0x03, 0x10, 0x14} }, + { {0x51, 0x08, 0x03, 0x10, 0x54} }, + { {0x51, 0x08, 0x03, 0x10, 0x55} }, + { {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-15 */ + { {0x51, 0x45, 0x03, 0x10, 0x50} }, + { {0x51, 0x3a, 0x03, 0x11, 0x50} }, + { {0x51, 0x30, 0x03, 0x10, 0x50} }, + { {0x51, 0x21, 0x03, 0x10, 0x50} }, + { {0x51, 0x10, 0x03, 0x10, 0x50} }, /* case-20 */ + { {0x51, 0x4a, 0x03, 0x10, 0x50} }, + { {0x51, 0x08, 0x03, 0x30, 0x54} }, + { {0x55, 0x08, 0x03, 0x10, 0x54} }, + { {0x65, 0x10, 0x03, 0x11, 0x10} }, + { {0x51, 0x10, 0x03, 0x10, 0x51} }, /* case-25 */ + { {0x51, 0x21, 0x03, 0x10, 0x50} }, + { {0x61, 0x08, 0x03, 0x11, 0x11} } +}; + +/* Non-Shared-Antenna TDMA */ +static const struct coex_tdma_para tdma_nsant_8821c[] = { + { {0x00, 0x00, 0x00, 0x40, 0x00} }, /* case-100 */ + { {0x61, 0x45, 0x03, 0x11, 0x11} }, + { {0x61, 0x25, 0x03, 0x11, 0x11} }, + { {0x61, 0x35, 0x03, 0x11, 0x11} }, + { {0x61, 0x20, 0x03, 0x11, 0x11} }, + { {0x61, 0x10, 0x03, 0x11, 0x11} }, /* case-105 */ + { {0x61, 0x45, 0x03, 0x11, 0x10} }, + { {0x61, 0x30, 0x03, 0x11, 0x10} }, + { {0x61, 0x30, 0x03, 0x11, 0x10} }, + { {0x61, 0x20, 0x03, 0x11, 0x10} }, + { {0x61, 0x10, 0x03, 0x11, 0x10} }, /* case-110 */ + { {0x61, 0x10, 0x03, 0x11, 0x11} }, + { {0x61, 0x08, 0x03, 0x10, 0x14} }, + { {0x51, 0x08, 0x03, 0x10, 0x54} }, + { {0x51, 0x08, 0x03, 0x10, 0x55} }, + { {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-115 */ + { {0x51, 0x45, 0x03, 0x10, 0x50} }, + { {0x51, 0x3a, 0x03, 0x10, 0x50} }, + { {0x51, 0x30, 0x03, 0x10, 0x50} }, + { {0x51, 0x21, 0x03, 0x10, 0x50} }, + { {0x51, 0x21, 0x03, 0x10, 0x50} }, /* case-120 */ + { {0x51, 0x10, 0x03, 0x10, 0x50} } }; +static const struct coex_5g_afh_map afh_5g_8821c[] = { {0, 0, 0} }; + +/* wl_tx_dec_power, bt_tx_dec_power, wl_rx_gain, bt_rx_lna_constrain */ +static const struct coex_rf_para rf_para_tx_8821c[] = { + {0, 0, false, 7}, /* for normal */ + {0, 20, false, 7}, /* for WL-CPT */ + {8, 17, true, 4}, + {7, 18, true, 4}, + {6, 19, true, 4}, + {5, 20, true, 4} +}; + +static const struct coex_rf_para rf_para_rx_8821c[] = { + {0, 0, false, 7}, /* for normal */ + {0, 20, false, 7}, /* for WL-CPT */ + {3, 24, true, 5}, + {2, 26, true, 5}, + {1, 27, true, 5}, + {0, 28, true, 5} +}; + +static_assert(ARRAY_SIZE(rf_para_tx_8821c) == ARRAY_SIZE(rf_para_rx_8821c)); + static const u8 rtw8821c_pwrtrk_5gb_n[][RTW_PWR_TRK_TBL_SZ] = { {0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12}, @@ -1394,6 +1743,31 @@ static const struct rtw_pwr_track_tbl rtw8821c_rtw_pwr_track_tbl = { .pwrtrk_2g_ccka_p = rtw8821c_pwrtrk_2g_cck_a_p, }; +static const struct rtw_reg_domain coex_info_hw_regs_8821c[] = { + {0xCB0, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0xCB4, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0xCBA, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, + {0, 0, RTW_REG_DOMAIN_NL}, + {0x430, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0x434, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0x42a, MASKLWORD, RTW_REG_DOMAIN_MAC16}, + {0x426, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, + {0x45e, BIT(3), RTW_REG_DOMAIN_MAC8}, + {0x454, MASKLWORD, RTW_REG_DOMAIN_MAC16}, + {0, 0, RTW_REG_DOMAIN_NL}, + {0x4c, BIT(24) | BIT(23), RTW_REG_DOMAIN_MAC32}, + {0x64, BIT(0), RTW_REG_DOMAIN_MAC8}, + {0x4c6, BIT(4), RTW_REG_DOMAIN_MAC8}, + {0x40, BIT(5), RTW_REG_DOMAIN_MAC8}, + {0x1, RFREG_MASK, RTW_REG_DOMAIN_RF_A}, + {0, 0, RTW_REG_DOMAIN_NL}, + {0x550, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0x522, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, + {0x953, BIT(1), RTW_REG_DOMAIN_MAC8}, + {0xc50, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, + {0x60A, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, +}; + struct rtw_chip_info rtw8821c_hw_spec = { .ops = &rtw8821c_ops, .id = RTW_CHIP_TYPE_8821C, @@ -1440,6 +1814,35 @@ struct rtw_chip_info rtw8821c_hw_spec = { .iqk_threshold = 8, .bfer_su_max_num = 2, .bfer_mu_max_num = 1, + + .coex_para_ver = 0x19092746, + .bt_desired_ver = 0x46, + .scbd_support = true, + .new_scbd10_def = false, + .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF, + .bt_rssi_type = COEX_BTRSSI_RATIO, + .ant_isolation = 15, + .rssi_tolerance = 2, + .wl_rssi_step = wl_rssi_step_8821c, + .bt_rssi_step = bt_rssi_step_8821c, + .table_sant_num = ARRAY_SIZE(table_sant_8821c), + .table_sant = table_sant_8821c, + .table_nsant_num = ARRAY_SIZE(table_nsant_8821c), + .table_nsant = table_nsant_8821c, + .tdma_sant_num = ARRAY_SIZE(tdma_sant_8821c), + .tdma_sant = tdma_sant_8821c, + .tdma_nsant_num = ARRAY_SIZE(tdma_nsant_8821c), + .tdma_nsant = tdma_nsant_8821c, + .wl_rf_para_num = ARRAY_SIZE(rf_para_tx_8821c), + .wl_rf_para_tx = rf_para_tx_8821c, + .wl_rf_para_rx = rf_para_rx_8821c, + .bt_afh_span_bw20 = 0x24, + .bt_afh_span_bw40 = 0x36, + .afh_5g_num = ARRAY_SIZE(afh_5g_8821c), + .afh_5g = afh_5g_8821c, + + .coex_info_hw_regs_num = ARRAY_SIZE(coex_info_hw_regs_8821c), + .coex_info_hw_regs = coex_info_hw_regs_8821c, }; EXPORT_SYMBOL(rtw8821c_hw_spec); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.h b/drivers/net/wireless/realtek/rtw88/rtw8821c.h index 166bd0e9294e..bd01e82b6bcd 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821c.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.h @@ -160,6 +160,18 @@ _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data) le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(11, 8)) #define GET_PHY_STAT_P1_HT_RXSC(phy_stat) \ le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(15, 12)) +#define GET_PHY_STAT_P1_RXEVM_A(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(7, 0)) +#define GET_PHY_STAT_P1_RXEVM_B(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(15, 8)) +#define GET_PHY_STAT_P1_CFO_TAIL_A(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x05), GENMASK(7, 0)) +#define GET_PHY_STAT_P1_CFO_TAIL_B(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x05), GENMASK(15, 8)) +#define GET_PHY_STAT_P1_RXSNR_A(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(7, 0)) +#define GET_PHY_STAT_P1_RXSNR_B(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(15, 8)) #define REG_INIRTS_RATE_SEL 0x0480 #define REG_HTSTFWT 0x800 @@ -217,6 +229,20 @@ _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data) #define REG_CCA_CCK 0xfcc #define REG_ANTWT 0x1904 #define REG_IQKFAILMSK 0x1bf0 +#define BIT_MASK_R_RFE_SEL_15 GENMASK(31, 28) +#define BIT_SDIO_INT BIT(18) +#define SAMPLE_RATE_MASK GENMASK(5, 0) +#define SAMPLE_RATE 0x5 +#define BT_CNT_ENABLE 0x1 +#define BIT_BCN_QUEUE BIT(3) +#define BCN_PRI_EN 0x1 +#define PTA_CTRL_PIN 0x66 +#define DPDT_CTRL_PIN 0x77 +#define ANTDIC_CTRL_PIN 0x88 +#define REG_CTRL_TYPE 0x67 +#define BIT_CTRL_TYPE1 BIT(5) +#define BIT_CTRL_TYPE2 BIT(4) +#define CTRL_TYPE_MASK GENMASK(15, 8) #define RF18_BAND_MASK (BIT(16) | BIT(9) | BIT(8)) #define RF18_BAND_2G (0) -- cgit v1.2.3 From 3f4600de8c93917594a8b3c9ca713160ee4d563c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Jun 2020 18:52:10 +0200 Subject: iwlwifi: yoyo: don't print failure if debug firmware is missing Missing this firmware is not fatal, my wifi card still works. Even more, I couldn't find any documentation what it is or where to get it. So, I don't think the users should be notified if it is missing. If you browse the net, you see the message is present is in quite some logs. Better remove it. Signed-off-by: Wolfram Sang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200625165210.14904-1-wsa@kernel.org --- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 7987a288917b..f180db2936e3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -468,7 +468,7 @@ void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans) if (!iwlwifi_mod_params.enable_ini) return; - res = request_firmware(&fw, "iwl-debug-yoyo.bin", dev); + res = firmware_request_nowarn(&fw, "iwl-debug-yoyo.bin", dev); if (res) return; -- cgit v1.2.3 From 880e21490be68ef9cc8185962e9b5722a0f1fc4d Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Sat, 18 Jul 2020 00:26:29 -0500 Subject: mt7601u: add missing release on skb in mt7601u_mcu_msg_send In the implementation of mt7601u_mcu_msg_send(), skb is supposed to be consumed on all execution paths. Release skb before returning if test_bit() fails. Signed-off-by: Navid Emamdoost Acked-by: Jakub Kicinski Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200718052630.11032-1-navid.emamdoost@gmail.com --- drivers/net/wireless/mediatek/mt7601u/mcu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt7601u/mcu.c b/drivers/net/wireless/mediatek/mt7601u/mcu.c index af55ed82b96f..1b5cc271a9e1 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mcu.c +++ b/drivers/net/wireless/mediatek/mt7601u/mcu.c @@ -116,8 +116,10 @@ mt7601u_mcu_msg_send(struct mt7601u_dev *dev, struct sk_buff *skb, int sent, ret; u8 seq = 0; - if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) + if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) { + consume_skb(skb); return 0; + } mutex_lock(&dev->mcu.mutex); -- cgit v1.2.3 From c83e2a6e2fbbb7d47ea46fd7cb1f01292f2d0b6e Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Fri, 17 Jul 2020 05:11:38 +0000 Subject: wilc1000: Move wilc1000 SDIO ID's from driver source to common header file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moved macros used for Vendor/Device ID from wilc1000 driver to common header file and changed macro name for consistency with other macros. Signed-off-by: Ajay Singh Acked-by: Ulf Hansson Acked-by: Pali Rohár Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200717051134.19160-1-ajay.kathat@microchip.com --- drivers/net/wireless/microchip/wilc1000/sdio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/microchip/wilc1000/sdio.c b/drivers/net/wireless/microchip/wilc1000/sdio.c index 36eb589263bf..3ece7b0b0392 100644 --- a/drivers/net/wireless/microchip/wilc1000/sdio.c +++ b/drivers/net/wireless/microchip/wilc1000/sdio.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -15,11 +16,8 @@ #define SDIO_MODALIAS "wilc1000_sdio" -#define SDIO_VENDOR_ID_WILC 0x0296 -#define SDIO_DEVICE_ID_WILC 0x5347 - static const struct sdio_device_id wilc_sdio_ids[] = { - { SDIO_DEVICE(SDIO_VENDOR_ID_WILC, SDIO_DEVICE_ID_WILC) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_MICROCHIP_WILC, SDIO_DEVICE_ID_MICROCHIP_WILC1000) }, { }, }; -- cgit v1.2.3 From 560a218d1ce6ea36df6fb943a1065181df90a4d6 Mon Sep 17 00:00:00 2001 From: Vaibhav Gupta Date: Fri, 17 Jul 2020 16:39:29 +0530 Subject: rt2x00: pci: use generic power management Drivers using legacy PM have to manage PCI states and device's PM states themselves. They also need to take care of configuration registers. With improved and powerful support of generic PM, PCI Core takes care of above mentioned, device-independent, jobs. The callbacks make use of PCI helper functions like pci_save/restore_state(), pci_enable/disable_device() and pci_set_power_state() to do required operations. In generic mode, they are no longer needed. Change function parameter in both .suspend() and .resume() to "struct device*" type. Use dev_get_drvdata() to get drv data. The .suspend() callback is invoking rt2x00lib_suspend() which needs to be modified as generic rt2x00pci_suspend() has no pm_message_t type argument, passed to it, which is required by it according to its declaration. Although this variable remained unused in the function body. Hence, remove it from the function definition & declaration. rt2x00lib_suspend() is also invoked by rt2x00usb_suspend() and rt2x00soc_suspend(). Thus, modify the functional call accordingly in their function body. Earlier, .suspend() & .resume() were exported and were used by the following drivers: - drivers/net/wireless/ralink/rt2x00/rt2400pci.c - drivers/net/wireless/ralink/rt2x00/rt2500pci.c - drivers/net/wireless/ralink/rt2x00/rt2800pci.c - drivers/net/wireless/ralink/rt2x00/rt61pci.c Now, we only need to bind "struct dev_pm_ops" variable to "struct pci_driver". Thus, make the callbacks static. Declare an "extern const struct dev_pm_ops" variable and bind PM callbacks to it. Now, export the variable instead and use it in respective drivers. Compile-tested only. Signed-off-by: Vaibhav Gupta Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200717110928.454867-1-vaibhavgupta40@gmail.com --- drivers/net/wireless/ralink/rt2x00/rt2400pci.c | 3 +-- drivers/net/wireless/ralink/rt2x00/rt2500pci.c | 3 +-- drivers/net/wireless/ralink/rt2x00/rt2800pci.c | 3 +-- drivers/net/wireless/ralink/rt2x00/rt2x00.h | 5 ++--- drivers/net/wireless/ralink/rt2x00/rt2x00dev.c | 4 +--- drivers/net/wireless/ralink/rt2x00/rt2x00pci.c | 31 +++++++------------------- drivers/net/wireless/ralink/rt2x00/rt2x00pci.h | 9 ++------ drivers/net/wireless/ralink/rt2x00/rt2x00soc.c | 2 +- drivers/net/wireless/ralink/rt2x00/rt2x00usb.c | 2 +- drivers/net/wireless/ralink/rt2x00/rt61pci.c | 3 +-- 10 files changed, 19 insertions(+), 46 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c index 4d44509e2ce3..c1ac933349d1 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c @@ -1834,8 +1834,7 @@ static struct pci_driver rt2400pci_driver = { .id_table = rt2400pci_device_table, .probe = rt2400pci_probe, .remove = rt2x00pci_remove, - .suspend = rt2x00pci_suspend, - .resume = rt2x00pci_resume, + .driver.pm = &rt2x00pci_pm_ops, }; module_pci_driver(rt2400pci_driver); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c index 4620990a94cf..0859adebd860 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c @@ -2132,8 +2132,7 @@ static struct pci_driver rt2500pci_driver = { .id_table = rt2500pci_device_table, .probe = rt2500pci_probe, .remove = rt2x00pci_remove, - .suspend = rt2x00pci_suspend, - .resume = rt2x00pci_resume, + .driver.pm = &rt2x00pci_pm_ops, }; module_pci_driver(rt2500pci_driver); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c index 3868c07672bd..9a33baaa6184 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c @@ -455,8 +455,7 @@ static struct pci_driver rt2800pci_driver = { .id_table = rt2800pci_device_table, .probe = rt2800pci_probe, .remove = rt2x00pci_remove, - .suspend = rt2x00pci_suspend, - .resume = rt2x00pci_resume, + .driver.pm = &rt2x00pci_pm_ops, }; module_pci_driver(rt2800pci_driver); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index ea8a34ecae14..ecc60d8cbb01 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -1487,9 +1487,8 @@ bool rt2x00mac_tx_frames_pending(struct ieee80211_hw *hw); */ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev); void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev); -#ifdef CONFIG_PM -int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state); + +int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev); int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev); -#endif /* CONFIG_PM */ #endif /* RT2X00_H */ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c index 7f9e43a4f805..8c6d3099b19d 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c @@ -1556,8 +1556,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev); /* * Device state handlers */ -#ifdef CONFIG_PM -int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) +int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev) { rt2x00_dbg(rt2x00dev, "Going to sleep\n"); @@ -1614,7 +1613,6 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) return 0; } EXPORT_SYMBOL_GPL(rt2x00lib_resume); -#endif /* CONFIG_PM */ /* * rt2x00lib module information. diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00pci.c b/drivers/net/wireless/ralink/rt2x00/rt2x00pci.c index 7f9baa94c7c8..cabeef0dde45 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00pci.c @@ -169,39 +169,24 @@ void rt2x00pci_remove(struct pci_dev *pci_dev) } EXPORT_SYMBOL_GPL(rt2x00pci_remove); -#ifdef CONFIG_PM -int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state) +static int __maybe_unused rt2x00pci_suspend(struct device *dev) { - struct ieee80211_hw *hw = pci_get_drvdata(pci_dev); + struct ieee80211_hw *hw = dev_get_drvdata(dev); struct rt2x00_dev *rt2x00dev = hw->priv; - int retval; - - retval = rt2x00lib_suspend(rt2x00dev, state); - if (retval) - return retval; - pci_save_state(pci_dev); - pci_disable_device(pci_dev); - return pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); + return rt2x00lib_suspend(rt2x00dev); } -EXPORT_SYMBOL_GPL(rt2x00pci_suspend); -int rt2x00pci_resume(struct pci_dev *pci_dev) +static int __maybe_unused rt2x00pci_resume(struct device *dev) { - struct ieee80211_hw *hw = pci_get_drvdata(pci_dev); + struct ieee80211_hw *hw = dev_get_drvdata(dev); struct rt2x00_dev *rt2x00dev = hw->priv; - if (pci_set_power_state(pci_dev, PCI_D0) || - pci_enable_device(pci_dev)) { - rt2x00_err(rt2x00dev, "Failed to resume device\n"); - return -EIO; - } - - pci_restore_state(pci_dev); return rt2x00lib_resume(rt2x00dev); } -EXPORT_SYMBOL_GPL(rt2x00pci_resume); -#endif /* CONFIG_PM */ + +SIMPLE_DEV_PM_OPS(rt2x00pci_pm_ops, rt2x00pci_suspend, rt2x00pci_resume); +EXPORT_SYMBOL_GPL(rt2x00pci_pm_ops); /* * rt2x00pci module information. diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00pci.h b/drivers/net/wireless/ralink/rt2x00/rt2x00pci.h index fd955ccaa1e6..27f7b2bd26ea 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00pci.h @@ -21,12 +21,7 @@ */ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops); void rt2x00pci_remove(struct pci_dev *pci_dev); -#ifdef CONFIG_PM -int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state); -int rt2x00pci_resume(struct pci_dev *pci_dev); -#else -#define rt2x00pci_suspend NULL -#define rt2x00pci_resume NULL -#endif /* CONFIG_PM */ + +extern const struct dev_pm_ops rt2x00pci_pm_ops; #endif /* RT2X00PCI_H */ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c b/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c index 596b8a432946..eface610178d 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c @@ -130,7 +130,7 @@ int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state) struct ieee80211_hw *hw = platform_get_drvdata(pdev); struct rt2x00_dev *rt2x00dev = hw->priv; - return rt2x00lib_suspend(rt2x00dev, state); + return rt2x00lib_suspend(rt2x00dev); } EXPORT_SYMBOL_GPL(rt2x00soc_suspend); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c index 92e9e023c349..e4473a551241 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c @@ -886,7 +886,7 @@ int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state) struct ieee80211_hw *hw = usb_get_intfdata(usb_intf); struct rt2x00_dev *rt2x00dev = hw->priv; - return rt2x00lib_suspend(rt2x00dev, state); + return rt2x00lib_suspend(rt2x00dev); } EXPORT_SYMBOL_GPL(rt2x00usb_suspend); diff --git a/drivers/net/wireless/ralink/rt2x00/rt61pci.c b/drivers/net/wireless/ralink/rt2x00/rt61pci.c index d83288bef2fc..eefce76fc99b 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c @@ -3009,8 +3009,7 @@ static struct pci_driver rt61pci_driver = { .id_table = rt61pci_device_table, .probe = rt61pci_probe, .remove = rt2x00pci_remove, - .suspend = rt2x00pci_suspend, - .resume = rt2x00pci_resume, + .driver.pm = &rt2x00pci_pm_ops, }; module_pci_driver(rt61pci_driver); -- cgit v1.2.3 From 348cb5dc4d702e071efb4f70c4dacfe2473c815d Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Sat, 18 Jul 2020 12:02:40 +0200 Subject: ipw2x00: Replace HTTP links with HTTPS ones Rationale: Reduces attack surface on kernel devs opening the links for MITM as HTTPS traffic is much harder to manipulate. Deterministic algorithm: For each file: If not .svg: For each line: If doesn't contain `\bxmlns\b`: For each link, `\bhttp://[^# \t\r\n]*(?:\w|/)`: If neither `\bgnu\.org/license`, nor `\bmozilla\.org/MPL\b`: If both the HTTP and HTTPS versions return 200 OK and serve the same content: Replace HTTP with HTTPS. Signed-off-by: Alexander A. Klimov Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200718100240.98593-1-grandmaster@al2klimov.de --- drivers/net/wireless/intel/ipw2x00/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/ipw2x00/Kconfig b/drivers/net/wireless/intel/ipw2x00/Kconfig index 18436592a3a6..b1e7b4470842 100644 --- a/drivers/net/wireless/intel/ipw2x00/Kconfig +++ b/drivers/net/wireless/intel/ipw2x00/Kconfig @@ -28,7 +28,7 @@ config IPW2100 You will also very likely need the Wireless Tools in order to configure your card: - . + . It is recommended that you compile this driver as a module (M) rather than built-in (Y). This driver requires firmware at device @@ -90,7 +90,7 @@ config IPW2200 You will also very likely need the Wireless Tools in order to configure your card: - . + . It is recommended that you compile this driver as a module (M) rather than built-in (Y). This driver requires firmware at device -- cgit v1.2.3 From 2d96c1ed4bab52e2dced98746ecc978a1ac0eeb7 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Sun, 19 Jul 2020 13:01:15 +0200 Subject: b43: Replace HTTP links with HTTPS ones Rationale: Reduces attack surface on kernel devs opening the links for MITM as HTTPS traffic is much harder to manipulate. Deterministic algorithm: For each file: If not .svg: For each line: If doesn't contain `\bxmlns\b`: For each link, `\bhttp://[^# \t\r\n]*(?:\w|/)`: If neither `\bgnu\.org/license`, nor `\bmozilla\.org/MPL\b`: If both the HTTP and HTTPS versions return 200 OK and serve the same content: Replace HTTP with HTTPS. Signed-off-by: Alexander A. Klimov Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200719110115.58085-1-grandmaster@al2klimov.de --- drivers/net/wireless/broadcom/b43/main.c | 14 +-- drivers/net/wireless/broadcom/b43/phy_common.c | 2 +- drivers/net/wireless/broadcom/b43/phy_g.c | 12 +- drivers/net/wireless/broadcom/b43/phy_ht.c | 2 +- drivers/net/wireless/broadcom/b43/phy_lp.c | 2 +- drivers/net/wireless/broadcom/b43/phy_n.c | 150 ++++++++++++------------ drivers/net/wireless/broadcom/b43/radio_2056.c | 2 +- drivers/net/wireless/broadcom/b43/tables_nphy.c | 4 +- drivers/net/wireless/intersil/orinoco/Kconfig | 4 +- 9 files changed, 96 insertions(+), 96 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index 0c2ea12fca19..a54dd4f7fa54 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -734,7 +734,7 @@ static void b43_short_slot_timing_disable(struct b43_wldev *dev) } /* DummyTransmission function, as documented on - * http://bcm-v4.sipsolutions.net/802.11/DummyTransmission + * https://bcm-v4.sipsolutions.net/802.11/DummyTransmission */ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) { @@ -1198,7 +1198,7 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/BmacCorePllReset */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/BmacCorePllReset */ void b43_wireless_core_phy_pll_reset(struct b43_wldev *dev) { struct bcma_drv_cc *bcma_cc __maybe_unused; @@ -2290,7 +2290,7 @@ err_format: return -EPROTO; } -/* http://bcm-v4.sipsolutions.net/802.11/Init/Firmware */ +/* https://bcm-v4.sipsolutions.net/802.11/Init/Firmware */ static int b43_try_request_fw(struct b43_request_fw_context *ctx) { struct b43_wldev *dev = ctx->dev; @@ -2843,7 +2843,7 @@ static int b43_upload_initvals_band(struct b43_wldev *dev) } /* Initialize the GPIOs - * http://bcm-specs.sipsolutions.net/GPIO + * https://bcm-specs.sipsolutions.net/GPIO */ #ifdef CONFIG_B43_SSB @@ -2971,7 +2971,7 @@ void b43_mac_enable(struct b43_wldev *dev) } } -/* http://bcm-specs.sipsolutions.net/SuspendMAC */ +/* https://bcm-specs.sipsolutions.net/SuspendMAC */ void b43_mac_suspend(struct b43_wldev *dev) { int i; @@ -3004,7 +3004,7 @@ out: dev->mac_suspended++; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */ void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on) { u32 tmp; @@ -3231,7 +3231,7 @@ static void b43_chip_exit(struct b43_wldev *dev) } /* Initialize the chip - * http://bcm-specs.sipsolutions.net/ChipInit + * https://bcm-specs.sipsolutions.net/ChipInit */ static int b43_chip_init(struct b43_wldev *dev) { diff --git a/drivers/net/wireless/broadcom/b43/phy_common.c b/drivers/net/wireless/broadcom/b43/phy_common.c index 923d4cb9fc30..1de4de094d61 100644 --- a/drivers/net/wireless/broadcom/b43/phy_common.c +++ b/drivers/net/wireless/broadcom/b43/phy_common.c @@ -559,7 +559,7 @@ bool b43_is_40mhz(struct b43_wldev *dev) return dev->phy.chandef->width == NL80211_CHAN_WIDTH_40; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */ void b43_phy_force_clock(struct b43_wldev *dev, bool force) { u32 tmp; diff --git a/drivers/net/wireless/broadcom/b43/phy_g.c b/drivers/net/wireless/broadcom/b43/phy_g.c index 1e022ec733a3..d5a1a5c58236 100644 --- a/drivers/net/wireless/broadcom/b43/phy_g.c +++ b/drivers/net/wireless/broadcom/b43/phy_g.c @@ -357,14 +357,14 @@ static void b43_set_original_gains(struct b43_wldev *dev) b43_dummy_transmission(dev, false, true); } -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */ static void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val) { b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val); } -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */ static s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset) { u16 val; @@ -375,7 +375,7 @@ static s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset) return (s16) val; } -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */ static void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) { u16 i; @@ -389,7 +389,7 @@ static void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) } } -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */ static void b43_nrssi_mem_update(struct b43_wldev *dev) { struct b43_phy_g *gphy = dev->phy.g; @@ -1575,7 +1575,7 @@ static void b43_phy_initb5(struct b43_wldev *dev) b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/Init/B6 */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/Init/B6 */ static void b43_phy_initb6(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -2746,7 +2746,7 @@ static int b43_gphy_op_interf_mitigation(struct b43_wldev *dev, return 0; } -/* http://bcm-specs.sipsolutions.net/EstimatePowerOut +/* https://bcm-specs.sipsolutions.net/EstimatePowerOut * This function converts a TSSI value to dBm in Q5.2 */ static s8 b43_gphy_estimate_power_out(struct b43_wldev *dev, s8 tssi) diff --git a/drivers/net/wireless/broadcom/b43/phy_ht.c b/drivers/net/wireless/broadcom/b43/phy_ht.c index 6033df1c3053..c685b4bb5ed6 100644 --- a/drivers/net/wireless/broadcom/b43/phy_ht.c +++ b/drivers/net/wireless/broadcom/b43/phy_ht.c @@ -1018,7 +1018,7 @@ static void b43_phy_ht_op_free(struct b43_wldev *dev) phy->ht = NULL; } -/* http://bcm-v4.sipsolutions.net/802.11/Radio/Switch%20Radio */ +/* https://bcm-v4.sipsolutions.net/802.11/Radio/Switch%20Radio */ static void b43_phy_ht_op_software_rfkill(struct b43_wldev *dev, bool blocked) { diff --git a/drivers/net/wireless/broadcom/b43/phy_lp.c b/drivers/net/wireless/broadcom/b43/phy_lp.c index cfb953d61dc5..0e5c076e7544 100644 --- a/drivers/net/wireless/broadcom/b43/phy_lp.c +++ b/drivers/net/wireless/broadcom/b43/phy_lp.c @@ -70,7 +70,7 @@ static void b43_lpphy_op_free(struct b43_wldev *dev) dev->phy.lp = NULL; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/LP/ReadBandSrom */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/LP/ReadBandSrom */ static void lpphy_read_band_sprom(struct b43_wldev *dev) { struct ssb_sprom *sprom = dev->dev->bus_sprom; diff --git a/drivers/net/wireless/broadcom/b43/phy_n.c b/drivers/net/wireless/broadcom/b43/phy_n.c index 46db91846007..f75f0ff1db1e 100644 --- a/drivers/net/wireless/broadcom/b43/phy_n.c +++ b/drivers/net/wireless/broadcom/b43/phy_n.c @@ -98,7 +98,7 @@ static inline bool b43_nphy_ipa(struct b43_wldev *dev) (dev->phy.n->ipa5g_on && band == NL80211_BAND_5GHZ)); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCoreGetState */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCoreGetState */ static u8 b43_nphy_get_rx_core_state(struct b43_wldev *dev) { return (b43_phy_read(dev, B43_NPHY_RFSEQCA) & B43_NPHY_RFSEQCA_RXEN) >> @@ -109,7 +109,7 @@ static u8 b43_nphy_get_rx_core_state(struct b43_wldev *dev) * RF (just without b43_nphy_rf_ctl_intc_override) **************************************************/ -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ForceRFSeq */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/ForceRFSeq */ static void b43_nphy_force_rf_sequence(struct b43_wldev *dev, enum b43_nphy_rf_sequence seq) { @@ -146,7 +146,7 @@ static void b43_nphy_rf_ctl_override_rev19(struct b43_wldev *dev, u16 field, /* TODO */ } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverrideRev7 */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverrideRev7 */ static void b43_nphy_rf_ctl_override_rev7(struct b43_wldev *dev, u16 field, u16 value, u8 core, bool off, u8 override) @@ -193,7 +193,7 @@ static void b43_nphy_rf_ctl_override_rev7(struct b43_wldev *dev, u16 field, } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverideOneToMany */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverideOneToMany */ static void b43_nphy_rf_ctl_override_one_to_many(struct b43_wldev *dev, enum n_rf_ctl_over_cmd cmd, u16 value, u8 core, bool off) @@ -237,7 +237,7 @@ static void b43_nphy_rf_ctl_override_one_to_many(struct b43_wldev *dev, } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */ static void b43_nphy_rf_ctl_override(struct b43_wldev *dev, u16 field, u16 value, u8 core, bool off) { @@ -382,7 +382,7 @@ static void b43_nphy_rf_ctl_intc_override_rev7(struct b43_wldev *dev, } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlIntcOverride */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlIntcOverride */ static void b43_nphy_rf_ctl_intc_override(struct b43_wldev *dev, enum n_intc_override intc_override, u16 value, u8 core) @@ -490,7 +490,7 @@ static void b43_nphy_rf_ctl_intc_override(struct b43_wldev *dev, * Various PHY ops **************************************************/ -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */ static void b43_nphy_write_clip_detection(struct b43_wldev *dev, const u16 *clip_st) { @@ -498,14 +498,14 @@ static void b43_nphy_write_clip_detection(struct b43_wldev *dev, b43_phy_write(dev, B43_NPHY_C2_CLIP1THRES, clip_st[1]); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */ static void b43_nphy_read_clip_detection(struct b43_wldev *dev, u16 *clip_st) { clip_st[0] = b43_phy_read(dev, B43_NPHY_C1_CLIP1THRES); clip_st[1] = b43_phy_read(dev, B43_NPHY_C2_CLIP1THRES); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/classifier */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/classifier */ static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val) { u16 tmp; @@ -526,7 +526,7 @@ static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val) return tmp; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */ static void b43_nphy_reset_cca(struct b43_wldev *dev) { u16 bbcfg; @@ -540,7 +540,7 @@ static void b43_nphy_reset_cca(struct b43_wldev *dev) b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/carriersearch */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/carriersearch */ static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable) { struct b43_phy *phy = &dev->phy; @@ -564,7 +564,7 @@ static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable) } } -/* http://bcm-v4.sipsolutions.net/PHY/N/Read_Lpf_Bw_Ctl */ +/* https://bcm-v4.sipsolutions.net/PHY/N/Read_Lpf_Bw_Ctl */ static u16 b43_nphy_read_lpf_ctl(struct b43_wldev *dev, u16 offset) { if (!offset) @@ -572,7 +572,7 @@ static u16 b43_nphy_read_lpf_ctl(struct b43_wldev *dev, u16 offset) return b43_ntab_read(dev, B43_NTAB16(7, offset)) & 0x7; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/AdjustLnaGainTbl */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/AdjustLnaGainTbl */ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; @@ -628,7 +628,7 @@ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev) b43_nphy_stay_in_carrier_search(dev, 0); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRfSeq */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRfSeq */ static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd, u8 *events, u8 *delays, u8 length) { @@ -805,7 +805,7 @@ static void b43_radio_2057_setup(struct b43_wldev *dev, } /* Calibrate resistors in LPF of PLL? - * http://bcm-v4.sipsolutions.net/PHY/radio205x_rcal + * https://bcm-v4.sipsolutions.net/PHY/radio205x_rcal */ static u8 b43_radio_2057_rcal(struct b43_wldev *dev) { @@ -919,7 +919,7 @@ static u8 b43_radio_2057_rcal(struct b43_wldev *dev) } /* Calibrate the internal RC oscillator? - * http://bcm-v4.sipsolutions.net/PHY/radio2057_rccal + * https://bcm-v4.sipsolutions.net/PHY/radio2057_rccal */ static u16 b43_radio_2057_rccal(struct b43_wldev *dev) { @@ -1030,7 +1030,7 @@ static void b43_radio_2057_init_post(struct b43_wldev *dev) b43_radio_mask(dev, R2057_RFPLL_MASTER, ~0x8); } -/* http://bcm-v4.sipsolutions.net/802.11/Radio/2057/Init */ +/* https://bcm-v4.sipsolutions.net/802.11/Radio/2057/Init */ static void b43_radio_2057_init(struct b43_wldev *dev) { b43_radio_2057_init_pre(dev); @@ -1117,7 +1117,7 @@ static void b43_chantab_radio_2056_upload(struct b43_wldev *dev, e->radio_tx1_mixg_boost_tune); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2056Setup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2056Setup */ static void b43_radio_2056_setup(struct b43_wldev *dev, const struct b43_nphy_channeltab_entry_rev3 *e) { @@ -1356,7 +1356,7 @@ static void b43_radio_init2056_post(struct b43_wldev *dev) /* * Initialize a Broadcom 2056 N-radio - * http://bcm-v4.sipsolutions.net/802.11/Radio/2056/Init + * https://bcm-v4.sipsolutions.net/802.11/Radio/2056/Init */ static void b43_radio_init2056(struct b43_wldev *dev) { @@ -1406,7 +1406,7 @@ static void b43_chantab_radio_upload(struct b43_wldev *dev, b43_radio_write(dev, B2055_C2_TX_MXBGTRIM, e->radio_c2_tx_mxbgtrim); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2055Setup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2055Setup */ static void b43_radio_2055_setup(struct b43_wldev *dev, const struct b43_nphy_channeltab_entry_rev2 *e) { @@ -1480,7 +1480,7 @@ static void b43_radio_init2055_post(struct b43_wldev *dev) /* * Initialize a Broadcom 2055 N-radio - * http://bcm-v4.sipsolutions.net/802.11/Radio/2055/Init + * https://bcm-v4.sipsolutions.net/802.11/Radio/2055/Init */ static void b43_radio_init2055(struct b43_wldev *dev) { @@ -1499,7 +1499,7 @@ static void b43_radio_init2055(struct b43_wldev *dev) * Samples **************************************************/ -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/LoadSampleTable */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/LoadSampleTable */ static int b43_nphy_load_samples(struct b43_wldev *dev, struct cordic_iq *samples, u16 len) { struct b43_phy_n *nphy = dev->phy.n; @@ -1526,7 +1526,7 @@ static int b43_nphy_load_samples(struct b43_wldev *dev, return 0; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GenLoadSamples */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/GenLoadSamples */ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max, bool test) { @@ -1569,7 +1569,7 @@ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max, return (i < 0) ? 0 : len; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, u16 wait, bool iqmode, bool dac_test, bool modify_bbmult) @@ -1650,7 +1650,7 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, * RSSI **************************************************/ -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ScaleOffsetRssi */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/ScaleOffsetRssi */ static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale, s8 offset, u8 core, enum n_rail_type rail, @@ -1895,7 +1895,7 @@ static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code, } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */ static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, enum n_rssi_type type) { @@ -1907,7 +1907,7 @@ static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, b43_nphy_rev2_rssi_select(dev, code, type); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRssi2055Vcm */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRssi2055Vcm */ static void b43_nphy_set_rssi_2055_vcm(struct b43_wldev *dev, enum n_rssi_type rssi_type, u8 *buf) { @@ -1936,7 +1936,7 @@ static void b43_nphy_set_rssi_2055_vcm(struct b43_wldev *dev, } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PollRssi */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/PollRssi */ static int b43_nphy_poll_rssi(struct b43_wldev *dev, enum n_rssi_type rssi_type, s32 *buf, u8 nsamp) { @@ -2025,7 +2025,7 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, enum n_rssi_type rssi_type, return out; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICalRev3 */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICalRev3 */ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -2287,7 +2287,7 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) b43_nphy_write_clip_detection(dev, clip_state); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal */ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, enum n_rssi_type type) { int i, j, vcm; @@ -2453,7 +2453,7 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, enum n_rssi_type type) /* * RSSI Calibration - * http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal + * https://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal */ static void b43_nphy_rssi_cal(struct b43_wldev *dev) { @@ -2680,7 +2680,7 @@ static void b43_nphy_gain_ctl_workarounds_rev1_2(struct b43_wldev *dev) b43_phy_maskset(dev, B43_PHY_N(0xC5D), 0xFF80, 4); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */ static void b43_nphy_gain_ctl_workarounds(struct b43_wldev *dev) { if (dev->phy.rev >= 19) @@ -3433,7 +3433,7 @@ static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev) B43_NPHY_FINERX2_CGC_DECGC); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */ static void b43_nphy_workarounds(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -3468,7 +3468,7 @@ static void b43_nphy_workarounds(struct b43_wldev *dev) /* * Transmits a known value for LO calibration - * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone + * https://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone */ static int b43_nphy_tx_tone(struct b43_wldev *dev, u32 freq, u16 max_val, bool iqmode, bool dac_test, bool modify_bbmult) @@ -3481,7 +3481,7 @@ static int b43_nphy_tx_tone(struct b43_wldev *dev, u32 freq, u16 max_val, return 0; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Chains */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/Chains */ static void b43_nphy_update_txrx_chain(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; @@ -3509,7 +3509,7 @@ static void b43_nphy_update_txrx_chain(struct b43_wldev *dev) ~B43_NPHY_RFSEQMODE_CAOVER); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/stop-playback */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/stop-playback */ static void b43_nphy_stop_playback(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -3546,7 +3546,7 @@ static void b43_nphy_stop_playback(struct b43_wldev *dev) b43_nphy_stay_in_carrier_search(dev, 0); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IqCalGainParams */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/IqCalGainParams */ static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core, struct nphy_txgains target, struct nphy_iqcal_params *params) @@ -3595,7 +3595,7 @@ static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core, * Tx and Rx **************************************************/ -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlEnable */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlEnable */ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable) { struct b43_phy *phy = &dev->phy; @@ -3732,7 +3732,7 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable) b43_nphy_stay_in_carrier_search(dev, 0); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrFix */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrFix */ static void b43_nphy_tx_power_fix(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -3926,7 +3926,7 @@ static void b43_nphy_ipa_internal_tssi_setup(struct b43_wldev *dev) /* * Stop radio and transmit known signal. Then check received signal strength to * get TSSI (Transmit Signal Strength Indicator). - * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlIdleTssi + * https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlIdleTssi */ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev) { @@ -3978,7 +3978,7 @@ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev) nphy->pwr_ctl_info[1].idle_tssi_2g = (tmp >> 8) & 0xFF; } -/* http://bcm-v4.sipsolutions.net/PHY/N/TxPwrLimitToTbl */ +/* https://bcm-v4.sipsolutions.net/PHY/N/TxPwrLimitToTbl */ static void b43_nphy_tx_prepare_adjusted_power_table(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; @@ -4039,7 +4039,7 @@ static void b43_nphy_tx_prepare_adjusted_power_table(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlSetup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlSetup */ static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -4272,7 +4272,7 @@ static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PA%20override */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/PA%20override */ static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable) { struct b43_phy_n *nphy = dev->phy.n; @@ -4310,7 +4310,7 @@ static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable) /* * TX low-pass filter bandwidth setup - * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxLpFbw + * https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxLpFbw */ static void b43_nphy_tx_lpf_bw(struct b43_wldev *dev) { @@ -4333,7 +4333,7 @@ static void b43_nphy_tx_lpf_bw(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqEst */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqEst */ static void b43_nphy_rx_iq_est(struct b43_wldev *dev, struct nphy_iq_est *est, u16 samps, u8 time, bool wait) { @@ -4372,7 +4372,7 @@ static void b43_nphy_rx_iq_est(struct b43_wldev *dev, struct nphy_iq_est *est, memset(est, 0, sizeof(*est)); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqCoeffs */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqCoeffs */ static void b43_nphy_rx_iq_coeffs(struct b43_wldev *dev, bool write, struct b43_phy_n_iq_comp *pcomp) { @@ -4391,7 +4391,7 @@ static void b43_nphy_rx_iq_coeffs(struct b43_wldev *dev, bool write, #if 0 /* Ready but not used anywhere */ -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhyCleanup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhyCleanup */ static void b43_nphy_rx_cal_phy_cleanup(struct b43_wldev *dev, u8 core) { u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs; @@ -4414,7 +4414,7 @@ static void b43_nphy_rx_cal_phy_cleanup(struct b43_wldev *dev, u8 core) b43_phy_write(dev, B43_NPHY_PAPD_EN1, regs[10]); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhySetup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhySetup */ static void b43_nphy_rx_cal_phy_setup(struct b43_wldev *dev, u8 core) { u8 rxval, txval; @@ -4476,7 +4476,7 @@ static void b43_nphy_rx_cal_phy_setup(struct b43_wldev *dev, u8 core) } #endif -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalcRxIqComp */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/CalcRxIqComp */ static void b43_nphy_calc_rx_iq_comp(struct b43_wldev *dev, u8 mask) { int i; @@ -4574,7 +4574,7 @@ static void b43_nphy_calc_rx_iq_comp(struct b43_wldev *dev, u8 mask) b43_nphy_rx_iq_coeffs(dev, true, &new); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxIqWar */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxIqWar */ static void b43_nphy_tx_iq_workaround(struct b43_wldev *dev) { u16 array[4]; @@ -4586,7 +4586,7 @@ static void b43_nphy_tx_iq_workaround(struct b43_wldev *dev) b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW3, array[3]); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SpurWar */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/SpurWar */ static void b43_nphy_spur_workaround(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; @@ -4645,7 +4645,7 @@ static void b43_nphy_spur_workaround(struct b43_wldev *dev) b43_nphy_stay_in_carrier_search(dev, 0); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */ static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; @@ -4713,7 +4713,7 @@ static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev) /* * Restore RSSI Calibration - * http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreRssiCal + * https://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreRssiCal */ static void b43_nphy_restore_rssi_cal(struct b43_wldev *dev) { @@ -4822,7 +4822,7 @@ static void b43_nphy_tx_cal_radio_setup_rev7(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalRadioSetup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalRadioSetup */ static void b43_nphy_tx_cal_radio_setup(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -4921,7 +4921,7 @@ static void b43_nphy_tx_cal_radio_setup(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/UpdateTxCalLadder */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/UpdateTxCalLadder */ static void b43_nphy_update_tx_cal_ladder(struct b43_wldev *dev, u16 core) { struct b43_phy_n *nphy = dev->phy.n; @@ -4955,14 +4955,14 @@ static void b43_nphy_pa_set_tx_dig_filter(struct b43_wldev *dev, u16 offset, b43_phy_write(dev, offset, filter[i]); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ExtPaSetTxDigiFilts */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/ExtPaSetTxDigiFilts */ static void b43_nphy_ext_pa_set_tx_dig_filters(struct b43_wldev *dev) { b43_nphy_pa_set_tx_dig_filter(dev, 0x2C5, tbl_tx_filter_coef_rev4[2]); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IpaSetTxDigiFilts */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/IpaSetTxDigiFilts */ static void b43_nphy_int_pa_set_tx_dig_filters(struct b43_wldev *dev) { /* B43_NPHY_TXF_20CO_S0A1, B43_NPHY_TXF_40CO_S0A1, unknown */ @@ -5002,7 +5002,7 @@ static void b43_nphy_int_pa_set_tx_dig_filters(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetTxGain */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/GetTxGain */ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; @@ -5077,7 +5077,7 @@ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev) return target; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhyCleanup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhyCleanup */ static void b43_nphy_tx_cal_phy_cleanup(struct b43_wldev *dev) { u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs; @@ -5106,7 +5106,7 @@ static void b43_nphy_tx_cal_phy_cleanup(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhySetup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhySetup */ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -5207,7 +5207,7 @@ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SaveCal */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/SaveCal */ static void b43_nphy_save_cal(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -5278,7 +5278,7 @@ static void b43_nphy_save_cal(struct b43_wldev *dev) b43_nphy_stay_in_carrier_search(dev, 0); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreCal */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreCal */ static void b43_nphy_restore_cal(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -5366,7 +5366,7 @@ static void b43_nphy_restore_cal(struct b43_wldev *dev) b43_nphy_rx_iq_coeffs(dev, true, rxcal_coeffs); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalTxIqlo */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/CalTxIqlo */ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, struct nphy_txgains target, bool full, bool mphase) @@ -5599,7 +5599,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, return error; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ReapplyTxCalCoeffs */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/ReapplyTxCalCoeffs */ static void b43_nphy_reapply_tx_cal_coeffs(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; @@ -5634,7 +5634,7 @@ static void b43_nphy_reapply_tx_cal_coeffs(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIqRev2 */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIqRev2 */ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, struct nphy_txgains target, u8 type, bool debug) { @@ -5821,7 +5821,7 @@ static int b43_nphy_rev3_cal_rx_iq(struct b43_wldev *dev, return -1; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIq */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIq */ static int b43_nphy_cal_rx_iq(struct b43_wldev *dev, struct nphy_txgains target, u8 type, bool debug) { @@ -5834,7 +5834,7 @@ static int b43_nphy_cal_rx_iq(struct b43_wldev *dev, return b43_nphy_rev2_cal_rx_iq(dev, target, type, debug); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCoreSetState */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCoreSetState */ static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask) { struct b43_phy *phy = &dev->phy; @@ -5939,7 +5939,7 @@ static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev, * N-PHY init **************************************************/ -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MIMOConfig */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/MIMOConfig */ static void b43_nphy_update_mimo_config(struct b43_wldev *dev, s32 preamble) { u16 mimocfg = b43_phy_read(dev, B43_NPHY_MIMOCFG); @@ -5953,7 +5953,7 @@ static void b43_nphy_update_mimo_config(struct b43_wldev *dev, s32 preamble) b43_phy_write(dev, B43_NPHY_MIMOCFG, mimocfg); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BPHYInit */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/BPHYInit */ static void b43_nphy_bphy_init(struct b43_wldev *dev) { unsigned int i; @@ -5972,7 +5972,7 @@ static void b43_nphy_bphy_init(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SuperSwitchInit */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/SuperSwitchInit */ static void b43_nphy_superswitch_init(struct b43_wldev *dev, bool init) { if (dev->phy.rev >= 7) @@ -6246,7 +6246,7 @@ static void b43_chantab_phy_upload(struct b43_wldev *dev, b43_phy_write(dev, B43_NPHY_BW6, e->phy_bw6); } -/* http://bcm-v4.sipsolutions.net/802.11/PmuSpurAvoid */ +/* https://bcm-v4.sipsolutions.net/802.11/PmuSpurAvoid */ static void b43_nphy_pmu_spur_avoid(struct b43_wldev *dev, bool avoid) { switch (dev->dev->bus_type) { @@ -6265,7 +6265,7 @@ static void b43_nphy_pmu_spur_avoid(struct b43_wldev *dev, bool avoid) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ChanspecSetup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/ChanspecSetup */ static void b43_nphy_channel_setup(struct b43_wldev *dev, const struct b43_phy_n_sfo_cfg *e, struct ieee80211_channel *new_channel) @@ -6372,7 +6372,7 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev, b43_nphy_spur_workaround(dev); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetChanspec */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/SetChanspec */ static int b43_nphy_set_channel(struct b43_wldev *dev, struct ieee80211_channel *channel, enum nl80211_channel_type channel_type) @@ -6589,7 +6589,7 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); } -/* http://bcm-v4.sipsolutions.net/802.11/Radio/Switch%20Radio */ +/* https://bcm-v4.sipsolutions.net/802.11/Radio/Switch%20Radio */ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, bool blocked) { @@ -6643,7 +6643,7 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/Anacore */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/Anacore */ static void b43_nphy_op_switch_analog(struct b43_wldev *dev, bool on) { struct b43_phy *phy = &dev->phy; diff --git a/drivers/net/wireless/broadcom/b43/radio_2056.c b/drivers/net/wireless/broadcom/b43/radio_2056.c index 575c696b7cdf..94f5e626acba 100644 --- a/drivers/net/wireless/broadcom/b43/radio_2056.c +++ b/drivers/net/wireless/broadcom/b43/radio_2056.c @@ -3072,7 +3072,7 @@ INITTABSPTS(b2056_inittab_radio_rev11); .phy_regs.phy_bw5 = r4, \ .phy_regs.phy_bw6 = r5 -/* http://bcm-v4.sipsolutions.net/802.11/Radio/2056/ChannelTable */ +/* https://bcm-v4.sipsolutions.net/802.11/Radio/2056/ChannelTable */ static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_phy_rev3[] = { { .freq = 4920, RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, diff --git a/drivers/net/wireless/broadcom/b43/tables_nphy.c b/drivers/net/wireless/broadcom/b43/tables_nphy.c index dad405abf9b1..7957db94e84c 100644 --- a/drivers/net/wireless/broadcom/b43/tables_nphy.c +++ b/drivers/net/wireless/broadcom/b43/tables_nphy.c @@ -3620,7 +3620,7 @@ static void b43_nphy_tables_init_rev0(struct b43_wldev *dev) ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/InitTables */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/InitTables */ void b43_nphy_tables_init(struct b43_wldev *dev) { if (dev->phy.rev >= 16) @@ -3633,7 +3633,7 @@ void b43_nphy_tables_init(struct b43_wldev *dev) b43_nphy_tables_init_rev0(dev); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetIpaGainTbl */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/GetIpaGainTbl */ static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; diff --git a/drivers/net/wireless/intersil/orinoco/Kconfig b/drivers/net/wireless/intersil/orinoco/Kconfig index c470ee23673f..f62730aa7be3 100644 --- a/drivers/net/wireless/intersil/orinoco/Kconfig +++ b/drivers/net/wireless/intersil/orinoco/Kconfig @@ -27,7 +27,7 @@ config HERMES You will also very likely also need the Wireless Tools in order to configure your card and that /etc/pcmcia/wireless.opts works : - + config HERMES_PRISM bool "Support Prism 2/2.5 chipset" @@ -120,7 +120,7 @@ config PCMCIA_HERMES You will very likely need the Wireless Tools in order to configure your card and that /etc/pcmcia/wireless.opts works: - . + . config PCMCIA_SPECTRUM tristate "Symbol Spectrum24 Trilogy PCMCIA card support" -- cgit v1.2.3 From 140c6026167b2b394bf3a8a882f3bfbca0726111 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Sun, 19 Jul 2020 13:11:24 +0200 Subject: b43legacy: Replace HTTP links with HTTPS ones Rationale: Reduces attack surface on kernel devs opening the links for MITM as HTTPS traffic is much harder to manipulate. Deterministic algorithm: For each file: If not .svg: For each line: If doesn't contain `\bxmlns\b`: For each link, `\bhttp://[^# \t\r\n]*(?:\w|/)`: If neither `\bgnu\.org/license`, nor `\bmozilla\.org/MPL\b`: If both the HTTP and HTTPS versions return 200 OK and serve the same content: Replace HTTP with HTTPS. Signed-off-by: Alexander A. Klimov Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200719111124.58167-1-grandmaster@al2klimov.de --- drivers/net/wireless/broadcom/b43legacy/main.c | 8 ++++---- drivers/net/wireless/broadcom/b43legacy/phy.c | 8 ++++---- drivers/net/wireless/broadcom/b43legacy/radio.c | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/b43legacy/main.c b/drivers/net/wireless/broadcom/b43legacy/main.c index 7bb6681fa882..da0d9e6087ca 100644 --- a/drivers/net/wireless/broadcom/b43legacy/main.c +++ b/drivers/net/wireless/broadcom/b43legacy/main.c @@ -591,7 +591,7 @@ static void b43legacy_synchronize_irq(struct b43legacy_wldev *dev) } /* DummyTransmission function, as documented on - * http://bcm-specs.sipsolutions.net/DummyTransmission + * https://bcm-specs.sipsolutions.net/DummyTransmission */ void b43legacy_dummy_transmission(struct b43legacy_wldev *dev) { @@ -1870,7 +1870,7 @@ out: } /* Initialize the GPIOs - * http://bcm-specs.sipsolutions.net/GPIO + * https://bcm-specs.sipsolutions.net/GPIO */ static int b43legacy_gpio_init(struct b43legacy_wldev *dev) { @@ -1960,7 +1960,7 @@ void b43legacy_mac_enable(struct b43legacy_wldev *dev) } } -/* http://bcm-specs.sipsolutions.net/SuspendMAC */ +/* https://bcm-specs.sipsolutions.net/SuspendMAC */ void b43legacy_mac_suspend(struct b43legacy_wldev *dev) { int i; @@ -2141,7 +2141,7 @@ static void b43legacy_chip_exit(struct b43legacy_wldev *dev) } /* Initialize the chip - * http://bcm-specs.sipsolutions.net/ChipInit + * https://bcm-specs.sipsolutions.net/ChipInit */ static int b43legacy_chip_init(struct b43legacy_wldev *dev) { diff --git a/drivers/net/wireless/broadcom/b43legacy/phy.c b/drivers/net/wireless/broadcom/b43legacy/phy.c index a659259bc51a..05404fbd1e70 100644 --- a/drivers/net/wireless/broadcom/b43legacy/phy.c +++ b/drivers/net/wireless/broadcom/b43legacy/phy.c @@ -129,7 +129,7 @@ void b43legacy_phy_calibrate(struct b43legacy_wldev *dev) } /* initialize B PHY power control - * as described in http://bcm-specs.sipsolutions.net/InitPowerControl + * as described in https://bcm-specs.sipsolutions.net/InitPowerControl */ static void b43legacy_phy_init_pctl(struct b43legacy_wldev *dev) { @@ -1461,7 +1461,7 @@ void b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev *dev, b43legacy_phy_write(dev, 0x0060, value); } -/* http://bcm-specs.sipsolutions.net/LocalOscillator/Measure */ +/* https://bcm-specs.sipsolutions.net/LocalOscillator/Measure */ void b43legacy_phy_lo_g_measure(struct b43legacy_wldev *dev) { static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 }; @@ -1721,7 +1721,7 @@ void b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev *dev) } } -/* http://bcm-specs.sipsolutions.net/EstimatePowerOut +/* https://bcm-specs.sipsolutions.net/EstimatePowerOut * This function converts a TSSI value to dBm in Q5.2 */ static s8 b43legacy_phy_estimate_power_out(struct b43legacy_wldev *dev, s8 tssi) @@ -1747,7 +1747,7 @@ static s8 b43legacy_phy_estimate_power_out(struct b43legacy_wldev *dev, s8 tssi) return dbm; } -/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ +/* https://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) { struct b43legacy_phy *phy = &dev->phy; diff --git a/drivers/net/wireless/broadcom/b43legacy/radio.c b/drivers/net/wireless/broadcom/b43legacy/radio.c index da40d1ca8723..06891b4f837b 100644 --- a/drivers/net/wireless/broadcom/b43legacy/radio.c +++ b/drivers/net/wireless/broadcom/b43legacy/radio.c @@ -313,14 +313,14 @@ u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev) return ret[channel - 1]; } -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */ void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val) { b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset); b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_DATA, (u16)val); } -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */ s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset) { u16 val; @@ -331,7 +331,7 @@ s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset) return (s16)val; } -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */ void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val) { u16 i; @@ -345,7 +345,7 @@ void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val) } } -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */ void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev) { struct b43legacy_phy *phy = &dev->phy; -- cgit v1.2.3 From 99aaa1aafa5c745c0d01f6f980f990ed0edd88ba Mon Sep 17 00:00:00 2001 From: Vaibhav Gupta Date: Tue, 21 Jul 2020 20:35:48 +0530 Subject: hostap: use generic power management Drivers using legacy power management .suspen()/.resume() callbacks have to manage PCI states and device's PM states themselves. They also need to take care of standard configuration registers. Switch to generic power management framework using a single "struct dev_pm_ops" variable to take the unnecessary load from the driver. This also avoids the need for the driver to directly call most of the PCI helper functions and device power state control functions as through the generic framework, PCI Core takes care of the necessary operations, and drivers are required to do only device-specific jobs. Signed-off-by: Vaibhav Gupta Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200721150547.371763-1-vaibhavgupta40@gmail.com --- drivers/net/wireless/intersil/hostap/hostap_hw.c | 6 ++-- drivers/net/wireless/intersil/hostap/hostap_pci.c | 34 +++++++---------------- 2 files changed, 13 insertions(+), 27 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intersil/hostap/hostap_hw.c b/drivers/net/wireless/intersil/hostap/hostap_hw.c index 2ab34cf74ecc..b6c497ce12e1 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_hw.c +++ b/drivers/net/wireless/intersil/hostap/hostap_hw.c @@ -3366,8 +3366,8 @@ static void prism2_free_local_data(struct net_device *dev) } -#if (defined(PRISM2_PCI) && defined(CONFIG_PM)) || defined(PRISM2_PCCARD) -static void prism2_suspend(struct net_device *dev) +#if defined(PRISM2_PCI) || defined(PRISM2_PCCARD) +static void __maybe_unused prism2_suspend(struct net_device *dev) { struct hostap_interface *iface; struct local_info *local; @@ -3385,7 +3385,7 @@ static void prism2_suspend(struct net_device *dev) /* Disable hardware and firmware */ prism2_hw_shutdown(dev, 0); } -#endif /* (PRISM2_PCI && CONFIG_PM) || PRISM2_PCCARD */ +#endif /* PRISM2_PCI || PRISM2_PCCARD */ /* These might at some point be compiled separately and used as separate diff --git a/drivers/net/wireless/intersil/hostap/hostap_pci.c b/drivers/net/wireless/intersil/hostap/hostap_pci.c index 0c2aa880e32a..101887e6bd0f 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_pci.c +++ b/drivers/net/wireless/intersil/hostap/hostap_pci.c @@ -403,36 +403,23 @@ static void prism2_pci_remove(struct pci_dev *pdev) pci_disable_device(pdev); } - -#ifdef CONFIG_PM -static int prism2_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused prism2_pci_suspend(struct device *dev_d) { - struct net_device *dev = pci_get_drvdata(pdev); + struct net_device *dev = dev_get_drvdata(dev_d); if (netif_running(dev)) { netif_stop_queue(dev); netif_device_detach(dev); } prism2_suspend(dev); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); return 0; } -static int prism2_pci_resume(struct pci_dev *pdev) +static int __maybe_unused prism2_pci_resume(struct device *dev_d) { - struct net_device *dev = pci_get_drvdata(pdev); - int err; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR "%s: pci_enable_device failed on resume\n", - dev->name); - return err; - } - pci_restore_state(pdev); + struct net_device *dev = dev_get_drvdata(dev_d); + prism2_hw_config(dev, 0); if (netif_running(dev)) { netif_device_attach(dev); @@ -441,20 +428,19 @@ static int prism2_pci_resume(struct pci_dev *pdev) return 0; } -#endif /* CONFIG_PM */ - MODULE_DEVICE_TABLE(pci, prism2_pci_id_table); +static SIMPLE_DEV_PM_OPS(prism2_pci_pm_ops, + prism2_pci_suspend, + prism2_pci_resume); + static struct pci_driver prism2_pci_driver = { .name = "hostap_pci", .id_table = prism2_pci_id_table, .probe = prism2_pci_probe, .remove = prism2_pci_remove, -#ifdef CONFIG_PM - .suspend = prism2_pci_suspend, - .resume = prism2_pci_resume, -#endif /* CONFIG_PM */ + .driver.pm = &prism2_pci_pm_ops, }; module_pci_driver(prism2_pci_driver); -- cgit v1.2.3 From 9130559cf8dbc34b3d54a2ab5f2a746b964c46a4 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 22 Jul 2020 12:17:01 +0200 Subject: ipw2100: Use GFP_KERNEL instead of GFP_ATOMIC in some memory allocation The call chain is: ipw2100_pci_init_one (the probe function) --> ipw2100_queues_allocate --> ipw2100_tx_allocate No lock is taken in the between. So it is safe to use GFP_KERNEL in 'ipw2100_tx_allocate()'. BTW, 'ipw2100_queues_allocate()' also calls 'ipw2100_msg_allocate()' which already allocates some memory using GFP_KERNEL. Signed-off-by: Christophe JAILLET Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200722101701.26126-1-christophe.jaillet@wanadoo.fr --- drivers/net/wireless/intel/ipw2x00/ipw2100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index 83d2f2acc0de..699deca745a2 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -4430,7 +4430,7 @@ static int ipw2100_tx_allocate(struct ipw2100_priv *priv) priv->tx_buffers = kmalloc_array(TX_PENDED_QUEUE_LENGTH, sizeof(struct ipw2100_tx_packet), - GFP_ATOMIC); + GFP_KERNEL); if (!priv->tx_buffers) { bd_queue_free(priv, &priv->tx_queue); return -ENOMEM; -- cgit v1.2.3 From e52525c0c320076deab35409a6b2cff6388959b8 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 22 Jul 2020 12:17:16 +0200 Subject: ipw2x00: switch from 'pci_' to 'dma_' API The wrappers in include/linux/pci-dma-compat.h should go away. The patch has been generated with the coccinelle script below and has been hand modified to replace GFP_ with a correct flag. It has been compile tested. When memory is allocated in 'ipw2100_msg_allocate()' (ipw2100.c), GFP_KERNEL can be used because it is called from the probe function. The call chain is: ipw2100_pci_init_one (the probe function) --> ipw2100_queues_allocate --> ipw2100_msg_allocate Moreover, 'ipw2100_msg_allocate()' already uses GFP_KERNEL for some other memory allocations. When memory is allocated in 'status_queue_allocate()' (ipw2100.c), GFP_KERNEL can be used because it is called from the probe function. The call chain is: ipw2100_pci_init_one (the probe function) --> ipw2100_queues_allocate --> ipw2100_rx_allocate --> status_queue_allocate Moreover, 'ipw2100_rx_allocate()' already uses GFP_KERNEL for some other memory allocations. When memory is allocated in 'bd_queue_allocate()' (ipw2100.c), GFP_KERNEL can be used because it is called from the probe function. The call chain is: ipw2100_pci_init_one (the probe function) --> ipw2100_queues_allocate --> ipw2100_rx_allocate --> bd_queue_allocate Moreover, 'ipw2100_rx_allocate()' already uses GFP_KERNEL for some other memory allocations. When memory is allocated in 'ipw2100_tx_allocate()' (ipw2100.c), GFP_KERNEL can be used because it is called from the probe function. The call chain is: ipw2100_pci_init_one (the probe function) --> ipw2100_queues_allocate --> ipw2100_tx_allocate Moreover, 'ipw2100_tx_allocate()' already uses GFP_KERNEL for some other memory allocations. When memory is allocated in 'ipw_queue_tx_init()' (ipw2200.c), GFP_KERNEL can be used because it is called from a call chain that already uses GFP_KERNEL and no spin_lock is taken in the between. The call chain is: ipw_up --> ipw_load --> ipw_queue_reset --> ipw_queue_tx_init 'ipw_up()' already uses GFP_KERNEL for some other memory allocations. @@ @@ - PCI_DMA_BIDIRECTIONAL + DMA_BIDIRECTIONAL @@ @@ - PCI_DMA_TODEVICE + DMA_TO_DEVICE @@ @@ - PCI_DMA_FROMDEVICE + DMA_FROM_DEVICE @@ @@ - PCI_DMA_NONE + DMA_NONE @@ expression e1, e2, e3; @@ - pci_alloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3; @@ - pci_zalloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3, e4; @@ - pci_free_consistent(e1, e2, e3, e4) + dma_free_coherent(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_single(e1, e2, e3, e4) + dma_map_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_single(e1, e2, e3, e4) + dma_unmap_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4, e5; @@ - pci_map_page(e1, e2, e3, e4, e5) + dma_map_page(&e1->dev, e2, e3, e4, e5) @@ expression e1, e2, e3, e4; @@ - pci_unmap_page(e1, e2, e3, e4) + dma_unmap_page(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_sg(e1, e2, e3, e4) + dma_map_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_sg(e1, e2, e3, e4) + dma_unmap_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_cpu(e1, e2, e3, e4) + dma_sync_single_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_device(e1, e2, e3, e4) + dma_sync_single_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_cpu(e1, e2, e3, e4) + dma_sync_sg_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_device(e1, e2, e3, e4) + dma_sync_sg_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2; @@ - pci_dma_mapping_error(e1, e2) + dma_mapping_error(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_dma_mask(e1, e2) + dma_set_mask(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_consistent_dma_mask(e1, e2) + dma_set_coherent_mask(&e1->dev, e2) Signed-off-by: Christophe JAILLET Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200722101716.26185-1-christophe.jaillet@wanadoo.fr --- drivers/net/wireless/intel/ipw2x00/ipw2100.c | 121 +++++++++++++-------------- drivers/net/wireless/intel/ipw2x00/ipw2200.c | 56 +++++++------ 2 files changed, 88 insertions(+), 89 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index 699deca745a2..461e955aa259 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -2295,10 +2295,11 @@ static int ipw2100_alloc_skb(struct ipw2100_priv *priv, return -ENOMEM; packet->rxp = (struct ipw2100_rx *)packet->skb->data; - packet->dma_addr = pci_map_single(priv->pci_dev, packet->skb->data, + packet->dma_addr = dma_map_single(&priv->pci_dev->dev, + packet->skb->data, sizeof(struct ipw2100_rx), - PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(priv->pci_dev, packet->dma_addr)) { + DMA_FROM_DEVICE); + if (dma_mapping_error(&priv->pci_dev->dev, packet->dma_addr)) { dev_kfree_skb(packet->skb); return -ENOMEM; } @@ -2479,9 +2480,8 @@ static void isr_rx(struct ipw2100_priv *priv, int i, return; } - pci_unmap_single(priv->pci_dev, - packet->dma_addr, - sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pci_dev->dev, packet->dma_addr, + sizeof(struct ipw2100_rx), DMA_FROM_DEVICE); skb_put(packet->skb, status->frame_size); @@ -2563,8 +2563,8 @@ static void isr_rx_monitor(struct ipw2100_priv *priv, int i, return; } - pci_unmap_single(priv->pci_dev, packet->dma_addr, - sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pci_dev->dev, packet->dma_addr, + sizeof(struct ipw2100_rx), DMA_FROM_DEVICE); memmove(packet->skb->data + sizeof(struct ipw_rt_hdr), packet->skb->data, status->frame_size); @@ -2689,9 +2689,9 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv) /* Sync the DMA for the RX buffer so CPU is sure to get * the correct values */ - pci_dma_sync_single_for_cpu(priv->pci_dev, packet->dma_addr, - sizeof(struct ipw2100_rx), - PCI_DMA_FROMDEVICE); + dma_sync_single_for_cpu(&priv->pci_dev->dev, packet->dma_addr, + sizeof(struct ipw2100_rx), + DMA_FROM_DEVICE); if (unlikely(ipw2100_corruption_check(priv, i))) { ipw2100_corruption_detected(priv, i); @@ -2923,9 +2923,8 @@ static int __ipw2100_tx_process(struct ipw2100_priv *priv) (packet->index + 1 + i) % txq->entries, tbd->host_addr, tbd->buf_length); - pci_unmap_single(priv->pci_dev, - tbd->host_addr, - tbd->buf_length, PCI_DMA_TODEVICE); + dma_unmap_single(&priv->pci_dev->dev, tbd->host_addr, + tbd->buf_length, DMA_TO_DEVICE); } libipw_txb_free(packet->info.d_struct.txb); @@ -3165,15 +3164,13 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) tbd->buf_length = packet->info.d_struct.txb-> fragments[i]->len - LIBIPW_3ADDR_LEN; - tbd->host_addr = pci_map_single(priv->pci_dev, + tbd->host_addr = dma_map_single(&priv->pci_dev->dev, packet->info.d_struct. - txb->fragments[i]-> - data + + txb->fragments[i]->data + LIBIPW_3ADDR_LEN, tbd->buf_length, - PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(priv->pci_dev, - tbd->host_addr)) { + DMA_TO_DEVICE); + if (dma_mapping_error(&priv->pci_dev->dev, tbd->host_addr)) { IPW_DEBUG_TX("dma mapping error\n"); break; } @@ -3182,10 +3179,10 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) txq->next, tbd->host_addr, tbd->buf_length); - pci_dma_sync_single_for_device(priv->pci_dev, - tbd->host_addr, - tbd->buf_length, - PCI_DMA_TODEVICE); + dma_sync_single_for_device(&priv->pci_dev->dev, + tbd->host_addr, + tbd->buf_length, + DMA_TO_DEVICE); txq->next++; txq->next %= txq->entries; @@ -3440,9 +3437,9 @@ static int ipw2100_msg_allocate(struct ipw2100_priv *priv) return -ENOMEM; for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) { - v = pci_zalloc_consistent(priv->pci_dev, - sizeof(struct ipw2100_cmd_header), - &p); + v = dma_alloc_coherent(&priv->pci_dev->dev, + sizeof(struct ipw2100_cmd_header), &p, + GFP_KERNEL); if (!v) { printk(KERN_ERR DRV_NAME ": " "%s: PCI alloc failed for msg " @@ -3461,11 +3458,10 @@ static int ipw2100_msg_allocate(struct ipw2100_priv *priv) return 0; for (j = 0; j < i; j++) { - pci_free_consistent(priv->pci_dev, - sizeof(struct ipw2100_cmd_header), - priv->msg_buffers[j].info.c_struct.cmd, - priv->msg_buffers[j].info.c_struct. - cmd_phys); + dma_free_coherent(&priv->pci_dev->dev, + sizeof(struct ipw2100_cmd_header), + priv->msg_buffers[j].info.c_struct.cmd, + priv->msg_buffers[j].info.c_struct.cmd_phys); } kfree(priv->msg_buffers); @@ -3496,11 +3492,10 @@ static void ipw2100_msg_free(struct ipw2100_priv *priv) return; for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) { - pci_free_consistent(priv->pci_dev, - sizeof(struct ipw2100_cmd_header), - priv->msg_buffers[i].info.c_struct.cmd, - priv->msg_buffers[i].info.c_struct. - cmd_phys); + dma_free_coherent(&priv->pci_dev->dev, + sizeof(struct ipw2100_cmd_header), + priv->msg_buffers[i].info.c_struct.cmd, + priv->msg_buffers[i].info.c_struct.cmd_phys); } kfree(priv->msg_buffers); @@ -4323,7 +4318,8 @@ static int status_queue_allocate(struct ipw2100_priv *priv, int entries) IPW_DEBUG_INFO("enter\n"); q->size = entries * sizeof(struct ipw2100_status); - q->drv = pci_zalloc_consistent(priv->pci_dev, q->size, &q->nic); + q->drv = dma_alloc_coherent(&priv->pci_dev->dev, q->size, &q->nic, + GFP_KERNEL); if (!q->drv) { IPW_DEBUG_WARNING("Can not allocate status queue.\n"); return -ENOMEM; @@ -4339,9 +4335,10 @@ static void status_queue_free(struct ipw2100_priv *priv) IPW_DEBUG_INFO("enter\n"); if (priv->status_queue.drv) { - pci_free_consistent(priv->pci_dev, priv->status_queue.size, - priv->status_queue.drv, - priv->status_queue.nic); + dma_free_coherent(&priv->pci_dev->dev, + priv->status_queue.size, + priv->status_queue.drv, + priv->status_queue.nic); priv->status_queue.drv = NULL; } @@ -4357,7 +4354,8 @@ static int bd_queue_allocate(struct ipw2100_priv *priv, q->entries = entries; q->size = entries * sizeof(struct ipw2100_bd); - q->drv = pci_zalloc_consistent(priv->pci_dev, q->size, &q->nic); + q->drv = dma_alloc_coherent(&priv->pci_dev->dev, q->size, &q->nic, + GFP_KERNEL); if (!q->drv) { IPW_DEBUG_INFO ("can't allocate shared memory for buffer descriptors\n"); @@ -4377,7 +4375,8 @@ static void bd_queue_free(struct ipw2100_priv *priv, struct ipw2100_bd_queue *q) return; if (q->drv) { - pci_free_consistent(priv->pci_dev, q->size, q->drv, q->nic); + dma_free_coherent(&priv->pci_dev->dev, q->size, q->drv, + q->nic); q->drv = NULL; } @@ -4437,9 +4436,9 @@ static int ipw2100_tx_allocate(struct ipw2100_priv *priv) } for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) { - v = pci_alloc_consistent(priv->pci_dev, - sizeof(struct ipw2100_data_header), - &p); + v = dma_alloc_coherent(&priv->pci_dev->dev, + sizeof(struct ipw2100_data_header), &p, + GFP_KERNEL); if (!v) { printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for tx " "buffers.\n", @@ -4459,11 +4458,10 @@ static int ipw2100_tx_allocate(struct ipw2100_priv *priv) return 0; for (j = 0; j < i; j++) { - pci_free_consistent(priv->pci_dev, - sizeof(struct ipw2100_data_header), - priv->tx_buffers[j].info.d_struct.data, - priv->tx_buffers[j].info.d_struct. - data_phys); + dma_free_coherent(&priv->pci_dev->dev, + sizeof(struct ipw2100_data_header), + priv->tx_buffers[j].info.d_struct.data, + priv->tx_buffers[j].info.d_struct.data_phys); } kfree(priv->tx_buffers); @@ -4540,12 +4538,10 @@ static void ipw2100_tx_free(struct ipw2100_priv *priv) priv->tx_buffers[i].info.d_struct.txb = NULL; } if (priv->tx_buffers[i].info.d_struct.data) - pci_free_consistent(priv->pci_dev, - sizeof(struct ipw2100_data_header), - priv->tx_buffers[i].info.d_struct. - data, - priv->tx_buffers[i].info.d_struct. - data_phys); + dma_free_coherent(&priv->pci_dev->dev, + sizeof(struct ipw2100_data_header), + priv->tx_buffers[i].info.d_struct.data, + priv->tx_buffers[i].info.d_struct.data_phys); } kfree(priv->tx_buffers); @@ -4608,9 +4604,10 @@ static int ipw2100_rx_allocate(struct ipw2100_priv *priv) return 0; for (j = 0; j < i; j++) { - pci_unmap_single(priv->pci_dev, priv->rx_buffers[j].dma_addr, + dma_unmap_single(&priv->pci_dev->dev, + priv->rx_buffers[j].dma_addr, sizeof(struct ipw2100_rx_packet), - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); dev_kfree_skb(priv->rx_buffers[j].skb); } @@ -4662,10 +4659,10 @@ static void ipw2100_rx_free(struct ipw2100_priv *priv) for (i = 0; i < RX_QUEUE_LENGTH; i++) { if (priv->rx_buffers[i].rxp) { - pci_unmap_single(priv->pci_dev, + dma_unmap_single(&priv->pci_dev->dev, priv->rx_buffers[i].dma_addr, sizeof(struct ipw2100_rx), - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); dev_kfree_skb(priv->rx_buffers[i].skb); } } @@ -6196,7 +6193,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, pci_set_master(pci_dev); pci_set_drvdata(pci_dev, priv); - err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); + err = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32)); if (err) { printk(KERN_WARNING DRV_NAME "Error calling pci_set_dma_mask.\n"); diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index 39ff3a426092..129ef2f6248a 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -3442,8 +3442,9 @@ static void ipw_rx_queue_reset(struct ipw_priv *priv, /* In the reset function, these buffers may have been allocated * to an SKB, so we need to unmap and free potential storage */ if (rxq->pool[i].skb != NULL) { - pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr, - IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pci_dev->dev, + rxq->pool[i].dma_addr, + IPW_RX_BUF_SIZE, DMA_FROM_DEVICE); dev_kfree_skb(rxq->pool[i].skb); rxq->pool[i].skb = NULL; } @@ -3774,7 +3775,8 @@ static int ipw_queue_tx_init(struct ipw_priv *priv, return -ENOMEM; q->bd = - pci_alloc_consistent(dev, sizeof(q->bd[0]) * count, &q->q.dma_addr); + dma_alloc_coherent(&dev->dev, sizeof(q->bd[0]) * count, + &q->q.dma_addr, GFP_KERNEL); if (!q->bd) { IPW_ERROR("pci_alloc_consistent(%zd) failed\n", sizeof(q->bd[0]) * count); @@ -3816,9 +3818,10 @@ static void ipw_queue_tx_free_tfd(struct ipw_priv *priv, /* unmap chunks if any */ for (i = 0; i < le32_to_cpu(bd->u.data.num_chunks); i++) { - pci_unmap_single(dev, le32_to_cpu(bd->u.data.chunk_ptr[i]), + dma_unmap_single(&dev->dev, + le32_to_cpu(bd->u.data.chunk_ptr[i]), le16_to_cpu(bd->u.data.chunk_len[i]), - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); if (txq->txb[txq->q.last_used]) { libipw_txb_free(txq->txb[txq->q.last_used]); txq->txb[txq->q.last_used] = NULL; @@ -3850,8 +3853,8 @@ static void ipw_queue_tx_free(struct ipw_priv *priv, struct clx2_tx_queue *txq) } /* free buffers belonging to queue itself */ - pci_free_consistent(dev, sizeof(txq->bd[0]) * q->n_bd, txq->bd, - q->dma_addr); + dma_free_coherent(&dev->dev, sizeof(txq->bd[0]) * q->n_bd, txq->bd, + q->dma_addr); kfree(txq->txb); /* 0 fill whole structure */ @@ -5196,8 +5199,8 @@ static void ipw_rx_queue_replenish(void *data) list_del(element); rxb->dma_addr = - pci_map_single(priv->pci_dev, rxb->skb->data, - IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + dma_map_single(&priv->pci_dev->dev, rxb->skb->data, + IPW_RX_BUF_SIZE, DMA_FROM_DEVICE); list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; @@ -5230,8 +5233,9 @@ static void ipw_rx_queue_free(struct ipw_priv *priv, struct ipw_rx_queue *rxq) for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { if (rxq->pool[i].skb != NULL) { - pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr, - IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pci_dev->dev, + rxq->pool[i].dma_addr, + IPW_RX_BUF_SIZE, DMA_FROM_DEVICE); dev_kfree_skb(rxq->pool[i].skb); } } @@ -8263,9 +8267,8 @@ static void ipw_rx(struct ipw_priv *priv) } priv->rxq->queue[i] = NULL; - pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr, - IPW_RX_BUF_SIZE, - PCI_DMA_FROMDEVICE); + dma_sync_single_for_cpu(&priv->pci_dev->dev, rxb->dma_addr, + IPW_RX_BUF_SIZE, DMA_FROM_DEVICE); pkt = (struct ipw_rx_packet *)rxb->skb->data; IPW_DEBUG_RX("Packet: type=%02X seq=%02X bits=%02X\n", @@ -8417,8 +8420,8 @@ static void ipw_rx(struct ipw_priv *priv) rxb->skb = NULL; } - pci_unmap_single(priv->pci_dev, rxb->dma_addr, - IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pci_dev->dev, rxb->dma_addr, + IPW_RX_BUF_SIZE, DMA_FROM_DEVICE); list_add_tail(&rxb->list, &priv->rxq->rx_used); i = (i + 1) % RX_QUEUE_SIZE; @@ -10217,11 +10220,10 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct libipw_txb *txb, txb->fragments[i]->len - hdr_len); tfd->u.data.chunk_ptr[i] = - cpu_to_le32(pci_map_single - (priv->pci_dev, - txb->fragments[i]->data + hdr_len, - txb->fragments[i]->len - hdr_len, - PCI_DMA_TODEVICE)); + cpu_to_le32(dma_map_single(&priv->pci_dev->dev, + txb->fragments[i]->data + hdr_len, + txb->fragments[i]->len - hdr_len, + DMA_TO_DEVICE)); tfd->u.data.chunk_len[i] = cpu_to_le16(txb->fragments[i]->len - hdr_len); } @@ -10251,10 +10253,10 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct libipw_txb *txb, dev_kfree_skb_any(txb->fragments[i]); txb->fragments[i] = skb; tfd->u.data.chunk_ptr[i] = - cpu_to_le32(pci_map_single - (priv->pci_dev, skb->data, - remaining_bytes, - PCI_DMA_TODEVICE)); + cpu_to_le32(dma_map_single(&priv->pci_dev->dev, + skb->data, + remaining_bytes, + DMA_TO_DEVICE)); le32_add_cpu(&tfd->u.data.num_chunks, 1); } @@ -11620,9 +11622,9 @@ static int ipw_pci_probe(struct pci_dev *pdev, pci_set_master(pdev); - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (err) { printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n"); goto out_pci_disable_device; -- cgit v1.2.3 From 141bc9abbbffa89d020957caa9ac4a61d0ef1e26 Mon Sep 17 00:00:00 2001 From: Wang Hai Date: Thu, 30 Jul 2020 14:49:10 +0800 Subject: qtnfmac: Missing platform_device_unregister() on error in qtnf_core_mac_alloc() Add the missing platform_device_unregister() before return from qtnf_core_mac_alloc() in the error handling case. Fixes: 616f5701f4ab ("qtnfmac: assign each wiphy to its own virtual platform device") Reported-by: Hulk Robot Signed-off-by: Wang Hai Reviewed-by: Sergey Matyukevich Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200730064910.37589-1-wanghai38@huawei.com --- drivers/net/wireless/quantenna/qtnfmac/core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c index eea777f8acea..6aafff9d4231 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.c +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -446,8 +446,11 @@ static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus, } wiphy = qtnf_wiphy_allocate(bus, pdev); - if (!wiphy) + if (!wiphy) { + if (pdev) + platform_device_unregister(pdev); return ERR_PTR(-ENOMEM); + } mac = wiphy_priv(wiphy); -- cgit v1.2.3 From 4dd9e7e08bc39ef34be40be8a0ddc6469fec8ff6 Mon Sep 17 00:00:00 2001 From: Flavio Suligoi Date: Thu, 23 Jul 2020 15:52:54 +0200 Subject: intersil: fix wiki website url In some Intersil files, the wiki url is still the old "wireless.kernel.org" instead of the new "wireless.wiki.kernel.org" Signed-off-by: Flavio Suligoi Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200723135254.594984-1-f.suligoi@asem.it --- drivers/net/wireless/intersil/Kconfig | 2 +- drivers/net/wireless/intersil/p54/Kconfig | 6 +++--- drivers/net/wireless/intersil/p54/fwio.c | 2 +- drivers/net/wireless/intersil/p54/p54usb.c | 2 +- drivers/net/wireless/intersil/prism54/islpci_hotplug.c | 3 ++- 5 files changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intersil/Kconfig b/drivers/net/wireless/intersil/Kconfig index 6a6ce9d4aeee..c52d9b535623 100644 --- a/drivers/net/wireless/intersil/Kconfig +++ b/drivers/net/wireless/intersil/Kconfig @@ -30,7 +30,7 @@ config PRISM54 For more information refer to the p54 wiki: - http://wireless.kernel.org/en/users/Drivers/p54 + http://wireless.wiki.kernel.org/en/users/Drivers/p54 Note: You need a motherboard with DMA support to use any of these cards diff --git a/drivers/net/wireless/intersil/p54/Kconfig b/drivers/net/wireless/intersil/p54/Kconfig index 024be5507daf..003c378ed131 100644 --- a/drivers/net/wireless/intersil/p54/Kconfig +++ b/drivers/net/wireless/intersil/p54/Kconfig @@ -10,7 +10,7 @@ config P54_COMMON also need to be enabled in order to support any devices. These devices require softmac firmware which can be found at - + If you choose to build a module, it'll be called p54common. @@ -22,7 +22,7 @@ config P54_USB This driver is for USB isl38xx based wireless cards. These devices require softmac firmware which can be found at - + If you choose to build a module, it'll be called p54usb. @@ -36,7 +36,7 @@ config P54_PCI supported by the fullmac driver/firmware. This driver requires softmac firmware which can be found at - + If you choose to build a module, it'll be called p54pci. diff --git a/drivers/net/wireless/intersil/p54/fwio.c b/drivers/net/wireless/intersil/p54/fwio.c index a5afcc865196..bece14e4ff0d 100644 --- a/drivers/net/wireless/intersil/p54/fwio.c +++ b/drivers/net/wireless/intersil/p54/fwio.c @@ -132,7 +132,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) if (priv->fw_var < 0x500) wiphy_info(priv->hw->wiphy, "you are using an obsolete firmware. " - "visit http://wireless.kernel.org/en/users/Drivers/p54 " + "visit http://wireless.wiki.kernel.org/en/users/Drivers/p54 " "and grab one for \"kernel >= 2.6.28\"!\n"); if (priv->fw_var >= 0x300) { diff --git a/drivers/net/wireless/intersil/p54/p54usb.c b/drivers/net/wireless/intersil/p54/p54usb.c index ff0e30c0c14c..cae47663b17b 100644 --- a/drivers/net/wireless/intersil/p54/p54usb.c +++ b/drivers/net/wireless/intersil/p54/p54usb.c @@ -36,7 +36,7 @@ static struct usb_driver p54u_driver; * Note: * * Always update our wiki's device list (located at: - * http://wireless.kernel.org/en/users/Drivers/p54/devices ), + * http://wireless.wiki.kernel.org/en/users/Drivers/p54/devices ), * whenever you add a new device. */ diff --git a/drivers/net/wireless/intersil/prism54/islpci_hotplug.c b/drivers/net/wireless/intersil/prism54/islpci_hotplug.c index f30a79a0b9c7..31a1e61326ff 100644 --- a/drivers/net/wireless/intersil/prism54/islpci_hotplug.c +++ b/drivers/net/wireless/intersil/prism54/islpci_hotplug.c @@ -26,7 +26,8 @@ module_param(init_pcitm, int, 0); /* In this order: vendor, device, subvendor, subdevice, class, class_mask, * driver_data * If you have an update for this please contact prism54-devel@prism54.org - * The latest list can be found at http://wireless.kernel.org/en/users/Drivers/p54 */ + * The latest list can be found at http://wireless.wiki.kernel.org/en/users/Drivers/p54 + */ static const struct pci_device_id prism54_id_tbl[] = { /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */ { -- cgit v1.2.3 From c3ab1804b168867974a4da541f6e77487a1074f5 Mon Sep 17 00:00:00 2001 From: Vaibhav Gupta Date: Tue, 28 Jul 2020 17:11:28 +0530 Subject: airo: use generic power management Drivers using legacy power management .suspen()/.resume() callbacks have to manage PCI states and device's PM states themselves. They also need to take care of standard configuration registers. Switch to generic power management framework using a single "struct dev_pm_ops" variable to take the unnecessary load from the driver. This also avoids the need for the driver to directly call most of the PCI helper functions and device power state control functions, as through the generic framework PCI Core takes care of the necessary operations, and drivers are required to do only device-specific jobs. Signed-off-by: Vaibhav Gupta Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200728114128.1218310-1-vaibhavgupta40@gmail.com --- drivers/net/wireless/cisco/airo.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c index 726cb1bc86cd..316672486d82 100644 --- a/drivers/net/wireless/cisco/airo.c +++ b/drivers/net/wireless/cisco/airo.c @@ -74,16 +74,19 @@ MODULE_DEVICE_TABLE(pci, card_ids); static int airo_pci_probe(struct pci_dev *, const struct pci_device_id *); static void airo_pci_remove(struct pci_dev *); -static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state); -static int airo_pci_resume(struct pci_dev *pdev); +static int __maybe_unused airo_pci_suspend(struct device *dev); +static int __maybe_unused airo_pci_resume(struct device *dev); + +static SIMPLE_DEV_PM_OPS(airo_pci_pm_ops, + airo_pci_suspend, + airo_pci_resume); static struct pci_driver airo_driver = { - .name = DRV_NAME, - .id_table = card_ids, - .probe = airo_pci_probe, - .remove = airo_pci_remove, - .suspend = airo_pci_suspend, - .resume = airo_pci_resume, + .name = DRV_NAME, + .id_table = card_ids, + .probe = airo_pci_probe, + .remove = airo_pci_remove, + .driver.pm = &airo_pci_pm_ops, }; #endif /* CONFIG_PCI */ @@ -5573,9 +5576,9 @@ static void airo_pci_remove(struct pci_dev *pdev) pci_disable_device(pdev); } -static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused airo_pci_suspend(struct device *dev_d) { - struct net_device *dev = pci_get_drvdata(pdev); + struct net_device *dev = dev_get_drvdata(dev_d); struct airo_info *ai = dev->ml_priv; Cmd cmd; Resp rsp; @@ -5591,25 +5594,21 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) return -EAGAIN; disable_MAC(ai, 0); netif_device_detach(dev); - ai->power = state; + ai->power = PMSG_SUSPEND; cmd.cmd = HOSTSLEEP; issuecommand(ai, &cmd, &rsp); - pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); - pci_save_state(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + device_wakeup_enable(dev_d); return 0; } -static int airo_pci_resume(struct pci_dev *pdev) +static int __maybe_unused airo_pci_resume(struct device *dev_d) { - struct net_device *dev = pci_get_drvdata(pdev); + struct net_device *dev = dev_get_drvdata(dev_d); struct airo_info *ai = dev->ml_priv; - pci_power_t prev_state = pdev->current_state; + pci_power_t prev_state = to_pci_dev(dev_d)->current_state; - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - pci_enable_wake(pdev, PCI_D0, 0); + device_wakeup_disable(dev_d); if (prev_state != PCI_D1) { reset_card(dev, 0); -- cgit v1.2.3 From 20e6421344b5bc2f97b8e2db47b6994368417904 Mon Sep 17 00:00:00 2001 From: Wang Hai Date: Thu, 30 Jul 2020 15:39:39 +0800 Subject: wl1251: fix always return 0 error wl1251_event_ps_report() should not always return 0 because wl1251_ps_set_mode() may fail. Change it to return 'ret'. Fixes: f7ad1eed4d4b ("wl1251: retry power save entry") Reported-by: Hulk Robot Signed-off-by: Wang Hai Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200730073939.33704-1-wanghai38@huawei.com --- drivers/net/wireless/ti/wl1251/event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ti/wl1251/event.c b/drivers/net/wireless/ti/wl1251/event.c index 850864dbafa1..e6d426edab56 100644 --- a/drivers/net/wireless/ti/wl1251/event.c +++ b/drivers/net/wireless/ti/wl1251/event.c @@ -70,7 +70,7 @@ static int wl1251_event_ps_report(struct wl1251 *wl, break; } - return 0; + return ret; } static void wl1251_event_mbox_dump(struct event_mailbox *mbox) -- cgit v1.2.3 From 3dc05ffb04436020f63138186dbc4f37bd938552 Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Tue, 21 Jul 2020 13:23:02 +0200 Subject: brcmfmac: Set timeout value when configuring power save Set the timeout value as per cfg80211's set_power_mgmt() request. If the requested value value is left undefined we set it to 2 seconds, the maximum supported value. Signed-off-by: Nicolas Saenz Julienne Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200721112302.22718-1-nsaenzjulienne@suse.de --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 5d99771c3f64..ab0da2ff982e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -84,6 +84,8 @@ #define BRCMF_ND_INFO_TIMEOUT msecs_to_jiffies(2000) +#define BRCMF_PS_MAX_TIMEOUT_MS 2000 + #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ (sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) @@ -2942,6 +2944,12 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, else bphy_err(drvr, "error (%d)\n", err); } + + err = brcmf_fil_iovar_int_set(ifp, "pm2_sleep_ret", + min_t(u32, timeout, BRCMF_PS_MAX_TIMEOUT_MS)); + if (err) + bphy_err(drvr, "Unable to set pm timeout, (%d)\n", err); + done: brcmf_dbg(TRACE, "Exit\n"); return err; -- cgit v1.2.3