From 8f9ed93d09a97444733d492a3bbf66bcb786a777 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 15 Jun 2020 20:28:59 +0300 Subject: ath10k: Wait until copy complete is actually done before completing On wcn3990 we have "per_ce_irq = true". That makes the ath10k_ce_interrupt_summary() function always return 0xfff. The ath10k_ce_per_engine_service_any() function will see this and think that _all_ copy engines have an interrupt. Without checking, the ath10k_ce_per_engine_service() assumes that if it's called that the "copy complete" (cc) interrupt fired. This combination seems bad. Let's add a check to make sure that the "copy complete" interrupt actually fired in ath10k_ce_per_engine_service(). This might fix a hard-to-reproduce failure where it appears that the copy complete handlers run before the copy is really complete. Specifically a symptom was that we were seeing this on a Qualcomm sc7180 board: arm-smmu 15000000.iommu: Unhandled context fault: fsr=0x402, iova=0x7fdd45780, fsynr=0x30003, cbfrsynra=0xc1, cb=10 Even on platforms that don't have wcn3990 this still seems like it would be a sane thing to do. Specifically the current IRQ handler comments indicate that there might be other misc interrupt sources firing that need to be cleared. If one of those sources was the one that caused the IRQ handler to be called it would also be important to double-check that the interrupt we cared about actually fired. Tested-on: WCN3990 SNOC WLAN.HL.3.2.2-00490-QCAHLSWMTPL-1 Signed-off-by: Douglas Anderson Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200609082015.1.Ife398994e5a0a6830e4d4a16306ef36e0144e7ba@changeid --- drivers/net/wireless/ath/ath10k/ce.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 294fbc1e89ab..ffdd4b995f33 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -481,6 +481,15 @@ static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar, ath10k_ce_write32(ar, ce_ctrl_addr + wm_regs->addr, mask); } +static inline bool ath10k_ce_engine_int_status_check(struct ath10k *ar, + u32 ce_ctrl_addr, + unsigned int mask) +{ + struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs; + + return ath10k_ce_read32(ar, ce_ctrl_addr + wm_regs->addr) & mask; +} + /* * Guts of ath10k_ce_send. * The caller takes responsibility for any needed locking. @@ -1301,19 +1310,22 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) spin_lock_bh(&ce->ce_lock); - /* Clear the copy-complete interrupts that will be handled here. */ - ath10k_ce_engine_int_status_clear(ar, ctrl_addr, - wm_regs->cc_mask); + if (ath10k_ce_engine_int_status_check(ar, ctrl_addr, + wm_regs->cc_mask)) { + /* Clear before handling */ + ath10k_ce_engine_int_status_clear(ar, ctrl_addr, + wm_regs->cc_mask); - spin_unlock_bh(&ce->ce_lock); + spin_unlock_bh(&ce->ce_lock); - if (ce_state->recv_cb) - ce_state->recv_cb(ce_state); + if (ce_state->recv_cb) + ce_state->recv_cb(ce_state); - if (ce_state->send_cb) - ce_state->send_cb(ce_state); + if (ce_state->send_cb) + ce_state->send_cb(ce_state); - spin_lock_bh(&ce->ce_lock); + spin_lock_bh(&ce->ce_lock); + } /* * Misc CE interrupts are not being handled, but still need -- cgit v1.2.3 From 67b927f9820847d30e97510b2f00cd142b9559b6 Mon Sep 17 00:00:00 2001 From: Venkateswara Naralasetty Date: Mon, 15 Jun 2020 20:29:01 +0300 Subject: ath10k: fix retry packets update in station dump When tx status enabled, retry count is updated from tx completion status. which is not working as expected due to firmware limitation where firmware can not provide per MSDU rate statistics from tx completion status. Due to this tx retry count is always 0 in station dump. Fix this issue by updating the retry packet count from per peer statistics. This patch will not break on SDIO devices since, this retry count is already updating from peer statistics for SDIO devices. Tested-on: QCA9984 PCI 10.4-3.6-00104 Tested-on: QCA9882 PCI 10.2.4-1.0-00047 Signed-off-by: Venkateswara Naralasetty Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1591856446-26977-1-git-send-email-vnaralas@codeaurora.org --- drivers/net/wireless/ath/ath10k/htt_rx.c | 8 +++++--- drivers/net/wireless/ath/ath10k/mac.c | 5 +++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index d787cbead56a..cac05e7bb6b0 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -3575,12 +3575,14 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar, } if (ar->htt.disable_tx_comp) { - arsta->tx_retries += peer_stats->retry_pkts; arsta->tx_failed += peer_stats->failed_pkts; - ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx retries %d tx failed %d\n", - arsta->tx_retries, arsta->tx_failed); + ath10k_dbg(ar, ATH10K_DBG_HTT, "tx failed %d\n", + arsta->tx_failed); } + arsta->tx_retries += peer_stats->retry_pkts; + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx retries %d", arsta->tx_retries); + if (ath10k_debug_is_extd_tx_stats_enabled(ar)) ath10k_accumulate_per_peer_tx_stats(ar, arsta, peer_stats, rate_idx); diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 919d15584d4a..d9d4b15a6d81 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -8547,12 +8547,13 @@ static void ath10k_sta_statistics(struct ieee80211_hw *hw, sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); if (ar->htt.disable_tx_comp) { - sinfo->tx_retries = arsta->tx_retries; - sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); sinfo->tx_failed = arsta->tx_failed; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); } + sinfo->tx_retries = arsta->tx_retries; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); + ath10k_mac_sta_get_peer_stats_info(ar, sta, sinfo); } -- cgit v1.2.3 From 720e5c03e5cb26d33d97f55192b791bb48478aa5 Mon Sep 17 00:00:00 2001 From: Venkateswara Naralasetty Date: Mon, 15 Jun 2020 20:29:03 +0300 Subject: ath10k: provide survey info as accumulated data It is expected that the returned counters by .get_survey are monotonic increasing. But the data from ath10k gets reset to zero regularly. Channel active/busy time are then showing incorrect values (less than previous or sometimes zero) for the currently active channel during successive survey dump commands. example: $ iw dev wlan0 survey dump Survey data from wlan0 frequency: 5180 MHz [in use] channel active time: 54995 ms channel busy time: 432 ms channel receive time: 0 ms channel transmit time: 59 ms ... $ iw dev wlan0 survey dump Survey data from wlan0 frequency: 5180 MHz [in use] channel active time: 32592 ms channel busy time: 254 ms channel receive time: 0 ms channel transmit time: 0 ms ... The correct way to handle this is to use the non-clearing WMI_BSS_SURVEY_REQ_TYPE_READ wmi_bss_survey_req_type. The firmware will then accumulate the survey data and handle wrap arounds. Tested-on: QCA9984 hw1.0 10.4-3.5.3-00057 Tested-on: QCA988X hw2.0 10.2.4-1.0-00047 Tested-on: QCA9888 hw2.0 10.4-3.9.0.2-00024 Tested-on: QCA4019 hw1.0 10.4-3.6-00140 Fixes: fa7937e3d5c2 ("ath10k: update bss channel survey information") Signed-off-by: Venkateswara Naralasetty Tested-by: Markus Theil Tested-by: John Deere <24601deerej@gmail.com> [sven@narfation.org: adjust commit message] Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1592232686-28712-1-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index d9d4b15a6d81..3e3896214e8b 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -7283,7 +7283,7 @@ ath10k_mac_update_bss_chan_survey(struct ath10k *ar, struct ieee80211_channel *channel) { int ret; - enum wmi_bss_survey_req_type type = WMI_BSS_SURVEY_REQ_TYPE_READ_CLEAR; + enum wmi_bss_survey_req_type type = WMI_BSS_SURVEY_REQ_TYPE_READ; lockdep_assert_held(&ar->conf_mutex); -- cgit v1.2.3 From 0aa90483f23e792f6cf571e8b396eef746194438 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Mon, 15 Jun 2020 20:29:06 +0300 Subject: wcn36xx: Add ieee80211 rx status rate information Packet encoding, bandwidth and bitrate can be derived from the wcn36xx rate_idx, part of the buffer descriptor. Signed-off-by: Loic Poulain Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1591961254-10243-1-git-send-email-loic.poulain@linaro.org --- drivers/net/wireless/ath/wcn36xx/txrx.c | 109 +++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index a6902371e89c..dda6d8946aef 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -23,9 +23,104 @@ static inline int get_rssi0(struct wcn36xx_rx_bd *bd) return 100 - ((bd->phy_stat0 >> 24) & 0xff); } +struct wcn36xx_rate { + u16 bitrate; + u16 mcs_or_legacy_index; + enum mac80211_rx_encoding encoding; + enum mac80211_rx_encoding_flags encoding_flags; + enum rate_info_bw bw; +}; + +static const struct wcn36xx_rate wcn36xx_rate_table[] = { + /* 11b rates */ + { 10, 0, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, + { 20, 1, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, + { 55, 2, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, + { 110, 3, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, + + /* 11b SP (short preamble) */ + { 10, 0, RX_ENC_LEGACY, RX_ENC_FLAG_SHORTPRE, RATE_INFO_BW_20 }, + { 20, 1, RX_ENC_LEGACY, RX_ENC_FLAG_SHORTPRE, RATE_INFO_BW_20 }, + { 55, 2, RX_ENC_LEGACY, RX_ENC_FLAG_SHORTPRE, RATE_INFO_BW_20 }, + { 110, 3, RX_ENC_LEGACY, RX_ENC_FLAG_SHORTPRE, RATE_INFO_BW_20 }, + + /* 11ag */ + { 60, 4, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, + { 90, 5, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, + { 120, 6, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, + { 180, 7, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, + { 240, 8, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, + { 360, 9, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, + { 480, 10, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, + { 540, 11, RX_ENC_LEGACY, 0, RATE_INFO_BW_20 }, + + /* 11n */ + { 65, 0, RX_ENC_HT, 0, RATE_INFO_BW_20 }, + { 130, 1, RX_ENC_HT, 0, RATE_INFO_BW_20 }, + { 195, 2, RX_ENC_HT, 0, RATE_INFO_BW_20 }, + { 260, 3, RX_ENC_HT, 0, RATE_INFO_BW_20 }, + { 390, 4, RX_ENC_HT, 0, RATE_INFO_BW_20 }, + { 520, 5, RX_ENC_HT, 0, RATE_INFO_BW_20 }, + { 585, 6, RX_ENC_HT, 0, RATE_INFO_BW_20 }, + { 650, 7, RX_ENC_HT, 0, RATE_INFO_BW_20 }, + + /* 11n SGI */ + { 72, 0, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, + { 144, 1, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, + { 217, 2, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, + { 289, 3, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, + { 434, 4, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, + { 578, 5, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, + { 650, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, + { 722, 7, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_20 }, + + /* 11n GF (greenfield) */ + { 65, 0, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, + { 130, 1, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, + { 195, 2, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, + { 260, 3, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, + { 390, 4, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, + { 520, 5, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, + { 585, 6, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, + { 650, 7, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_20 }, + + /* 11n CB (channel bonding) */ + { 135, 0, RX_ENC_HT, 0, RATE_INFO_BW_40 }, + { 270, 1, RX_ENC_HT, 0, RATE_INFO_BW_40 }, + { 405, 2, RX_ENC_HT, 0, RATE_INFO_BW_40 }, + { 540, 3, RX_ENC_HT, 0, RATE_INFO_BW_40 }, + { 810, 4, RX_ENC_HT, 0, RATE_INFO_BW_40 }, + { 1080, 5, RX_ENC_HT, 0, RATE_INFO_BW_40 }, + { 1215, 6, RX_ENC_HT, 0, RATE_INFO_BW_40 }, + { 1350, 7, RX_ENC_HT, 0, RATE_INFO_BW_40 }, + + /* 11n CB + SGI */ + { 150, 0, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, + { 300, 1, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, + { 450, 2, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, + { 600, 3, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, + { 900, 4, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, + { 1200, 5, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, + { 1350, 6, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, + { 1500, 7, RX_ENC_HT, RX_ENC_FLAG_SHORT_GI, RATE_INFO_BW_40 }, + + /* 11n GF + CB */ + { 135, 0, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, + { 270, 1, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, + { 405, 2, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, + { 540, 3, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, + { 810, 4, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, + { 1080, 5, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, + { 1215, 6, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, + { 1350, 7, RX_ENC_HT, RX_ENC_FLAG_HT_GF, RATE_INFO_BW_40 }, + + /* TODO: AC rates */ +}; + int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) { struct ieee80211_rx_status status; + const struct wcn36xx_rate *rate; struct ieee80211_hdr *hdr; struct wcn36xx_rx_bd *bd; u16 fc, sn; @@ -61,7 +156,6 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) status.mactime = 10; status.signal = -get_rssi0(bd); status.antenna = 1; - status.rate_idx = 1; status.flag = 0; status.rx_flags = 0; status.flag |= RX_FLAG_IV_STRIPPED | @@ -70,6 +164,19 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x\n", status.flag); + if (bd->rate_id < ARRAY_SIZE(wcn36xx_rate_table)) { + rate = &wcn36xx_rate_table[bd->rate_id]; + status.encoding = rate->encoding; + status.enc_flags = rate->encoding_flags; + status.bw = rate->bw; + status.rate_idx = rate->mcs_or_legacy_index; + } else { + status.encoding = 0; + status.bw = 0; + status.enc_flags = 0; + status.rate_idx = 0; + } + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); if (ieee80211_is_beacon(hdr->frame_control)) { -- cgit v1.2.3 From 7309f7730532c05916981901c4350bf21edf1a33 Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Tue, 16 Jun 2020 11:27:33 +0300 Subject: ath11k: update firmware files read path We need this so that all hardware versions can coexist and it's easier to manage everything then all hardware directories are under ath11k directory. Copy ath11k firmware files to /lib/firmware/ath11k/IPQ8074/hw2.0/ Signed-off-by: Anilkumar Kolli Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1591709581-18039-3-git-send-email-akolli@codeaurora.org --- drivers/net/wireless/ath/ath11k/hw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index dc4434aefbbe..6e065c4e5935 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -69,7 +69,7 @@ #define ATH11K_FW_DIR "ath11k" /* IPQ8074 definitions */ -#define IPQ8074_FW_DIR "IPQ8074" +#define IPQ8074_FW_DIR ATH11K_FW_DIR "/IPQ8074/hw2.0" #define IPQ8074_MAX_BOARD_DATA_SZ (256 * 1024) #define IPQ8074_MAX_CAL_DATA_SZ IPQ8074_MAX_BOARD_DATA_SZ -- cgit v1.2.3 From 93a5b668806c1d868f7f9f0438321006200c049f Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Tue, 16 Jun 2020 11:27:34 +0300 Subject: ath11k: rename default board file Rename default BDF to make it consistent with board-2.bin naming. Signed-off-by: Anilkumar Kolli Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1591709581-18039-4-git-send-email-akolli@codeaurora.org --- drivers/net/wireless/ath/ath11k/hw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 6e065c4e5935..f7f070af233c 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -75,7 +75,7 @@ #define ATH11K_BOARD_MAGIC "QCA-ATH11K-BOARD" #define ATH11K_BOARD_API2_FILE "board-2.bin" -#define ATH11K_DEFAULT_BOARD_FILE "bdwlan.bin" +#define ATH11K_DEFAULT_BOARD_FILE "board.bin" #define ATH11K_DEFAULT_CAL_FILE "caldata.bin" enum ath11k_hw_rate_cck { -- cgit v1.2.3 From aed95297250f0cac4c4861eef4a91708970aa1dc Mon Sep 17 00:00:00 2001 From: Zekun Shen Date: Tue, 16 Jun 2020 09:25:43 -0400 Subject: ath10k: pci: fix memcpy size of bmi response A compromized ath10k peripheral is able to control the size argument of memcpy in ath10k_pci_hif_exchange_bmi_msg. The min result from previous line is not used as the size argument for memcpy. Instead, xfer.resp_len comes from untrusted stream dma input. The value comes from "nbytes" in ath10k_pci_bmi_recv_data, which is set inside _ath10k_ce_completed_recv_next_nolock with the line nbytes = __le16_to_cpu(sdesc.nbytes); sdesc is a stream dma region which device can write to. Signed-off-by: Zekun Shen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200616132544.17478-1-bruceshenzk@gmail.com --- drivers/net/wireless/ath/ath10k/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 1d941d53fdc9..ad28d91565d1 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2184,7 +2184,7 @@ err_req: if (ret == 0 && resp_len) { *resp_len = min(*resp_len, xfer.resp_len); - memcpy(resp, tresp, xfer.resp_len); + memcpy(resp, tresp, *resp_len); } err_dma: kfree(treq); -- cgit v1.2.3 From 166e22b38aa3bcde616534f67b35d6e7e52b5b54 Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Tue, 16 Jun 2020 17:00:44 +0300 Subject: ath11k: ahb: call ath11k_core_init() before irq configuration This is needed to init .max_radios in hw_params and onfigure external interrupts for available pdev_ids. Compile tested only. Signed-off-by: Anilkumar Kolli Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1592316055-24958-2-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/ahb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 30092841ac46..2ea6da7682ce 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -951,15 +951,15 @@ static int ath11k_ahb_probe(struct platform_device *pdev) ath11k_ahb_init_qmi_ce_config(ab); - ret = ath11k_ahb_config_irq(ab); + ret = ath11k_core_init(ab); if (ret) { - ath11k_err(ab, "failed to configure irq: %d\n", ret); + ath11k_err(ab, "failed to init core: %d\n", ret); goto err_ce_free; } - ret = ath11k_core_init(ab); + ret = ath11k_ahb_config_irq(ab); if (ret) { - ath11k_err(ab, "failed to init core: %d\n", ret); + ath11k_err(ab, "failed to configure irq: %d\n", ret); goto err_ce_free; } -- cgit v1.2.3 From d3318abf41cf6be94424b3e3adcde791d563a147 Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Tue, 16 Jun 2020 17:00:45 +0300 Subject: ath11k: convert ath11k_hw_params to an array Convert to ath11k_hw_params to an array to make it possible add new hardware in the future, for example IPQ6018 or QCA6390. No functional changes. Compile tested only. Signed-off-by: Anilkumar Kolli Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1592316055-24958-3-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/core.c | 46 ++++++++++++++++++++++++++++------ drivers/net/wireless/ath/ath11k/hw.h | 1 + 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 905cd8beaf28..92d7925ad0f4 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -17,12 +17,15 @@ unsigned int ath11k_debug_mask; module_param_named(debug_mask, ath11k_debug_mask, uint, 0644); MODULE_PARM_DESC(debug_mask, "Debugging mask"); -static const struct ath11k_hw_params ath11k_hw_params = { - .name = "ipq8074", - .fw = { - .dir = IPQ8074_FW_DIR, - .board_size = IPQ8074_MAX_BOARD_DATA_SZ, - .cal_size = IPQ8074_MAX_CAL_DATA_SZ, +static const struct ath11k_hw_params ath11k_hw_params[] = { + { + .hw_rev = ATH11K_HW_IPQ8074, + .name = "ipq8074 hw2.0", + .fw = { + .dir = IPQ8074_FW_DIR, + .board_size = IPQ8074_MAX_BOARD_DATA_SZ, + .cal_size = IPQ8074_MAX_CAL_DATA_SZ, + }, }, }; @@ -717,6 +720,30 @@ static void ath11k_core_restart(struct work_struct *work) complete(&ab->driver_recovery); } +static int ath11k_init_hw_params(struct ath11k_base *ab) +{ + const struct ath11k_hw_params *hw_params = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(ath11k_hw_params); i++) { + hw_params = &ath11k_hw_params[i]; + + if (hw_params->hw_rev == ab->hw_rev) + break; + } + + if (i == ARRAY_SIZE(ath11k_hw_params)) { + ath11k_err(ab, "Unsupported hardware version: 0x%x\n", ab->hw_rev); + return -EINVAL; + } + + ab->hw_params = *hw_params; + + ath11k_dbg(ab, ATH11K_DBG_BOOT, "Hardware name %s\n", ab->hw_params.name); + + return 0; +} + int ath11k_core_init(struct ath11k_base *ab) { struct device *dev = ab->dev; @@ -735,7 +762,12 @@ int ath11k_core_init(struct ath11k_base *ab) return -EINVAL; } ab->tgt_rproc = prproc; - ab->hw_params = ath11k_hw_params; + + ret = ath11k_init_hw_params(ab); + if (ret) { + ath11k_err(ab, "failed to get hw params %d\n", ret); + return ret; + } ret = ath11k_core_soc_create(ab); if (ret) { diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index f7f070af233c..f95ad31d3d6c 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -106,6 +106,7 @@ enum ath11k_bus { struct ath11k_hw_params { const char *name; + u16 hw_rev; struct { const char *dir; size_t board_size; -- cgit v1.2.3 From b1cc29e97d1b96dfd3a7437083f7ba4aa5f32b88 Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Tue, 16 Jun 2020 17:00:46 +0300 Subject: ath11k: define max_radios in hw_params IPQ6018 needs different value for max_radios so make it configurable via hw_params. No functional changes. Compile tested only. Signed-off-by: Anilkumar Kolli Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1592316055-24958-4-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/core.c | 1 + drivers/net/wireless/ath/ath11k/dp_rx.c | 2 +- drivers/net/wireless/ath/ath11k/htc.c | 2 +- drivers/net/wireless/ath/ath11k/hw.h | 1 + drivers/net/wireless/ath/ath11k/reg.c | 2 +- drivers/net/wireless/ath/ath11k/wmi.c | 4 ++-- 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 92d7925ad0f4..67822508327c 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -26,6 +26,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .board_size = IPQ8074_MAX_BOARD_DATA_SZ, .cal_size = IPQ8074_MAX_CAL_DATA_SZ, }, + .max_radios = 3, }, }; diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 791d971784ce..5680b99a4f5c 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -3820,7 +3820,7 @@ int ath11k_dp_rx_process_wbm_err(struct ath11k_base *ab, int total_num_buffs_reaped = 0; int ret, i; - for (i = 0; i < MAX_RADIOS; i++) + for (i = 0; i < ab->num_radios; i++) __skb_queue_head_init(&msdu_list[i]); srng = &ab->hal.srng_list[dp->rx_rel_ring.ring_id]; diff --git a/drivers/net/wireless/ath/ath11k/htc.c b/drivers/net/wireless/ath/ath11k/htc.c index ad13c648b679..bc0026c1e4a6 100644 --- a/drivers/net/wireless/ath/ath11k/htc.c +++ b/drivers/net/wireless/ath/ath11k/htc.c @@ -748,7 +748,7 @@ int ath11k_htc_init(struct ath11k_base *ab) htc->wmi_ep_count = 3; break; default: - htc->wmi_ep_count = 3; + htc->wmi_ep_count = ab->hw_params.max_radios; break; } diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index f95ad31d3d6c..ba897d186cf5 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -107,6 +107,7 @@ enum ath11k_bus { struct ath11k_hw_params { const char *name; u16 hw_rev; + u8 max_radios; struct { const char *dir; size_t board_size; diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index 7c9dc91cc48a..0ba80e6f3979 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -699,7 +699,7 @@ void ath11k_reg_free(struct ath11k_base *ab) { int i; - for (i = 0; i < MAX_RADIOS; i++) { + for (i = 0; i < ab->hw_params.max_radios; i++) { kfree(ab->default_regd[i]); kfree(ab->new_regd[i]); } diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 8e3437a65673..cd1bdb2a75c9 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -6682,7 +6682,7 @@ int ath11k_wmi_connect(struct ath11k_base *ab) u8 wmi_ep_count; wmi_ep_count = ab->htc.wmi_ep_count; - if (wmi_ep_count > MAX_RADIOS) + if (wmi_ep_count > ab->hw_params.max_radios) return -1; for (i = 0; i < wmi_ep_count; i++) @@ -6704,7 +6704,7 @@ int ath11k_wmi_pdev_attach(struct ath11k_base *ab, { struct ath11k_pdev_wmi *wmi_handle; - if (pdev_id >= MAX_RADIOS) + if (pdev_id >= ab->hw_params.max_radios) return -EINVAL; wmi_handle = &ab->wmi_ab.wmi[pdev_id]; -- cgit v1.2.3 From d547ca4c8cc5638669b9942ad7284ebf7106f708 Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Tue, 16 Jun 2020 17:00:47 +0300 Subject: ath11k: add hw_ops for pdev id to hw_mac mapping pdev_id to hw_mac is different for ipq8074 and ipq6018 Below table has the mapping pdev_id ipq8074 ipq6018 ------- ------- ------- 0 0 0 1 2 1 2 1 Not applicable No functional changes. Compile tested only. Signed-off-by: Anilkumar Kolli Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1592316055-24958-5-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/Makefile | 3 ++- drivers/net/wireless/ath/ath11k/ahb.c | 15 +++++++------- drivers/net/wireless/ath/ath11k/core.c | 18 +---------------- drivers/net/wireless/ath/ath11k/core.h | 1 - drivers/net/wireless/ath/ath11k/hw.c | 34 ++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/hw.h | 19 ++++++++++++++++++ drivers/net/wireless/ath/ath11k/mac.c | 2 +- 7 files changed, 65 insertions(+), 27 deletions(-) create mode 100644 drivers/net/wireless/ath/ath11k/hw.c diff --git a/drivers/net/wireless/ath/ath11k/Makefile b/drivers/net/wireless/ath/ath11k/Makefile index 104186373c9e..ee13a3becbcf 100644 --- a/drivers/net/wireless/ath/ath11k/Makefile +++ b/drivers/net/wireless/ath/ath11k/Makefile @@ -16,7 +16,8 @@ ath11k-y += core.o \ debug.o \ ce.o \ peer.o \ - dbring.o + dbring.o \ + hw.o ath11k-$(CONFIG_ATH11K_DEBUGFS) += debug_htt_stats.o debugfs_sta.o ath11k-$(CONFIG_NL80211_TESTMODE) += testmode.o diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 2ea6da7682ce..7e9bfeaaf4d2 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -734,6 +734,7 @@ static irqreturn_t ath11k_ahb_ext_interrupt_handler(int irq, void *arg) static int ath11k_ahb_ext_irq_config(struct ath11k_base *ab) { + struct ath11k_hw_params *hw = &ab->hw_params; int i, j; int irq; int ret; @@ -768,26 +769,26 @@ static int ath11k_ahb_ext_irq_config(struct ath11k_base *ab) if (ath11k_reo_status_ring_mask[i] & BIT(j)) irq_grp->irqs[num_irq++] = reo2host_status; - if (j < MAX_RADIOS) { + if (j < ab->hw_params.max_radios) { if (ath11k_rxdma2host_ring_mask[i] & BIT(j)) { irq_grp->irqs[num_irq++] = - rxdma2host_destination_ring_mac1 - - ath11k_core_get_hw_mac_id(ab, j); + rxdma2host_destination_ring_mac1 - + ath11k_hw_get_mac_from_pdev_id(hw, j); } if (ath11k_host2rxdma_ring_mask[i] & BIT(j)) { irq_grp->irqs[num_irq++] = - host2rxdma_host_buf_ring_mac1 - - ath11k_core_get_hw_mac_id(ab, j); + host2rxdma_host_buf_ring_mac1 - + ath11k_hw_get_mac_from_pdev_id(hw, j); } if (rx_mon_status_ring_mask[i] & BIT(j)) { irq_grp->irqs[num_irq++] = ppdu_end_interrupts_mac1 - - ath11k_core_get_hw_mac_id(ab, j); + ath11k_hw_get_mac_from_pdev_id(hw, j); irq_grp->irqs[num_irq++] = rxdma2host_monitor_status_ring_mac1 - - ath11k_core_get_hw_mac_id(ab, j); + ath11k_hw_get_mac_from_pdev_id(hw, j); } } } diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 67822508327c..089b46ba86c5 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -27,26 +27,10 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .cal_size = IPQ8074_MAX_CAL_DATA_SZ, }, .max_radios = 3, + .hw_ops = &ipq8074_ops, }, }; -/* Map from pdev index to hw mac index */ -u8 ath11k_core_get_hw_mac_id(struct ath11k_base *ab, int pdev_idx) -{ - switch (pdev_idx) { - case 0: - return 0; - case 1: - return 2; - case 2: - return 1; - default: - ath11k_warn(ab, "Invalid pdev idx %d\n", pdev_idx); - return ATH11K_INVALID_HW_MAC_ID; - } -} -EXPORT_SYMBOL(ath11k_core_get_hw_mac_id); - static int ath11k_core_create_board_name(struct ath11k_base *ab, char *name, size_t name_len) { diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index e5c4e19020ee..98de9c35e178 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -860,7 +860,6 @@ int ath11k_core_fetch_bdf(struct ath11k_base *ath11k, void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd); void ath11k_core_halt(struct ath11k *ar); -u8 ath11k_core_get_hw_mac_id(struct ath11k_base *ab, int pdev_idx); static inline const char *ath11k_scan_state_str(enum ath11k_scan_state state) { diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c new file mode 100644 index 000000000000..7cc5f36509c0 --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + */ + +#include "core.h" + +/* Map from pdev index to hw mac index */ +static u8 ath11k_hw_ipq8074_mac_from_pdev_id(int pdev_idx) +{ + switch (pdev_idx) { + case 0: + return 0; + case 1: + return 2; + case 2: + return 1; + default: + return ATH11K_INVALID_HW_MAC_ID; + } +} + +static u8 ath11k_hw_ipq6018_mac_from_pdev_id(int pdev_idx) +{ + return pdev_idx; +} + +const struct ath11k_hw_ops ipq8074_ops = { + .get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id, +}; + +const struct ath11k_hw_ops ipq6018_ops = { + .get_hw_mac_from_pdev_id = ath11k_hw_ipq6018_mac_from_pdev_id, +}; diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index ba897d186cf5..2fb986b9a6cb 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -104,6 +104,10 @@ enum ath11k_bus { ATH11K_BUS_PCI, }; +struct ath11k_hw_ops { + u8 (*get_hw_mac_from_pdev_id)(int pdev_id); +}; + struct ath11k_hw_params { const char *name; u16 hw_rev; @@ -113,8 +117,23 @@ struct ath11k_hw_params { size_t board_size; size_t cal_size; } fw; + + const struct ath11k_hw_ops *hw_ops; }; +extern const struct ath11k_hw_ops ipq8074_ops; +extern const struct ath11k_hw_ops ipq6018_ops; + +static inline +int ath11k_hw_get_mac_from_pdev_id(struct ath11k_hw_params *hw, + int pdev_idx) +{ + if (hw->hw_ops->get_hw_mac_from_pdev_id) + return hw->hw_ops->get_hw_mac_from_pdev_id(pdev_idx); + + return 0; +} + struct ath11k_fw_ie { __le32 id; __le32 len; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 07d3e031c75a..cdedb2ea7d87 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -6194,7 +6194,7 @@ int ath11k_mac_allocate(struct ath11k_base *ab) ar->ab = ab; ar->pdev = pdev; ar->pdev_idx = i; - ar->lmac_id = ath11k_core_get_hw_mac_id(ab, i); + ar->lmac_id = ath11k_hw_get_mac_from_pdev_id(&ab->hw_params, i); ar->wmi = &ab->wmi_ab.wmi[i]; /* FIXME wmi[0] is already initialized during attach, -- cgit v1.2.3 From 3b94ae4c62db0b158404073a039eb8fd0b00b75f Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Tue, 16 Jun 2020 17:00:48 +0300 Subject: ath11k: Add bdf-addr in hw_params bdf-addr is different for IPQ8074 and IPQ6018 so add it to hw_params. No functional changes. Compile tested only. Signed-off-by: Anilkumar Kolli Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1592316055-24958-6-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/core.c | 1 + drivers/net/wireless/ath/ath11k/hw.h | 2 ++ drivers/net/wireless/ath/ath11k/qmi.c | 6 +++--- drivers/net/wireless/ath/ath11k/qmi.h | 1 - 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 089b46ba86c5..5232a355ac12 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -27,6 +27,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .cal_size = IPQ8074_MAX_CAL_DATA_SZ, }, .max_radios = 3, + .bdf_addr = 0x4B0C0000, .hw_ops = &ipq8074_ops, }, }; diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 2fb986b9a6cb..78518e3f773d 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -112,6 +112,8 @@ struct ath11k_hw_params { const char *name; u16 hw_rev; u8 max_radios; + u32 bdf_addr; + struct { const char *dir; size_t board_size; diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index c00a99ad8dbc..e4198d3b0bae 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -1681,8 +1681,8 @@ static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab) for (i = 0, idx = 0; i < ab->qmi.mem_seg_count; i++) { switch (ab->qmi.target_mem[i].type) { case BDF_MEM_REGION_TYPE: - ab->qmi.target_mem[idx].paddr = ATH11K_QMI_BDF_ADDRESS; - ab->qmi.target_mem[idx].vaddr = ATH11K_QMI_BDF_ADDRESS; + ab->qmi.target_mem[idx].paddr = ab->hw_params.bdf_addr; + ab->qmi.target_mem[idx].vaddr = ab->hw_params.bdf_addr; ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size; ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type; idx++; @@ -1854,7 +1854,7 @@ static int ath11k_qmi_load_bdf(struct ath11k_base *ab) return -ENOMEM; memset(&resp, 0, sizeof(resp)); - bdf_addr = ioremap(ATH11K_QMI_BDF_ADDRESS, ATH11K_QMI_BDF_MAX_SIZE); + bdf_addr = ioremap(ab->hw_params.bdf_addr, ATH11K_QMI_BDF_MAX_SIZE); if (!bdf_addr) { ath11k_warn(ab, "qmi ioremap error for BDF\n"); ret = -EIO; diff --git a/drivers/net/wireless/ath/ath11k/qmi.h b/drivers/net/wireless/ath/ath11k/qmi.h index 3f7db642d869..a7a0a189cbe4 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.h +++ b/drivers/net/wireless/ath/ath11k/qmi.h @@ -12,7 +12,6 @@ #define ATH11K_HOST_VERSION_STRING "WIN" #define ATH11K_QMI_WLANFW_TIMEOUT_MS 5000 #define ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE 64 -#define ATH11K_QMI_BDF_ADDRESS 0x4B0C0000 #define ATH11K_QMI_BDF_MAX_SIZE (256 * 1024) #define ATH11K_QMI_CALDATA_OFFSET (128 * 1024) #define ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 128 -- cgit v1.2.3 From 7b57b2ddec21c1a660af2d832939d392081e515f Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 16 Jun 2020 17:00:49 +0300 Subject: ath11k: create a common function to request all firmware files To avoid duplicating the logic how the full firmware path is created create a common function ath11k_core_firmware_request() and convert also qmi.c to use it. Also remove a useless info print, it's more like a debug message anyway. No functional changes. Compile tested only. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1592316055-24958-7-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/core.c | 27 +++++++++++++-------------- drivers/net/wireless/ath/ath11k/core.h | 4 ++++ drivers/net/wireless/ath/ath11k/qmi.c | 12 ++++-------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 5232a355ac12..7e29977c23b4 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -48,9 +48,9 @@ static int ath11k_core_create_board_name(struct ath11k_base *ab, char *name, return 0; } -static const struct firmware *ath11k_fetch_fw_file(struct ath11k_base *ab, - const char *dir, - const char *file) +const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab, + const char *dir, + const char *file) { char filename[100]; const struct firmware *fw; @@ -63,14 +63,13 @@ static const struct firmware *ath11k_fetch_fw_file(struct ath11k_base *ab, dir = "."; snprintf(filename, sizeof(filename), "%s/%s", dir, file); - ret = firmware_request_nowarn(&fw, filename, ab->dev); - ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot fw request '%s': %d\n", - filename, ret); + ret = firmware_request_nowarn(&fw, filename, ab->dev); if (ret) return ERR_PTR(ret); - ath11k_warn(ab, "Downloading BDF: %s, size: %zu\n", - filename, fw->size); + + ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot firmware request %s size %zu\n", + filename, fw->size); return fw; } @@ -176,9 +175,9 @@ static int ath11k_core_fetch_board_data_api_n(struct ath11k_base *ab, int ret, ie_id; if (!bd->fw) - bd->fw = ath11k_fetch_fw_file(ab, - ab->hw_params.fw.dir, - filename); + bd->fw = ath11k_core_firmware_request(ab, + ab->hw_params.fw.dir, + filename); if (IS_ERR(bd->fw)) return PTR_ERR(bd->fw); @@ -268,9 +267,9 @@ err: static int ath11k_core_fetch_board_data_api_1(struct ath11k_base *ab, struct ath11k_board_data *bd) { - bd->fw = ath11k_fetch_fw_file(ab, - ab->hw_params.fw.dir, - ATH11K_DEFAULT_BOARD_FILE); + bd->fw = ath11k_core_firmware_request(ab, + ab->hw_params.fw.dir, + ATH11K_DEFAULT_BOARD_FILE); if (IS_ERR(bd->fw)) return PTR_ERR(bd->fw); diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 98de9c35e178..be1339a5ea0a 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -861,6 +861,10 @@ void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd); void ath11k_core_halt(struct ath11k *ar); +const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab, + const char *dir, + const char *file); + static inline const char *ath11k_scan_state_str(enum ath11k_scan_state state) { switch (state) { diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index e4198d3b0bae..0cd3fb8eeece 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -1790,8 +1790,6 @@ ath11k_qmi_prepare_bdf_download(struct ath11k_base *ab, int type, struct qmi_wlanfw_bdf_download_req_msg_v01 *req, void __iomem *bdf_addr) { - struct device *dev = ab->dev; - char filename[ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE]; const struct firmware *fw_entry; struct ath11k_board_data bd; u32 fw_size; @@ -1812,11 +1810,11 @@ ath11k_qmi_prepare_bdf_download(struct ath11k_base *ab, int type, ath11k_core_free_bdf(ab, &bd); break; case ATH11K_QMI_FILE_TYPE_CALDATA: - snprintf(filename, sizeof(filename), - "%s/%s", ab->hw_params.fw.dir, ATH11K_QMI_DEFAULT_CAL_FILE_NAME); - ret = request_firmware(&fw_entry, filename, dev); + fw_entry = ath11k_core_firmware_request(ab, ab->hw_params.fw.dir, + ATH11K_QMI_DEFAULT_CAL_FILE_NAME); if (ret) { - ath11k_warn(ab, "qmi failed to load CAL: %s\n", filename); + ath11k_warn(ab, "failed to load %s: %d\n", + ATH11K_QMI_DEFAULT_CAL_FILE_NAME, ret); goto out; } @@ -1825,8 +1823,6 @@ ath11k_qmi_prepare_bdf_download(struct ath11k_base *ab, int type, memcpy_toio(bdf_addr + ATH11K_QMI_CALDATA_OFFSET, fw_entry->data, fw_size); - ath11k_info(ab, "qmi downloading BDF: %s, size: %zu\n", - filename, fw_entry->size); release_firmware(fw_entry); break; -- cgit v1.2.3 From 34d9fc80bac34ea4128daf55a1a85161ccb55d9b Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 16 Jun 2020 17:00:50 +0300 Subject: ath11k: don't use defines for hw specific firmware directories The downside of using defines in struct ath11k_hw_params.fw.dir is that it's easy to get it wrong as the full path is not visible. So drop the use of defines and instead create the patch runtime using a static inline function ath11k_core_create_firmware_path(). Hopefully this reduces the chances of using incorrect firmware path. No functional changes. Compile tested only. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1592316055-24958-8-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/core.c | 23 ++++++++--------------- drivers/net/wireless/ath/ath11k/core.h | 11 +++++++++-- drivers/net/wireless/ath/ath11k/hw.h | 1 - drivers/net/wireless/ath/ath11k/qmi.c | 2 +- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 7e29977c23b4..de5b1d20771a 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -22,7 +22,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .hw_rev = ATH11K_HW_IPQ8074, .name = "ipq8074 hw2.0", .fw = { - .dir = IPQ8074_FW_DIR, + .dir = "IPQ8074/hw2.0", .board_size = IPQ8074_MAX_BOARD_DATA_SZ, .cal_size = IPQ8074_MAX_CAL_DATA_SZ, }, @@ -49,27 +49,23 @@ static int ath11k_core_create_board_name(struct ath11k_base *ab, char *name, } const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab, - const char *dir, const char *file) { - char filename[100]; const struct firmware *fw; + char path[100]; int ret; if (file == NULL) return ERR_PTR(-ENOENT); - if (dir == NULL) - dir = "."; + ath11k_core_create_firmware_path(ab, file, path, sizeof(path)); - snprintf(filename, sizeof(filename), "%s/%s", dir, file); - - ret = firmware_request_nowarn(&fw, filename, ab->dev); + ret = firmware_request_nowarn(&fw, path, ab->dev); if (ret) return ERR_PTR(ret); ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot firmware request %s size %zu\n", - filename, fw->size); + path, fw->size); return fw; } @@ -175,9 +171,8 @@ static int ath11k_core_fetch_board_data_api_n(struct ath11k_base *ab, int ret, ie_id; if (!bd->fw) - bd->fw = ath11k_core_firmware_request(ab, - ab->hw_params.fw.dir, - filename); + bd->fw = ath11k_core_firmware_request(ab, filename); + if (IS_ERR(bd->fw)) return PTR_ERR(bd->fw); @@ -267,9 +262,7 @@ err: static int ath11k_core_fetch_board_data_api_1(struct ath11k_base *ab, struct ath11k_board_data *bd) { - bd->fw = ath11k_core_firmware_request(ab, - ab->hw_params.fw.dir, - ATH11K_DEFAULT_BOARD_FILE); + bd->fw = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_BOARD_FILE); if (IS_ERR(bd->fw)) return PTR_ERR(bd->fw); diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index be1339a5ea0a..b6ccd9f93853 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -862,8 +862,7 @@ void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd); void ath11k_core_halt(struct ath11k *ar); const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab, - const char *dir, - const char *file); + const char *filename); static inline const char *ath11k_scan_state_str(enum ath11k_scan_state state) { @@ -897,4 +896,12 @@ static inline struct ath11k_vif *ath11k_vif_to_arvif(struct ieee80211_vif *vif) return (struct ath11k_vif *)vif->drv_priv; } +static inline void ath11k_core_create_firmware_path(struct ath11k_base *ab, + const char *filename, + void *buf, size_t buf_len) +{ + snprintf(buf, buf_len, "%s/%s/%s", ATH11K_FW_DIR, + ab->hw_params.fw.dir, filename); +} + #endif /* _CORE_H_ */ diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 78518e3f773d..828c8c076218 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -69,7 +69,6 @@ #define ATH11K_FW_DIR "ath11k" /* IPQ8074 definitions */ -#define IPQ8074_FW_DIR ATH11K_FW_DIR "/IPQ8074/hw2.0" #define IPQ8074_MAX_BOARD_DATA_SZ (256 * 1024) #define IPQ8074_MAX_CAL_DATA_SZ IPQ8074_MAX_BOARD_DATA_SZ diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index 0cd3fb8eeece..d9ffdf84ccae 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -1810,7 +1810,7 @@ ath11k_qmi_prepare_bdf_download(struct ath11k_base *ab, int type, ath11k_core_free_bdf(ab, &bd); break; case ATH11K_QMI_FILE_TYPE_CALDATA: - fw_entry = ath11k_core_firmware_request(ab, ab->hw_params.fw.dir, + fw_entry = ath11k_core_firmware_request(ab, ATH11K_QMI_DEFAULT_CAL_FILE_NAME); if (ret) { ath11k_warn(ab, "failed to load %s: %d\n", -- cgit v1.2.3 From 31d78a3de4de8e0254da8aa055f6328c970998fc Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 16 Jun 2020 17:00:51 +0300 Subject: ath11k: change ath11k_core_fetch_board_data_api_n() to use ath11k_core_create_firmware_path() Use the helper added in previous comment to create the full path, instead of doing it manually. No functional changes. Compile tested only. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1592316055-24958-9-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/core.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index de5b1d20771a..84a566dffad9 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -165,11 +165,13 @@ static int ath11k_core_fetch_board_data_api_n(struct ath11k_base *ab, { size_t len, magic_len; const u8 *data; - char *filename = ATH11K_BOARD_API2_FILE; + char *filename, filepath[100]; size_t ie_len; struct ath11k_fw_ie *hdr; int ret, ie_id; + filename = ATH11K_BOARD_API2_FILE; + if (!bd->fw) bd->fw = ath11k_core_firmware_request(ab, filename); @@ -179,11 +181,14 @@ static int ath11k_core_fetch_board_data_api_n(struct ath11k_base *ab, data = bd->fw->data; len = bd->fw->size; + ath11k_core_create_firmware_path(ab, filename, + filepath, sizeof(filepath)); + /* magic has extra null byte padded */ magic_len = strlen(ATH11K_BOARD_MAGIC) + 1; if (len < magic_len) { - ath11k_err(ab, "failed to find magic value in %s/%s, file too short: %zu\n", - ab->hw_params.fw.dir, filename, len); + ath11k_err(ab, "failed to find magic value in %s, file too short: %zu\n", + filepath, len); ret = -EINVAL; goto err; } @@ -197,8 +202,8 @@ static int ath11k_core_fetch_board_data_api_n(struct ath11k_base *ab, /* magic is padded to 4 bytes */ magic_len = ALIGN(magic_len, 4); if (len < magic_len) { - ath11k_err(ab, "failed: %s/%s too small to contain board data, len: %zu\n", - ab->hw_params.fw.dir, filename, len); + ath11k_err(ab, "failed: %s too small to contain board data, len: %zu\n", + filepath, len); ret = -EINVAL; goto err; } @@ -246,8 +251,8 @@ static int ath11k_core_fetch_board_data_api_n(struct ath11k_base *ab, out: if (!bd->data || !bd->len) { ath11k_err(ab, - "failed to fetch board data for %s from %s/%s\n", - boardname, ab->hw_params.fw.dir, filename); + "failed to fetch board data for %s from %s\n", + boardname, filepath); ret = -ENODATA; goto err; } -- cgit v1.2.3 From 21b1a5a4c34cff5e62499523728f59de5e38fde5 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 16 Jun 2020 17:00:52 +0300 Subject: ath11k: remove useless info messages ath11k should not be spamming these to the logs. If these are important they should be debug messages, but I just remove them for now. Compile tested only. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1592316055-24958-10-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/mac.c | 8 -------- drivers/net/wireless/ath/ath11k/peer.c | 3 --- drivers/net/wireless/ath/ath11k/qmi.c | 1 - drivers/net/wireless/ath/ath11k/spectral.c | 8 ++------ 4 files changed, 2 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index cdedb2ea7d87..0fd1f714429c 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -3039,10 +3039,6 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, if (ret) ath11k_warn(ar->ab, "Failed to associate station: %pM\n", sta->addr); - else - ath11k_info(ar->ab, - "Station %pM moved to assoc state\n", - sta->addr); } else if (old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTH && (vif->type == NL80211_IFTYPE_AP || @@ -3052,10 +3048,6 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, if (ret) ath11k_warn(ar->ab, "Failed to disassociate station: %pM\n", sta->addr); - else - ath11k_info(ar->ab, - "Station %pM moved to disassociated state\n", - sta->addr); } mutex_unlock(&ar->conf_mutex); diff --git a/drivers/net/wireless/ath/ath11k/peer.c b/drivers/net/wireless/ath/ath11k/peer.c index 297172538620..61ad9300eafb 100644 --- a/drivers/net/wireless/ath/ath11k/peer.c +++ b/drivers/net/wireless/ath/ath11k/peer.c @@ -223,9 +223,6 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif, peer = ath11k_peer_find_by_pdev_idx(ar->ab, ar->pdev_idx, param->peer_addr); if (peer) { spin_unlock_bh(&ar->ab->base_lock); - ath11k_info(ar->ab, - "ignoring the peer %pM creation on same pdev idx %d\n", - param->peer_addr, ar->pdev_idx); return -EINVAL; } spin_unlock_bh(&ar->ab->base_lock); diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index d9ffdf84ccae..bbdbf1ed19dc 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -1901,7 +1901,6 @@ static int ath11k_qmi_load_bdf(struct ath11k_base *ab) goto out_qmi_bdf; } } - ath11k_info(ab, "qmi BDF downloaded\n"); out_qmi_bdf: iounmap(bdf_addr); diff --git a/drivers/net/wireless/ath/ath11k/spectral.c b/drivers/net/wireless/ath/ath11k/spectral.c index 1c5d65bb411f..6cbe6f4e2864 100644 --- a/drivers/net/wireless/ath/ath11k/spectral.c +++ b/drivers/net/wireless/ath/ath11k/spectral.c @@ -954,10 +954,8 @@ int ath11k_spectral_init(struct ath11k_base *ab) int i; if (!test_bit(WMI_TLV_SERVICE_FREQINFO_IN_METADATA, - ab->wmi_ab.svc_map)) { - ath11k_info(ab, "spectral not supported\n"); + ab->wmi_ab.svc_map)) return 0; - } for (i = 0; i < ab->num_radios; i++) { ar = ab->pdevs[i].ar; @@ -966,10 +964,8 @@ int ath11k_spectral_init(struct ath11k_base *ab) ret = ath11k_dbring_get_cap(ar->ab, ar->pdev_idx, WMI_DIRECT_BUF_SPECTRAL, &db_cap); - if (ret) { - ath11k_info(ab, "spectral not enabled for pdev %d\n", i); + if (ret) continue; - } idr_init(&sp->rx_ring.bufs_idr); spin_lock_init(&sp->rx_ring.idr_lock); -- cgit v1.2.3 From 6e5dd03c0b1f8bf9d8f5b3101ee92c46f804d526 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 16 Jun 2020 17:00:53 +0300 Subject: ath11k: qmi: cleanup info messages Use simplified format, just like ath10k uses, which is easier to read. Compile tested only. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1592316055-24958-11-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/qmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index bbdbf1ed19dc..495c0e1812d7 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -1772,11 +1772,11 @@ static int ath11k_qmi_request_target_cap(struct ath11k_base *ab) strlcpy(ab->qmi.target.fw_build_id, resp.fw_build_id, sizeof(ab->qmi.target.fw_build_id)); - ath11k_info(ab, "qmi target: chip_id: 0x%x, chip_family: 0x%x, board_id: 0x%x, soc_id: 0x%x\n", + ath11k_info(ab, "chip_id 0x%x chip_family 0x%x board_id 0x%x soc_id 0x%x\n", ab->qmi.target.chip_id, ab->qmi.target.chip_family, ab->qmi.target.board_id, ab->qmi.target.soc_id); - ath11k_info(ab, "qmi fw_version: 0x%x fw_build_timestamp: %s fw_build_id: %s", + ath11k_info(ab, "fw_version 0x%x fw_build_timestamp %s fw_build_id %s", ab->qmi.target.fw_version, ab->qmi.target.fw_build_timestamp, ab->qmi.target.fw_build_id); -- cgit v1.2.3 From b3a18338ebd6cc8b540e63d8d9d9e30c20041bef Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 16 Jun 2020 17:00:54 +0300 Subject: ath11k: don't use defines in hw_params These defines are not used anywhere else so to avoid extra indirection add the values directly to hw_params. No functional changes. Compile tested only. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1592316055-24958-12-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/core.c | 4 ++-- drivers/net/wireless/ath/ath11k/hw.h | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 84a566dffad9..38e830a2395b 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -23,8 +23,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .name = "ipq8074 hw2.0", .fw = { .dir = "IPQ8074/hw2.0", - .board_size = IPQ8074_MAX_BOARD_DATA_SZ, - .cal_size = IPQ8074_MAX_CAL_DATA_SZ, + .board_size = 256 * 1024, + .cal_size = 256 * 1024, }, .max_radios = 3, .bdf_addr = 0x4B0C0000, diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 828c8c076218..f31d53f6adb8 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -68,10 +68,6 @@ #define ATH11K_FW_DIR "ath11k" -/* IPQ8074 definitions */ -#define IPQ8074_MAX_BOARD_DATA_SZ (256 * 1024) -#define IPQ8074_MAX_CAL_DATA_SZ IPQ8074_MAX_BOARD_DATA_SZ - #define ATH11K_BOARD_MAGIC "QCA-ATH11K-BOARD" #define ATH11K_BOARD_API2_FILE "board-2.bin" #define ATH11K_DEFAULT_BOARD_FILE "board.bin" -- cgit v1.2.3 From a9bf090932032bd259672814670df701ecb3ff51 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 16 Jun 2020 17:00:55 +0300 Subject: ath11k: remove define ATH11K_QMI_DEFAULT_CAL_FILE_NAME It's just a duplicate of ATH11K_DEFAULT_CAL_FILE. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1592316055-24958-13-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/qmi.c | 5 ++--- drivers/net/wireless/ath/ath11k/qmi.h | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index 495c0e1812d7..50812df6527d 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -1810,11 +1810,10 @@ ath11k_qmi_prepare_bdf_download(struct ath11k_base *ab, int type, ath11k_core_free_bdf(ab, &bd); break; case ATH11K_QMI_FILE_TYPE_CALDATA: - fw_entry = ath11k_core_firmware_request(ab, - ATH11K_QMI_DEFAULT_CAL_FILE_NAME); + fw_entry = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_CAL_FILE); if (ret) { ath11k_warn(ab, "failed to load %s: %d\n", - ATH11K_QMI_DEFAULT_CAL_FILE_NAME, ret); + ATH11K_DEFAULT_CAL_FILE, ret); goto out; } diff --git a/drivers/net/wireless/ath/ath11k/qmi.h b/drivers/net/wireless/ath/ath11k/qmi.h index a7a0a189cbe4..3307be5be687 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.h +++ b/drivers/net/wireless/ath/ath11k/qmi.h @@ -22,7 +22,6 @@ #define ATH11K_QMI_RESP_LEN_MAX 8192 #define ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01 32 #define ATH11K_QMI_CALDB_SIZE 0x480000 -#define ATH11K_QMI_DEFAULT_CAL_FILE_NAME "caldata.bin" #define QMI_WLFW_REQUEST_MEM_IND_V01 0x0035 #define QMI_WLFW_FW_MEM_READY_IND_V01 0x0037 -- cgit v1.2.3 From 9a8ab2bfb678193f326239143290691c965faede Mon Sep 17 00:00:00 2001 From: Bolarinwa Olayemi Saheed Date: Mon, 13 Jul 2020 19:55:26 +0200 Subject: ath9k: Check the return value of pcie_capability_read_*() On failure pcie_capability_read_dword() sets it's last parameter, val to 0. However, with Patch 14/14, it is possible that val is set to ~0 on failure. This would introduce a bug because (x & x) == (~0 & x). This bug can be avoided without changing the function's behaviour if the return value of pcie_capability_read_dword is checked to confirm success. Check the return value of pcie_capability_read_dword() to ensure success. Suggested-by: Bjorn Helgaas Signed-off-by: Bolarinwa Olayemi Saheed Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200713175529.29715-2-refactormyself@gmail.com --- drivers/net/wireless/ath/ath9k/pci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index f3461b193c7a..cff9af3af38d 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -825,6 +825,7 @@ static void ath_pci_aspm_init(struct ath_common *common) struct pci_dev *pdev = to_pci_dev(sc->dev); struct pci_dev *parent; u16 aspm; + int ret; if (!ah->is_pciexpress) return; @@ -866,8 +867,8 @@ static void ath_pci_aspm_init(struct ath_common *common) if (AR_SREV_9462(ah)) pci_read_config_dword(pdev, 0x70c, &ah->config.aspm_l1_fix); - pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &aspm); - if (aspm & (PCI_EXP_LNKCTL_ASPM_L0S | PCI_EXP_LNKCTL_ASPM_L1)) { + ret = pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &aspm); + if (!ret && (aspm & (PCI_EXP_LNKCTL_ASPM_L0S | PCI_EXP_LNKCTL_ASPM_L1))) { ah->aspm_enabled = true; /* Initialize PCIe PM and SERDES registers. */ ath9k_hw_configpcipowersave(ah, false); -- cgit v1.2.3 From bad60b8d1a7194df38fd7fe4b22f3f4dcf775099 Mon Sep 17 00:00:00 2001 From: Zekun Shen Date: Tue, 23 Jun 2020 18:11:05 -0400 Subject: ath10k: check idx validity in __ath10k_htt_rx_ring_fill_n() The idx in __ath10k_htt_rx_ring_fill_n function lives in consistent dma region writable by the device. Malfunctional or malicious device could manipulate such idx to have a OOB write. Either by htt->rx_ring.netbufs_ring[idx] = skb; or by ath10k_htt_set_paddrs_ring(htt, paddr, idx); The idx can also be negative as it's signed, giving a large memory space to write to. It's possibly exploitable by corruptting a legit pointer with a skb pointer. And then fill skb with payload as rougue object. Part of the log here. Sometimes it appears as UAF when writing to a freed memory by chance. [ 15.594376] BUG: unable to handle page fault for address: ffff887f5c1804f0 [ 15.595483] #PF: supervisor write access in kernel mode [ 15.596250] #PF: error_code(0x0002) - not-present page [ 15.597013] PGD 0 P4D 0 [ 15.597395] Oops: 0002 [#1] SMP KASAN PTI [ 15.597967] CPU: 0 PID: 82 Comm: kworker/u2:2 Not tainted 5.6.0 #69 [ 15.598843] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.1-0-ga5cab58e9a3f-prebuilt.qemu.org 04/01/2014 [ 15.600438] Workqueue: ath10k_wq ath10k_core_register_work [ath10k_core] [ 15.601389] RIP: 0010:__ath10k_htt_rx_ring_fill_n (linux/drivers/net/wireless/ath/ath10k/htt_rx.c:173) ath10k_core Signed-off-by: Zekun Shen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200623221105.3486-1-bruceshenzk@gmail.com --- drivers/net/wireless/ath/ath10k/htt_rx.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index cac05e7bb6b0..69ad4ca1a87c 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -142,6 +142,14 @@ static int __ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num) BUILD_BUG_ON(HTT_RX_RING_FILL_LEVEL >= HTT_RX_RING_SIZE / 2); idx = __le32_to_cpu(*htt->rx_ring.alloc_idx.vaddr); + + if (idx < 0 || idx >= htt->rx_ring.size) { + ath10k_err(htt->ar, "rx ring index is not valid, firmware malfunctioning?\n"); + idx &= htt->rx_ring.size_mask; + ret = -ENOMEM; + goto fail; + } + while (num > 0) { skb = dev_alloc_skb(HTT_RX_BUF_SIZE + HTT_RX_DESC_ALIGN); if (!skb) { -- cgit v1.2.3 From 060202027aa8f382e8d1b7e73f0da2b5cf9191dc Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Sat, 25 Jul 2020 10:09:33 +0300 Subject: ath9k: 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/20200719105052.57997-1-grandmaster@al2klimov.de --- drivers/net/wireless/ath/ath9k/ani.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 5214dd7a3936..41d192709e8e 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -74,7 +74,7 @@ static const struct ani_ofdm_level_entry ofdm_level_table[] = { * Regardless of alignment in time, the antenna signals add constructively after * FFT and improve your reception. For more information: * - * http://en.wikipedia.org/wiki/Maximal-ratio_combining + * https://en.wikipedia.org/wiki/Maximal-ratio_combining */ struct ani_cck_level_entry { -- cgit v1.2.3 From 743adae9da12aeae93b4006d7f7724530e8c54f6 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Sat, 25 Jul 2020 10:09:33 +0300 Subject: ath9k: Fix typo in function name Typo "destoy" made me wonder if correct patch is wrong; fix it. No functional change. Signed-off-by: Pavel Machek (CIP) Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200724083910.GA31930@amd --- drivers/net/wireless/ath/ath9k/hif_usb.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 2 +- drivers/net/wireless/ath/ath9k/wmi.c | 2 +- drivers/net/wireless/ath/ath9k/wmi.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 4ed21dad6a8e..1bb55b9532c9 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -1373,7 +1373,7 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface) if (hif_dev->flags & HIF_USB_READY) { ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged); ath9k_hif_usb_dev_deinit(hif_dev); - ath9k_destoy_wmi(hif_dev->htc_handle->drv_priv); + ath9k_destroy_wmi(hif_dev->htc_handle->drv_priv); ath9k_htc_hw_free(hif_dev->htc_handle); } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 1d6ad8d46607..ac79dfd5be7a 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -973,7 +973,7 @@ err_init: ath9k_stop_wmi(priv); hif_dev = (struct hif_device_usb *)htc_handle->hif_dev; ath9k_hif_usb_dealloc_urbs(hif_dev); - ath9k_destoy_wmi(priv); + ath9k_destroy_wmi(priv); err_free: ieee80211_free_hw(hw); return ret; diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index e7a3127395be..9cf5ae3f7298 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -121,7 +121,7 @@ void ath9k_stop_wmi(struct ath9k_htc_priv *priv) mutex_unlock(&wmi->op_mutex); } -void ath9k_destoy_wmi(struct ath9k_htc_priv *priv) +void ath9k_destroy_wmi(struct ath9k_htc_priv *priv) { kfree(priv->wmi); } diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index d8b912206232..9386b3a9d303 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -189,7 +189,7 @@ void ath9k_wmi_event_tasklet(unsigned long data); void ath9k_fatal_work(struct work_struct *work); void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv); void ath9k_stop_wmi(struct ath9k_htc_priv *priv); -void ath9k_destoy_wmi(struct ath9k_htc_priv *priv); +void ath9k_destroy_wmi(struct ath9k_htc_priv *priv); #define WMI_CMD(_wmi_cmd) \ do { \ -- cgit v1.2.3 From ffe835aa5bdb33572fceb0b14cba6a44c3371bdd Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 24 Jul 2020 12:20:47 +0200 Subject: wcn36xx: Fix multiple AMPDU sessions support Several AMPDU sessions can be started, e.g. for different TIDs. Currently the driver does not take care of the session ID when requesting block-ack (statically set to 0), which leads to never block-acked packet with sessions other than 0. Fix this by saving the session id when creating the ba session and use it in subsequent ba operations. This issue can be reproduced with iperf in two steps (tid 0 strem then tid 6 stream). 1.0 iperf -s # wcn36xx side 1.1 iperf -c ${IP_ADDR} # host side Then 2.0 iperf -s -u -S 0xC0 # wcn36xx side 2.1 iperf -c ${IP_ADDR} -u -S 0xC0 -l 2000 # host side Signed-off-by: Loic Poulain Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1595586052-16081-2-git-send-email-loic.poulain@linaro.org --- drivers/net/wireless/ath/wcn36xx/main.c | 10 ++++++---- drivers/net/wireless/ath/wcn36xx/smd.c | 32 ++++++++++++++++++++++++++------ drivers/net/wireless/ath/wcn36xx/smd.h | 4 ++-- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 702b689c06df..af32bd68859c 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -1083,6 +1083,7 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, u16 tid = params->tid; u16 *ssn = ¶ms->ssn; int ret = 0; + u8 session; wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n", action, tid); @@ -1092,10 +1093,11 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: sta_priv->tid = tid; - wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 0, - get_sta_index(vif, sta_priv)); - wcn36xx_smd_add_ba(wcn); - wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv)); + session = wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 0, + get_sta_index(vif, sta_priv)); + wcn36xx_smd_add_ba(wcn, session); + wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv), tid, + session); break; case IEEE80211_AMPDU_RX_STOP: wcn36xx_smd_del_ba(wcn, tid, get_sta_index(vif, sta_priv)); diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 77269ac7f352..59f9f53fc788 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -2102,6 +2102,22 @@ out: return ret; } +static int wcn36xx_smd_add_ba_session_rsp(void *buf, int len, u8 *session) +{ + struct wcn36xx_hal_add_ba_session_rsp_msg *rsp; + + if (len < sizeof(*rsp)) + return -EINVAL; + + rsp = (struct wcn36xx_hal_add_ba_session_rsp_msg *)buf; + if (rsp->status != WCN36XX_FW_MSG_RESULT_SUCCESS) + return rsp->status; + + *session = rsp->ba_session_id; + + return 0; +} + int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn, struct ieee80211_sta *sta, u16 tid, @@ -2110,6 +2126,7 @@ int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn, u8 sta_index) { struct wcn36xx_hal_add_ba_session_req_msg msg_body; + u8 session_id; int ret; mutex_lock(&wcn->hal_mutex); @@ -2135,17 +2152,20 @@ int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn, wcn36xx_err("Sending hal_add_ba_session failed\n"); goto out; } - ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); + ret = wcn36xx_smd_add_ba_session_rsp(wcn->hal_buf, wcn->hal_rsp_len, + &session_id); if (ret) { wcn36xx_err("hal_add_ba_session response failed err=%d\n", ret); goto out; } + + ret = session_id; out: mutex_unlock(&wcn->hal_mutex); return ret; } -int wcn36xx_smd_add_ba(struct wcn36xx *wcn) +int wcn36xx_smd_add_ba(struct wcn36xx *wcn, u8 session_id) { struct wcn36xx_hal_add_ba_req_msg msg_body; int ret; @@ -2153,7 +2173,7 @@ int wcn36xx_smd_add_ba(struct wcn36xx *wcn) mutex_lock(&wcn->hal_mutex); INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_BA_REQ); - msg_body.session_id = 0; + msg_body.session_id = session_id; msg_body.win_size = WCN36XX_AGGR_BUFFER_SIZE; PREPARE_HAL_BUF(wcn->hal_buf, msg_body); @@ -2212,7 +2232,7 @@ static int wcn36xx_smd_trigger_ba_rsp(void *buf, int len) return rsp->status; } -int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index) +int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u8 session_id) { struct wcn36xx_hal_trigger_ba_req_msg msg_body; struct wcn36xx_hal_trigger_ba_req_candidate *candidate; @@ -2221,7 +2241,7 @@ int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index) mutex_lock(&wcn->hal_mutex); INIT_HAL_MSG(msg_body, WCN36XX_HAL_TRIGGER_BA_REQ); - msg_body.session_id = 0; + msg_body.session_id = session_id; msg_body.candidate_cnt = 1; msg_body.header.len += sizeof(*candidate); PREPARE_HAL_BUF(wcn->hal_buf, msg_body); @@ -2229,7 +2249,7 @@ int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index) candidate = (struct wcn36xx_hal_trigger_ba_req_candidate *) (wcn->hal_buf + sizeof(msg_body)); candidate->sta_index = sta_index; - candidate->tid_bitmap = 1; + candidate->tid_bitmap = 1 << tid; ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); if (ret) { diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h index ff15df8ab56f..68c59df7a0ad 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.h +++ b/drivers/net/wireless/ath/wcn36xx/smd.h @@ -132,9 +132,9 @@ int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn, u16 *ssn, u8 direction, u8 sta_index); -int wcn36xx_smd_add_ba(struct wcn36xx *wcn); +int wcn36xx_smd_add_ba(struct wcn36xx *wcn, u8 session_id); int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index); -int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index); +int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index, u16 tid, u8 session_id); int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value); -- cgit v1.2.3 From fdf21cc3714939dd4327f3d664fe5863d15ccb31 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 24 Jul 2020 12:20:48 +0200 Subject: wcn36xx: Add TX ack support The controller is capable of reporting TX indication which can be used to report TX ack when IEEE80211_TX_CTL_REQ_TX_STATUS is set. The support was only partially implemented. The firmware can be configured for reporting event when a packet is acked, without specifying which packet though. In order to send a packet flagged with TX status callback, we need to stop the queue, submit the packet and wait for the firmware ack event. Then the queue can be restarted and mac80211 status callback called. In case the packet is not acked, no ack event will be received, therefore a timeout mechanism is introduced to restart the queue and call the status cb in case no event is received after a 100ms. Signed-off-by: Loic Poulain Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1595586052-16081-3-git-send-email-loic.poulain@linaro.org --- drivers/net/wireless/ath/wcn36xx/dxe.c | 57 ++++++++++++++++++++++++++++-- drivers/net/wireless/ath/wcn36xx/main.c | 1 + drivers/net/wireless/ath/wcn36xx/txrx.c | 20 +++++++---- drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 1 + 4 files changed, 70 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index bab30f7a443c..63079231e48e 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -334,6 +334,7 @@ void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status) spin_lock_irqsave(&wcn->dxe_lock, flags); skb = wcn->tx_ack_skb; wcn->tx_ack_skb = NULL; + del_timer(&wcn->tx_ack_timer); spin_unlock_irqrestore(&wcn->dxe_lock, flags); if (!skb) { @@ -345,6 +346,8 @@ void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status) if (status == 1) info->flags |= IEEE80211_TX_STAT_ACK; + else + info->flags &= ~IEEE80211_TX_STAT_ACK; wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ack status: %d\n", status); @@ -352,6 +355,32 @@ void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status) ieee80211_wake_queues(wcn->hw); } +static void wcn36xx_dxe_tx_timer(struct timer_list *t) +{ + struct wcn36xx *wcn = from_timer(wcn, t, tx_ack_timer); + struct ieee80211_tx_info *info; + unsigned long flags; + struct sk_buff *skb; + + /* TX Timeout */ + wcn36xx_dbg(WCN36XX_DBG_DXE, "TX timeout\n"); + + spin_lock_irqsave(&wcn->dxe_lock, flags); + skb = wcn->tx_ack_skb; + wcn->tx_ack_skb = NULL; + spin_unlock_irqrestore(&wcn->dxe_lock, flags); + + if (!skb) + return; + + info = IEEE80211_SKB_CB(skb); + info->flags &= ~IEEE80211_TX_STAT_ACK; + info->flags &= ~IEEE80211_TX_STAT_NOACK_TRANSMITTED; + + ieee80211_tx_status_irqsafe(wcn->hw, skb); + ieee80211_wake_queues(wcn->hw); +} + static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch) { struct wcn36xx_dxe_ctl *ctl; @@ -397,6 +426,7 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev) { struct wcn36xx *wcn = (struct wcn36xx *)dev; int int_src, int_reason; + bool transmitted = false; wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_INT_SRC_RAW_REG, &int_src); @@ -434,8 +464,10 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev) int_reason); if (int_reason & (WCN36XX_CH_STAT_INT_DONE_MASK | - WCN36XX_CH_STAT_INT_ED_MASK)) + WCN36XX_CH_STAT_INT_ED_MASK)) { reap_tx_dxes(wcn, &wcn->dxe_tx_h_ch); + transmitted = true; + } } if (int_src & WCN36XX_INT_MASK_CHAN_TX_L) { @@ -473,9 +505,27 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev) int_reason); if (int_reason & (WCN36XX_CH_STAT_INT_DONE_MASK | - WCN36XX_CH_STAT_INT_ED_MASK)) + WCN36XX_CH_STAT_INT_ED_MASK)) { reap_tx_dxes(wcn, &wcn->dxe_tx_l_ch); + transmitted = true; + } + } + + spin_lock(&wcn->dxe_lock); + if (wcn->tx_ack_skb && transmitted) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(wcn->tx_ack_skb); + + /* TX complete, no need to wait for 802.11 ack indication */ + if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS && + info->flags & IEEE80211_TX_CTL_NO_ACK) { + info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + del_timer(&wcn->tx_ack_timer); + ieee80211_tx_status_irqsafe(wcn->hw, wcn->tx_ack_skb); + wcn->tx_ack_skb = NULL; + ieee80211_wake_queues(wcn->hw); + } } + spin_unlock(&wcn->dxe_lock); return IRQ_HANDLED; } @@ -916,6 +966,8 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn) if (ret < 0) goto out_err_irq; + timer_setup(&wcn->tx_ack_timer, wcn36xx_dxe_tx_timer, 0); + return 0; out_err_irq: @@ -934,6 +986,7 @@ void wcn36xx_dxe_deinit(struct wcn36xx *wcn) { free_irq(wcn->tx_irq, wcn); free_irq(wcn->rx_irq, wcn); + del_timer(&wcn->tx_ack_timer); if (wcn->tx_ack_skb) { ieee80211_tx_status_irqsafe(wcn->hw, wcn->tx_ack_skb); diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index af32bd68859c..c19648f2d73a 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -1175,6 +1175,7 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn) ieee80211_hw_set(wcn->hw, SIGNAL_DBM); ieee80211_hw_set(wcn->hw, HAS_RATE_CONTROL); ieee80211_hw_set(wcn->hw, SINGLE_SCAN_ON_ALL_BANDS); + ieee80211_hw_set(wcn->hw, REPORTS_TX_ACK_STATUS); wcn->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index dda6d8946aef..0a418ac30765 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -298,9 +298,10 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, bd->dpu_sign = __vif_priv->self_ucast_dpu_sign; } - if (ieee80211_is_nullfunc(hdr->frame_control) || - (sta_priv && !sta_priv->is_data_encrypted)) + if (ieee80211_is_any_nullfunc(hdr->frame_control) || + (sta_priv && !sta_priv->is_data_encrypted)) { bd->dpu_ne = 1; + } if (bcast) { bd->ub = 1; @@ -394,9 +395,9 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, bd.dpu_rf = WCN36XX_BMU_WQ_TX; - bd.tx_comp = !!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS); - if (bd.tx_comp) { + if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested\n"); + spin_lock_irqsave(&wcn->dxe_lock, flags); if (wcn->tx_ack_skb) { spin_unlock_irqrestore(&wcn->dxe_lock, flags); @@ -409,10 +410,15 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, /* Only one at a time is supported by fw. Stop the TX queues * until the ack status gets back. - * - * TODO: Add watchdog in case FW does not answer */ ieee80211_stop_queues(wcn->hw); + + /* TX watchdog if no TX irq or ack indication received */ + mod_timer(&wcn->tx_ack_timer, jiffies + HZ / 10); + + /* Request ack indication from the firmware */ + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) + bd.tx_comp = 1; } /* Data frames served first*/ @@ -426,7 +432,7 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, bd.tx_bd_sign = 0xbdbdbdbd; ret = wcn36xx_dxe_tx_frame(wcn, vif_priv, &bd, skb, is_low); - if (ret && bd.tx_comp) { + if (ret && (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) { /* If the skb has not been transmitted, * don't keep a reference to it. */ diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index a58f313983b9..2d89849c630b 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -245,6 +245,7 @@ struct wcn36xx { struct wcn36xx_dxe_mem_pool data_mem_pool; struct sk_buff *tx_ack_skb; + struct timer_list tx_ack_timer; /* RF module */ unsigned rf_id; -- cgit v1.2.3 From 1c20560607e6e142af76b9bd57e275b9053958a1 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 24 Jul 2020 12:20:49 +0200 Subject: wcn36xx: Increase number of TX retries Increase the short/long retry limit to 15 in order to impove TX robustness in noisy/busy environment. 15 is the default value defined in the downstream driver. Observed number of ack timeout is reduced with this change. Signed-off-by: Loic Poulain Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1595586052-16081-4-git-send-email-loic.poulain@linaro.org --- drivers/net/wireless/ath/wcn36xx/smd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 59f9f53fc788..908cc6cf7b1a 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -45,8 +45,8 @@ static struct wcn36xx_cfg_val wcn36xx_cfg_vals[] = { WCN36XX_CFG_VAL(MAX_MEDIUM_TIME, 6000), WCN36XX_CFG_VAL(MAX_MPDUS_IN_AMPDU, 64), WCN36XX_CFG_VAL(RTS_THRESHOLD, 2347), - WCN36XX_CFG_VAL(SHORT_RETRY_LIMIT, 6), - WCN36XX_CFG_VAL(LONG_RETRY_LIMIT, 6), + WCN36XX_CFG_VAL(SHORT_RETRY_LIMIT, 15), + WCN36XX_CFG_VAL(LONG_RETRY_LIMIT, 15), WCN36XX_CFG_VAL(FRAGMENTATION_THRESHOLD, 8000), WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ZERO, 5), WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ONE, 10), -- cgit v1.2.3 From 512b191d965237249999b3c58600fe50356ab323 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 24 Jul 2020 12:20:50 +0200 Subject: wcn36xx: Fix TX data path This patch contains the following fixes: - Use correct queue for submitting QoS packet. The queue id to use is a one-to-one mapping with the TID. - Don't encrypt a frame with IEEE80211_TX_INTFL_DONT_ENCRYPT flag. - Use the 'special queue' for null packets, preventing the firmware to submit it as AMPDU. Signed-off-by: Loic Poulain Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1595586052-16081-5-git-send-email-loic.poulain@linaro.org --- drivers/net/wireless/ath/wcn36xx/txrx.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index 0a418ac30765..52aff4c63587 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -267,9 +267,11 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, bool bcast) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = NULL; struct wcn36xx_vif *__vif_priv = NULL; - bool is_data_qos; + bool is_data_qos = ieee80211_is_data_qos(hdr->frame_control); + u16 tid = 0; bd->bd_rate = WCN36XX_BD_RATE_DATA; @@ -298,24 +300,33 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, bd->dpu_sign = __vif_priv->self_ucast_dpu_sign; } - if (ieee80211_is_any_nullfunc(hdr->frame_control) || - (sta_priv && !sta_priv->is_data_encrypted)) { + if (is_data_qos) { + tid = ieee80211_get_tid(hdr); + /* TID->QID is one-to-one mapping */ + bd->queue_id = tid; + } + + if (info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT || + (sta_priv && !sta_priv->is_data_encrypted)) { bd->dpu_ne = 1; } + if (ieee80211_is_any_nullfunc(hdr->frame_control)) { + /* Don't use a regular queue for null packet (no ampdu) */ + bd->queue_id = WCN36XX_TX_U_WQ_ID; + } + if (bcast) { bd->ub = 1; bd->ack_policy = 1; } *vif_priv = __vif_priv; - is_data_qos = ieee80211_is_data_qos(hdr->frame_control); - wcn36xx_set_tx_pdu(bd, is_data_qos ? sizeof(struct ieee80211_qos_hdr) : sizeof(struct ieee80211_hdr_3addr), - skb->len, sta_priv ? sta_priv->tid : 0); + skb->len, tid); if (sta_priv && is_data_qos) wcn36xx_tx_start_ampdu(wcn, sta_priv, skb); -- cgit v1.2.3 From 84aff52e4f57ed4702ec328b839941cd29551d49 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 24 Jul 2020 12:20:52 +0200 Subject: wcn36xx: Use sequence number allocated by mac80211 Instead of using the firmware generated sequence number, use the one already allocated by the mac80211 layer. This allows better control of the sequence numbers and avoid to rely on same sequence for Data, QOS Data and QOS Null Data packets. Signed-off-by: Loic Poulain Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1595586052-16081-7-git-send-email-loic.poulain@linaro.org --- drivers/net/wireless/ath/wcn36xx/txrx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index 52aff4c63587..f5872e7dfb51 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -207,7 +207,8 @@ static void wcn36xx_set_tx_pdu(struct wcn36xx_tx_bd *bd, bd->pdu.mpdu_header_off; bd->pdu.mpdu_len = len; bd->pdu.tid = tid; - bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_DPU_QOS; + /* Use seq number generated by mac80211 */ + bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_HOST; } static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn, -- cgit v1.2.3 From 221af8135478939eaedf1f558aea32e08e05ae65 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 27 Jul 2020 14:35:20 -0500 Subject: ath9k: Use fallthrough pseudo-keyword Replace the existing /* fall through */ comments and its variants with the new pseudo-keyword macro fallthrough[1]. [1] https://www.kernel.org/doc/html/v5.7/process/deprecated.html?highlight=fallthrough#implicit-switch-case-fall-through Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200727193520.GA832@embeddedor --- drivers/net/wireless/ath/ath9k/ar5008_phy.c | 4 ++-- drivers/net/wireless/ath/ath9k/ar9002_mac.c | 2 +- drivers/net/wireless/ath/ath9k/ar9002_phy.c | 2 +- drivers/net/wireless/ath/ath9k/ar9003_mac.c | 2 +- drivers/net/wireless/ath/ath9k/channel.c | 4 ++-- drivers/net/wireless/ath/ath9k/eeprom_def.c | 2 +- drivers/net/wireless/ath/ath9k/hw.c | 6 +++--- drivers/net/wireless/ath/ath9k/main.c | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index dae95402eb3a..0d34356baf73 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -579,14 +579,14 @@ static void ar5008_hw_init_chain_masks(struct ath_hw *ah) case 0x5: REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN); - /* fall through */ + fallthrough; case 0x3: if (ah->hw_version.macVersion == AR_SREV_REVISION_5416_10) { REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7); REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7); break; } - /* fall through */ + fallthrough; case 0x1: case 0x2: case 0x7: diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 4b3c9b108197..ce9a0a53771e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -267,7 +267,7 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) switch (i->aggr) { case AGGR_BUF_FIRST: ctl6 |= SM(i->aggr_len, AR_AggrLen); - /* fall through */ + fallthrough; case AGGR_BUF_MIDDLE: ctl1 |= AR_IsAggr | AR_MoreAggr; ctl6 |= SM(i->ndelim, AR_PadDelim); diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c index 6f32b8d2ec7f..fcfed8e59d29 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c @@ -119,7 +119,7 @@ static int ar9002_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) aModeRefSel = 2; if (aModeRefSel) break; - /* fall through */ + fallthrough; case 1: default: aModeRefSel = 0; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index e1fe7a7c3ad8..76b538942a79 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -120,7 +120,7 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) switch (i->aggr) { case AGGR_BUF_FIRST: ctl17 |= SM(i->aggr_len, AR_AggrLen); - /* fall through */ + fallthrough; case AGGR_BUF_MIDDLE: ctl12 |= AR_IsAggr | AR_MoreAggr; ctl17 |= SM(i->ndelim, AR_PadDelim); diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index fd61ae4782b6..6cf087522157 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -706,7 +706,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, "Move chanctx state from FORCE_ACTIVE to IDLE\n"); sc->sched.state = ATH_CHANCTX_STATE_IDLE; - /* fall through */ + fallthrough; case ATH_CHANCTX_EVENT_SWITCH: if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) || sc->sched.state == ATH_CHANCTX_STATE_FORCE_ACTIVE || @@ -1080,7 +1080,7 @@ static void ath_offchannel_timer(struct timer_list *t) mod_timer(&sc->offchannel.timer, jiffies + HZ / 10); break; } - /* fall through */ + fallthrough; case ATH_OFFCHANNEL_SUSPEND: if (!sc->offchannel.scan_req) return; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 56b44fc7a8e6..9729a69d3e2e 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -402,7 +402,7 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, return AR5416_PWR_TABLE_OFFSET_DB; case EEP_ANTENNA_GAIN_2G: band = 1; - /* fall through */ + fallthrough; case EEP_ANTENNA_GAIN_5G: return max_t(u8, max_t(u8, pModal[band].antennaGainCh[0], diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8c97db73e34c..6609ce122e6e 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1277,12 +1277,12 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; } - /* fall through */ + fallthrough; case NL80211_IFTYPE_OCB: case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: set |= AR_STA_ID1_STA_AP; - /* fall through */ + fallthrough; case NL80211_IFTYPE_STATION: REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; @@ -2293,7 +2293,7 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) case NL80211_IFTYPE_ADHOC: REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); - /* fall through */ + fallthrough; case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a47f6e978095..0ea3b80f664c 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1934,7 +1934,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: flush = true; - /* fall through */ + fallthrough; case IEEE80211_AMPDU_TX_STOP_CONT: ath9k_ps_wakeup(sc); ath_tx_aggr_stop(sc, sta, tid); -- cgit v1.2.3 From 18c25b4019caa94deee67e839aea6b7b626e70d5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 26 Jul 2020 12:58:32 +0200 Subject: ath: drop unnecessary list_empty list_for_each_entry{_safe} is able to handle an empty list. The only effect of avoiding the loop is not initializing the index variable. Drop list_empty tests in cases where these variables are not used. Note that list_for_each_entry{_safe} is defined in terms of list_first_entry, which indicates that it should not be used on an empty list. But in list_for_each_entry{_safe}, the element obtained by list_first_entry is not really accessed, only the address of its list_head field is compared to the address of the list head, so the list_first_entry is safe. The semantic patch that makes this change for the list_for_each_entry case is as follows: (http://coccinelle.lip6.fr/) @@ expression x,e; statement S; identifier i; @@ -if (!(list_empty(x))) list_for_each_entry(i,x,...) S ... when != i ? i = e Signed-off-by: Julia Lawall Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1595761112-11003-8-git-send-email-Julia.Lawall@inria.fr --- drivers/net/wireless/ath/dfs_pattern_detector.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c index a274eb0d1968..0813473793df 100644 --- a/drivers/net/wireless/ath/dfs_pattern_detector.c +++ b/drivers/net/wireless/ath/dfs_pattern_detector.c @@ -253,17 +253,15 @@ channel_detector_get(struct dfs_pattern_detector *dpd, u16 freq) static void dpd_reset(struct dfs_pattern_detector *dpd) { struct channel_detector *cd; - if (!list_empty(&dpd->channel_detectors)) - list_for_each_entry(cd, &dpd->channel_detectors, head) - channel_detector_reset(dpd, cd); + list_for_each_entry(cd, &dpd->channel_detectors, head) + channel_detector_reset(dpd, cd); } static void dpd_exit(struct dfs_pattern_detector *dpd) { struct channel_detector *cd, *cd0; - if (!list_empty(&dpd->channel_detectors)) - list_for_each_entry_safe(cd, cd0, &dpd->channel_detectors, head) - channel_detector_exit(dpd, cd); + list_for_each_entry_safe(cd, cd0, &dpd->channel_detectors, head) + channel_detector_exit(dpd, cd); kfree(dpd); } @@ -331,9 +329,8 @@ static bool dpd_set_domain(struct dfs_pattern_detector *dpd, return false; /* delete all channel detectors for previous DFS domain */ - if (!list_empty(&dpd->channel_detectors)) - list_for_each_entry_safe(cd, cd0, &dpd->channel_detectors, head) - channel_detector_exit(dpd, cd); + list_for_each_entry_safe(cd, cd0, &dpd->channel_detectors, head) + channel_detector_exit(dpd, cd); dpd->radar_spec = rt->radar_types; dpd->num_radar_types = rt->num_radar_types; -- cgit v1.2.3 From 5b525ce88af90c6d986b25c21a868c0f9c4cc021 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Sun, 19 Jul 2020 12:40:41 +0200 Subject: ath5k: 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/20200719104041.57916-1-grandmaster@al2klimov.de --- drivers/net/wireless/ath/ath5k/ath5k.h | 2 +- drivers/net/wireless/ath/ath5k/rfbuffer.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 979800c6f57f..234ea939d316 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -410,7 +410,7 @@ enum ath5k_radio { * This article claims Super G sticks to bonding of channels 5 and 6 for * USA: * - * http://www.pcworld.com/article/id,113428-page,1/article.html + * https://www.pcworld.com/article/id,113428-page,1/article.html * * The channel bonding seems to be driver specific though. * diff --git a/drivers/net/wireless/ath/ath5k/rfbuffer.h b/drivers/net/wireless/ath/ath5k/rfbuffer.h index aed34d9954c0..151935c4827f 100644 --- a/drivers/net/wireless/ath/ath5k/rfbuffer.h +++ b/drivers/net/wireless/ath/ath5k/rfbuffer.h @@ -42,7 +42,7 @@ * Also check out reg.h and U.S. Patent 6677779 B1 (about buffer * registers and control registers): * - * http://www.google.com/patents?id=qNURAAAAEBAJ + * https://www.google.com/patents?id=qNURAAAAEBAJ */ -- cgit v1.2.3 From 2fd3c8f34d08af0a6236085f9961866ad92ef9ec Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Fri, 14 Aug 2020 18:17:08 +0300 Subject: ath10k: start recovery process when payload length exceeds max htc length for sdio When simulate random transfer fail for sdio write and read, it happened "payload length exceeds max htc length" and recovery later sometimes. Test steps: 1. Add config and update kernel: CONFIG_FAIL_MMC_REQUEST=y CONFIG_FAULT_INJECTION=y CONFIG_FAULT_INJECTION_DEBUG_FS=y 2. Run simulate fail: cd /sys/kernel/debug/mmc1/fail_mmc_request echo 10 > probability echo 10 > times # repeat until hitting issues 3. It happened payload length exceeds max htc length. [ 199.935506] ath10k_sdio mmc1:0001:1: payload length 57005 exceeds max htc length: 4088 .... [ 264.990191] ath10k_sdio mmc1:0001:1: payload length 57005 exceeds max htc length: 4088 4. after some time, such as 60 seconds, it start recovery which triggered by wmi command timeout for periodic scan. [ 269.229232] ieee80211 phy0: Hardware restart was requested [ 269.734693] ath10k_sdio mmc1:0001:1: device successfully recovered The simulate fail of sdio is not a real sdio transter fail, it only set an error status in mmc_should_fail_request after the transfer end, actually the transfer is success, then sdio_io_rw_ext_helper will return error status and stop transfer the left data. For example, the really RX len is 286 bytes, then it will split to 2 blocks in sdio_io_rw_ext_helper, one is 256 bytes, left is 30 bytes, if the first 256 bytes get an error status by mmc_should_fail_request,then the left 30 bytes will not read in this RX operation. Then when the next RX arrive, the left 30 bytes will be considered as the header of the read, the top 4 bytes of the 30 bytes will be considered as lookaheads, but actually the 4 bytes is not the lookaheads, so the len from this lookaheads is not correct, it exceeds max htc length 4088 sometimes. When happened exceeds, the buffer chain is not matched between firmware and ath10k, then it need to start recovery ASAP. Recently then recovery will be started by wmi command timeout, but it will be long time later, for example, it is 60+ seconds later from the periodic scan, if it does not have periodic scan, it will be longer. Start recovery when it happened "payload length exceeds max htc length" will be reasonable. This patch only effect sdio chips. Tested with QCA6174 SDIO with firmware WLAN.RMH.4.4.1-00029. Signed-off-by: Wen Gong Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200108031957.22308-3-wgong@codeaurora.org --- drivers/net/wireless/ath/ath10k/sdio.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 63f882c690bf..0841e69b10b1 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -557,6 +557,10 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar, le16_to_cpu(htc_hdr->len), ATH10K_HTC_MBOX_MAX_PAYLOAD_LENGTH); ret = -ENOMEM; + + queue_work(ar->workqueue, &ar->restart_work); + ath10k_warn(ar, "exceeds length, start recovery\n"); + goto err; } -- cgit v1.2.3 From e39f32afc6d2157efbd601911d872eb46f93e866 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Fri, 14 Aug 2020 18:55:50 +0300 Subject: ath10k: add wmi service peer stat info for wmi tlv ath10k_sta_statistics is used to report info for iw wlan0 link, it check ath10k_peer_stats_enabled, and ath10k_peer_stats_enabled check WMI_SERVICE_PEER_STATS bit of ar->wmi.svc_map. SVCMAP() for WMI_SERVICE_PEER_STATS was defined only for wmi_10x_svc_map and wmi_10_4_svc_map interfaces, it missed in wmi_tlv_svc_map, so it is not usable for iw wlan0 link for wmi tlv interface. If firmware report WMI_TLV_SERVICE_PEER_STATS_INFO for wmi tlv, then enable the WMI_SERVICE_PEER_STATS bit in ath10k, and then it pass check in ath10k_peer_stats_enabled and ath10k_sta_statistics pass check. Tested-on: QCA6174 hw3.2 SDIO WLAN.RMH.4.4.1-00048 Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00110-QCARMSWP-1 Signed-off-by: Wen Gong Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597312029-32348-2-git-send-email-wgong@codeaurora.org --- drivers/net/wireless/ath/ath10k/wmi-tlv.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index e77b97ca5c7f..b39c9b78b32b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1614,6 +1614,8 @@ wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len) WMI_SERVICE_MESH_11S, len); SVCMAP(WMI_TLV_SERVICE_SYNC_DELETE_CMDS, WMI_SERVICE_SYNC_DELETE_CMDS, len); + SVCMAP(WMI_TLV_SERVICE_PEER_STATS_INFO, + WMI_SERVICE_PEER_STATS, len); } static inline void -- cgit v1.2.3 From 1cd6ba8ae33ecc4a99a842d8f8e904dee79113bc Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Fri, 14 Aug 2020 18:55:50 +0300 Subject: ath10k: remove return for NL80211_STA_INFO_TX_BITRATE ath10k_sta_statistics is used to report many info to iw wlan0 link, if it return for empty legacy and nss of arsta->txrate, then the other stats after it will not be set. It has 4 bit to set after the return: NL80211_STA_INFO_TX_FAILED NL80211_STA_INFO_RX_BITRATE NL80211_STA_INFO_TX_BITRATE NL80211_STA_INFO_TX_RETRIES This patch not effect the info of above 4 bit for all hardware, reason as below: NL80211_STA_INFO_TX_FAILED is only for htt.disable_tx_comp is true, it is for QCA6174 SDIO. NL80211_STA_INFO_RX_BITRATE and NL80211_STA_INFO_TX_BITRATE are both set in ath10k_mac_sta_get_peer_stats_info, it is only enabled for chips which supports_peer_stats_info is true in hw_params, recently only for QCA6174 SDIO, NL80211_STA_INFO_TX_BITRATE is set again in function ath10k_mac_sta_get_peer_stats_info because the value which parsed from arsta->tx_rate_code and arsta->tx_bitrate_kbps is correct for QCA6174 SDIO and PCIe, and the value arsta->txrate is not correct for QCA6174 SDIO and PCIe, so it need to set again with the correct value. NL80211_STA_INFO_TX_RETRIES is use value of arsta->tx_retries, it is set in ath10k_update_per_peer_tx_stats, which accumulate the retry_pkts in HTT message from firmware, if the chips not support this feature, then it is always 0 after accumulate, then iw wlan0 station dump always show 0 for retry count. If not set NL80211_STA_INFO_TX_RETRIES here, then it is still 0, so the result is same, then set NL80211_STA_INFO_TX_RETRIES has no effect. Tested-on: QCA6174 hw3.2 SDIO WLAN.RMH.4.4.1-00048 Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00110-QCARMSWP-1 Signed-off-by: Wen Gong Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597312029-32348-3-git-send-email-wgong@codeaurora.org --- drivers/net/wireless/ath/ath10k/mac.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 3e3896214e8b..4554a82d0105 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -8533,18 +8533,17 @@ static void ath10k_sta_statistics(struct ieee80211_hw *hw, sinfo->rx_duration = arsta->rx_duration; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION); - if (!arsta->txrate.legacy && !arsta->txrate.nss) - return; - - if (arsta->txrate.legacy) { - sinfo->txrate.legacy = arsta->txrate.legacy; - } else { - sinfo->txrate.mcs = arsta->txrate.mcs; - sinfo->txrate.nss = arsta->txrate.nss; - sinfo->txrate.bw = arsta->txrate.bw; + if (arsta->txrate.legacy || arsta->txrate.nss) { + if (arsta->txrate.legacy) { + sinfo->txrate.legacy = arsta->txrate.legacy; + } else { + sinfo->txrate.mcs = arsta->txrate.mcs; + sinfo->txrate.nss = arsta->txrate.nss; + sinfo->txrate.bw = arsta->txrate.bw; + } + sinfo->txrate.flags = arsta->txrate.flags; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); } - sinfo->txrate.flags = arsta->txrate.flags; - sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); if (ar->htt.disable_tx_comp) { sinfo->tx_failed = arsta->tx_failed; -- cgit v1.2.3 From cbcbabb9c3950889664eb2380b71d9ac60ec5ce5 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Fri, 14 Aug 2020 18:55:51 +0300 Subject: ath10k: enable supports_peer_stats_info for QCA6174 PCI devices When using QCA6174 PCI devices working in station mode, after connected to AP, tx bitrate is always '1.0 MBit/s' in output of command 'iw wlan0 station dump'. (QCA6174 SDIO devices are working fine.) After this patch, it show correct bitrate: Station c4:04:15:5d:97:22 (on wls1) inactive time: 312 ms rx bytes: 31496 rx packets: 173 tx bytes: 8625 tx packets: 46 tx retries: 0 tx failed: 0 signal: -76 [-88, -80] dBm signal avg: -75 [-82, -77] dBm tx bitrate: 39.0 MBit/s MCS 4 rx bitrate: 26.0 MBit/s MCS 3 Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00110-QCARMSWP-1 Signed-off-by: Wen Gong Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597312029-32348-4-git-send-email-wgong@codeaurora.org --- drivers/net/wireless/ath/ath10k/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 22b6937ac225..c4f098c4431f 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -334,6 +334,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_filter_reset_required = true, .fw_diag_ce_download = true, .tx_stats_over_pktlog = false, + .supports_peer_stats_info = true, }, { .id = QCA99X0_HW_2_0_DEV_VERSION, -- cgit v1.2.3 From db04b755edaa0c9d03e99f915e9060fef50277f1 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Fri, 14 Aug 2020 16:04:54 +0800 Subject: ath10k: correct the array index from mcs index for HT mode for QCA6174 The mcs index of HT mode is 0 to 31, please refer http://mcsindex.com/. Its spatial stream(Nss) number is from 1 to 4, mcs index is 0~7 for Nss=1, 8~15 for Nss=2, 16~23 for Nss=3 and 24~31 is for Nss=4. The mcs is reported from firmware in wmi_tlv_peer_stats_info of event WMI_TLV_PEER_STATS_INFO_EVENTID, its range is from 0~15 for QCA6174 SDIO and PCIe. It is for both Nss=1 and Nss=2, and it has 2 rate table supported_ht_mcs_rate_nss1 and supported_ht_mcs_rate_nss2 in ath10k, they are for Nss=1 and Nss=2, each table has 8 rates. It need to find the matched row number with the mcs index, for example, mcs index is 2, it is <=7, so it is Nss=1, and match row 2 in table of Nss=1. If mcs index is 12, it is >= 8 and <= 15, so it is Nss=2, it match row 4(12-8) in table of Nss=2. If mcs index is >=16, it is for Nss=3/4, it need to add rate table, so it is not support in current ath10k. This patch is to find the row number in rate table of Nss=1 or Nss=2 with the mcs index reported from firmware. This patch only effect the chips which supports_peer_stats_info of its hw_params is true, it is true only for QCA6174 currently. Tested-on: QCA6174 hw3.2 SDIO WLAN.RMH.4.4.1-00048 Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00110-QCARMSWP-1 Signed-off-by: Wen Gong Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597392294-13124-1-git-send-email-wgong@codeaurora.org --- drivers/net/wireless/ath/ath10k/mac.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 4554a82d0105..de3922e98dd8 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -8368,19 +8368,32 @@ static void ath10k_mac_get_rate_flags_ht(struct ath10k *ar, u32 rate, u8 nss, u8 u8 *flags, u8 *bw) { struct ath10k_index_ht_data_rate_type *mcs_rate; + u8 index; + size_t len_nss1 = ARRAY_SIZE(supported_ht_mcs_rate_nss1); + size_t len_nss2 = ARRAY_SIZE(supported_ht_mcs_rate_nss2); + + if (mcs >= (len_nss1 + len_nss2)) { + ath10k_warn(ar, "not supported mcs %d in current rate table", mcs); + return; + } mcs_rate = (struct ath10k_index_ht_data_rate_type *) ((nss == 1) ? &supported_ht_mcs_rate_nss1 : &supported_ht_mcs_rate_nss2); - if (rate == mcs_rate[mcs].supported_rate[0]) { + if (mcs >= len_nss1) + index = mcs - len_nss1; + else + index = mcs; + + if (rate == mcs_rate[index].supported_rate[0]) { *bw = RATE_INFO_BW_20; - } else if (rate == mcs_rate[mcs].supported_rate[1]) { + } else if (rate == mcs_rate[index].supported_rate[1]) { *bw |= RATE_INFO_BW_40; - } else if (rate == mcs_rate[mcs].supported_rate[2]) { + } else if (rate == mcs_rate[index].supported_rate[2]) { *bw |= RATE_INFO_BW_20; *flags |= RATE_INFO_FLAGS_SHORT_GI; - } else if (rate == mcs_rate[mcs].supported_rate[3]) { + } else if (rate == mcs_rate[index].supported_rate[3]) { *bw |= RATE_INFO_BW_40; *flags |= RATE_INFO_FLAGS_SHORT_GI; } else { @@ -8441,6 +8454,9 @@ static void ath10k_mac_parse_bitrate(struct ath10k *ar, u32 rate_code, u8 mcs = WMI_TLV_GET_HW_RC_RATE_V1(rate_code); u8 flags = 0, bw = 0; + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac parse rate code 0x%x bitrate %d kbps\n", + rate_code, bitrate_kbps); + if (preamble == WMI_RATE_PREAMBLE_HT) mode = ATH10K_PHY_MODE_HT; else if (preamble == WMI_RATE_PREAMBLE_VHT) -- cgit v1.2.3 From 322b60ceb0f321b4b9c41717f7306c0dbaf0279b Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Thu, 13 Aug 2020 12:04:17 +0300 Subject: ath11k: do not depend on ARCH_QCOM for ath11k With only IPQ8074 supported ath11k was only usable on Qualcomm architectures. But now that we are adding QCA6390 PCI support to ath11k that's not the case anymore and it can be used on any architecture supporting PCI. So remove the dependency on ARCH_QCOM. After that there is also no need to depend on COMPILE_TEST. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597309466-19688-2-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/Kconfig b/drivers/net/wireless/ath/ath11k/Kconfig index 88a97356f0a1..0fd44d83e0e9 100644 --- a/drivers/net/wireless/ath/ath11k/Kconfig +++ b/drivers/net/wireless/ath/ath11k/Kconfig @@ -4,7 +4,6 @@ config ATH11K depends on MAC80211 && HAS_DMA depends on REMOTEPROC depends on CRYPTO_MICHAEL_MIC - depends on ARCH_QCOM || COMPILE_TEST select ATH_COMMON select QCOM_QMI_HELPERS help -- cgit v1.2.3 From 9de2ad43d46c80fcb4072f2e9bf36623f7e5b4ff Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Thu, 13 Aug 2020 12:04:18 +0300 Subject: ath11k: add hw_params entry for QCA6390 Define own firmware directory and settings for QCA6390. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597309466-19688-3-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/core.c | 12 ++++++++++++ drivers/net/wireless/ath/ath11k/core.h | 1 + drivers/net/wireless/ath/ath11k/hw.c | 4 ++++ drivers/net/wireless/ath/ath11k/hw.h | 1 + 4 files changed, 18 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 38e830a2395b..093faf20f324 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -30,6 +30,18 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .bdf_addr = 0x4B0C0000, .hw_ops = &ipq8074_ops, }, + { + .name = "qca6390 hw2.0", + .hw_rev = ATH11K_HW_QCA6390_HW20, + .fw = { + .dir = "QCA6390/hw2.0", + .board_size = 256 * 1024, + .cal_size = 256 * 1024, + }, + .max_radios = 3, + .bdf_addr = 0x4B0C0000, + .hw_ops = &qca6390_ops, + }, }; static int ath11k_core_create_board_name(struct ath11k_base *ab, char *name, diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index b6ccd9f93853..c48d53ec4fa7 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -90,6 +90,7 @@ struct ath11k_skb_rxcb { enum ath11k_hw_rev { ATH11K_HW_IPQ8074, + ATH11K_HW_QCA6390_HW20, }; enum ath11k_firmware_mode { diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index 7cc5f36509c0..6feb0f699cfc 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -32,3 +32,7 @@ const struct ath11k_hw_ops ipq8074_ops = { const struct ath11k_hw_ops ipq6018_ops = { .get_hw_mac_from_pdev_id = ath11k_hw_ipq6018_mac_from_pdev_id, }; + +const struct ath11k_hw_ops qca6390_ops = { + .get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id, +}; diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index f31d53f6adb8..1958830c01ec 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -120,6 +120,7 @@ struct ath11k_hw_params { extern const struct ath11k_hw_ops ipq8074_ops; extern const struct ath11k_hw_ops ipq6018_ops; +extern const struct ath11k_hw_ops qca6390_ops; static inline int ath11k_hw_get_mac_from_pdev_id(struct ath11k_hw_params *hw, -- cgit v1.2.3 From 34d5a3a88436327dae73550d8e0d831b95dd5d0f Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 13 Aug 2020 12:04:19 +0300 Subject: ath11k: move ring mask definitions to hw_params This is needed for splitting ahb and pci modules as they have different ring mask settings. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597309466-19688-4-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/ahb.c | 88 ++++------------------------------ drivers/net/wireless/ath/ath11k/core.c | 2 + drivers/net/wireless/ath/ath11k/core.h | 10 ---- drivers/net/wireless/ath/ath11k/dp.c | 22 ++++----- drivers/net/wireless/ath/ath11k/hw.c | 68 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/hw.h | 17 +++++++ 6 files changed, 106 insertions(+), 101 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 7e9bfeaaf4d2..e3228a4f485f 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -321,78 +321,6 @@ static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { "tcl2host-status-ring", }; -#define ATH11K_TX_RING_MASK_0 0x1 -#define ATH11K_TX_RING_MASK_1 0x2 -#define ATH11K_TX_RING_MASK_2 0x4 - -#define ATH11K_RX_RING_MASK_0 0x1 -#define ATH11K_RX_RING_MASK_1 0x2 -#define ATH11K_RX_RING_MASK_2 0x4 -#define ATH11K_RX_RING_MASK_3 0x8 - -#define ATH11K_RX_ERR_RING_MASK_0 0x1 - -#define ATH11K_RX_WBM_REL_RING_MASK_0 0x1 - -#define ATH11K_REO_STATUS_RING_MASK_0 0x1 - -#define ATH11K_RXDMA2HOST_RING_MASK_0 0x1 -#define ATH11K_RXDMA2HOST_RING_MASK_1 0x2 -#define ATH11K_RXDMA2HOST_RING_MASK_2 0x4 - -#define ATH11K_HOST2RXDMA_RING_MASK_0 0x1 -#define ATH11K_HOST2RXDMA_RING_MASK_1 0x2 -#define ATH11K_HOST2RXDMA_RING_MASK_2 0x4 - -#define ATH11K_RX_MON_STATUS_RING_MASK_0 0x1 -#define ATH11K_RX_MON_STATUS_RING_MASK_1 0x2 -#define ATH11K_RX_MON_STATUS_RING_MASK_2 0x4 - -const u8 ath11k_tx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = { - ATH11K_TX_RING_MASK_0, - ATH11K_TX_RING_MASK_1, - ATH11K_TX_RING_MASK_2, -}; - -const u8 rx_mon_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = { - 0, 0, 0, 0, - ATH11K_RX_MON_STATUS_RING_MASK_0, - ATH11K_RX_MON_STATUS_RING_MASK_1, - ATH11K_RX_MON_STATUS_RING_MASK_2, -}; - -const u8 ath11k_rx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = { - 0, 0, 0, 0, 0, 0, 0, - ATH11K_RX_RING_MASK_0, - ATH11K_RX_RING_MASK_1, - ATH11K_RX_RING_MASK_2, - ATH11K_RX_RING_MASK_3, -}; - -const u8 ath11k_rx_err_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = { - ATH11K_RX_ERR_RING_MASK_0, -}; - -const u8 ath11k_rx_wbm_rel_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = { - ATH11K_RX_WBM_REL_RING_MASK_0, -}; - -const u8 ath11k_reo_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = { - ATH11K_REO_STATUS_RING_MASK_0, -}; - -const u8 ath11k_rxdma2host_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = { - ATH11K_RXDMA2HOST_RING_MASK_0, - ATH11K_RXDMA2HOST_RING_MASK_1, - ATH11K_RXDMA2HOST_RING_MASK_2, -}; - -const u8 ath11k_host2rxdma_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = { - ATH11K_HOST2RXDMA_RING_MASK_0, - ATH11K_HOST2RXDMA_RING_MASK_1, - ATH11K_HOST2RXDMA_RING_MASK_2, -}; - /* enum ext_irq_num - irq numbers that can be used by external modules * like datapath */ @@ -750,39 +678,39 @@ static int ath11k_ahb_ext_irq_config(struct ath11k_base *ab) ath11k_ahb_ext_grp_napi_poll, NAPI_POLL_WEIGHT); for (j = 0; j < ATH11K_EXT_IRQ_NUM_MAX; j++) { - if (ath11k_tx_ring_mask[i] & BIT(j)) { + if (ab->hw_params.ring_mask->tx[i] & BIT(j)) { irq_grp->irqs[num_irq++] = wbm2host_tx_completions_ring1 - j; } - if (ath11k_rx_ring_mask[i] & BIT(j)) { + if (ab->hw_params.ring_mask->rx[i] & BIT(j)) { irq_grp->irqs[num_irq++] = reo2host_destination_ring1 - j; } - if (ath11k_rx_err_ring_mask[i] & BIT(j)) + if (ab->hw_params.ring_mask->rx_err[i] & BIT(j)) irq_grp->irqs[num_irq++] = reo2host_exception; - if (ath11k_rx_wbm_rel_ring_mask[i] & BIT(j)) + if (ab->hw_params.ring_mask->rx_wbm_rel[i] & BIT(j)) irq_grp->irqs[num_irq++] = wbm2host_rx_release; - if (ath11k_reo_status_ring_mask[i] & BIT(j)) + if (ab->hw_params.ring_mask->reo_status[i] & BIT(j)) irq_grp->irqs[num_irq++] = reo2host_status; if (j < ab->hw_params.max_radios) { - if (ath11k_rxdma2host_ring_mask[i] & BIT(j)) { + if (ab->hw_params.ring_mask->rxdma2host[i] & BIT(j)) { irq_grp->irqs[num_irq++] = rxdma2host_destination_ring_mac1 - ath11k_hw_get_mac_from_pdev_id(hw, j); } - if (ath11k_host2rxdma_ring_mask[i] & BIT(j)) { + if (ab->hw_params.ring_mask->host2rxdma[i] & BIT(j)) { irq_grp->irqs[num_irq++] = host2rxdma_host_buf_ring_mac1 - ath11k_hw_get_mac_from_pdev_id(hw, j); } - if (rx_mon_status_ring_mask[i] & BIT(j)) { + if (ab->hw_params.ring_mask->rx_mon_status[i] & BIT(j)) { irq_grp->irqs[num_irq++] = ppdu_end_interrupts_mac1 - ath11k_hw_get_mac_from_pdev_id(hw, j); diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 093faf20f324..5638f0731634 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -29,6 +29,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .max_radios = 3, .bdf_addr = 0x4B0C0000, .hw_ops = &ipq8074_ops, + .ring_mask = &ath11k_hw_ring_mask_ipq8074, }, { .name = "qca6390 hw2.0", @@ -41,6 +42,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .max_radios = 3, .bdf_addr = 0x4B0C0000, .hw_ops = &qca6390_ops, + .ring_mask = &ath11k_hw_ring_mask_ipq8074, }, }; diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index c48d53ec4fa7..ca97ccf250a4 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -102,18 +102,8 @@ enum ath11k_firmware_mode { }; #define ATH11K_IRQ_NUM_MAX 52 -#define ATH11K_EXT_IRQ_GRP_NUM_MAX 11 #define ATH11K_EXT_IRQ_NUM_MAX 16 -extern const u8 ath11k_reo_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX]; -extern const u8 ath11k_tx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX]; -extern const u8 ath11k_rx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX]; -extern const u8 ath11k_rx_err_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX]; -extern const u8 ath11k_rx_wbm_rel_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX]; -extern const u8 ath11k_rxdma2host_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX]; -extern const u8 ath11k_host2rxdma_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX]; -extern const u8 rx_mon_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX]; - struct ath11k_ext_irq_grp { struct ath11k_base *ab; u32 irqs[ATH11K_EXT_IRQ_NUM_MAX]; diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index 1d64c3c51ac9..73fcb4f7f3c4 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -625,13 +625,13 @@ int ath11k_dp_service_srng(struct ath11k_base *ab, int i = 0; int tot_work_done = 0; - while (ath11k_tx_ring_mask[grp_id] >> i) { - if (ath11k_tx_ring_mask[grp_id] & BIT(i)) + while (ab->hw_params.ring_mask->tx[grp_id] >> i) { + if (ab->hw_params.ring_mask->tx[grp_id] & BIT(i)) ath11k_dp_tx_completion_handler(ab, i); i++; } - if (ath11k_rx_err_ring_mask[grp_id]) { + if (ab->hw_params.ring_mask->rx_err[grp_id]) { work_done = ath11k_dp_process_rx_err(ab, napi, budget); budget -= work_done; tot_work_done += work_done; @@ -639,7 +639,7 @@ int ath11k_dp_service_srng(struct ath11k_base *ab, goto done; } - if (ath11k_rx_wbm_rel_ring_mask[grp_id]) { + if (ab->hw_params.ring_mask->rx_wbm_rel[grp_id]) { work_done = ath11k_dp_rx_process_wbm_err(ab, napi, budget); @@ -650,8 +650,8 @@ int ath11k_dp_service_srng(struct ath11k_base *ab, goto done; } - if (ath11k_rx_ring_mask[grp_id]) { - i = fls(ath11k_rx_ring_mask[grp_id]) - 1; + if (ab->hw_params.ring_mask->rx[grp_id]) { + i = fls(ab->hw_params.ring_mask->rx[grp_id]) - 1; work_done = ath11k_dp_process_rx(ab, i, napi, budget); budget -= work_done; @@ -660,9 +660,9 @@ int ath11k_dp_service_srng(struct ath11k_base *ab, goto done; } - if (rx_mon_status_ring_mask[grp_id]) { + if (ab->hw_params.ring_mask->rx_mon_status[grp_id]) { for (i = 0; i < ab->num_radios; i++) { - if (rx_mon_status_ring_mask[grp_id] & BIT(i)) { + if (ab->hw_params.ring_mask->rx_mon_status[grp_id] & BIT(i)) { work_done = ath11k_dp_rx_process_mon_rings(ab, i, napi, @@ -675,11 +675,11 @@ int ath11k_dp_service_srng(struct ath11k_base *ab, } } - if (ath11k_reo_status_ring_mask[grp_id]) + if (ab->hw_params.ring_mask->reo_status[grp_id]) ath11k_dp_process_reo_status(ab); for (i = 0; i < ab->num_radios; i++) { - if (ath11k_rxdma2host_ring_mask[grp_id] & BIT(i)) { + if (ab->hw_params.ring_mask->rxdma2host[grp_id] & BIT(i)) { work_done = ath11k_dp_process_rxdma_err(ab, i, budget); budget -= work_done; tot_work_done += work_done; @@ -688,7 +688,7 @@ int ath11k_dp_service_srng(struct ath11k_base *ab, if (budget <= 0) goto done; - if (ath11k_host2rxdma_ring_mask[grp_id] & BIT(i)) { + if (ab->hw_params.ring_mask->host2rxdma[grp_id] & BIT(i)) { struct ath11k_pdev_dp *dp = &ab->pdevs[i].ar->dp; struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index 6feb0f699cfc..f7354476d673 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -36,3 +36,71 @@ const struct ath11k_hw_ops ipq6018_ops = { const struct ath11k_hw_ops qca6390_ops = { .get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id, }; + +#define ATH11K_TX_RING_MASK_0 0x1 +#define ATH11K_TX_RING_MASK_1 0x2 +#define ATH11K_TX_RING_MASK_2 0x4 + +#define ATH11K_RX_RING_MASK_0 0x1 +#define ATH11K_RX_RING_MASK_1 0x2 +#define ATH11K_RX_RING_MASK_2 0x4 +#define ATH11K_RX_RING_MASK_3 0x8 + +#define ATH11K_RX_ERR_RING_MASK_0 0x1 + +#define ATH11K_RX_WBM_REL_RING_MASK_0 0x1 + +#define ATH11K_REO_STATUS_RING_MASK_0 0x1 + +#define ATH11K_RXDMA2HOST_RING_MASK_0 0x1 +#define ATH11K_RXDMA2HOST_RING_MASK_1 0x2 +#define ATH11K_RXDMA2HOST_RING_MASK_2 0x4 + +#define ATH11K_HOST2RXDMA_RING_MASK_0 0x1 +#define ATH11K_HOST2RXDMA_RING_MASK_1 0x2 +#define ATH11K_HOST2RXDMA_RING_MASK_2 0x4 + +#define ATH11K_RX_MON_STATUS_RING_MASK_0 0x1 +#define ATH11K_RX_MON_STATUS_RING_MASK_1 0x2 +#define ATH11K_RX_MON_STATUS_RING_MASK_2 0x4 + +const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq8074 = { + .tx = { + ATH11K_TX_RING_MASK_0, + ATH11K_TX_RING_MASK_1, + ATH11K_TX_RING_MASK_2, + }, + .rx_mon_status = { + 0, 0, 0, 0, + ATH11K_RX_MON_STATUS_RING_MASK_0, + ATH11K_RX_MON_STATUS_RING_MASK_1, + ATH11K_RX_MON_STATUS_RING_MASK_2, + }, + .rx = { + 0, 0, 0, 0, 0, 0, 0, + ATH11K_RX_RING_MASK_0, + ATH11K_RX_RING_MASK_1, + ATH11K_RX_RING_MASK_2, + ATH11K_RX_RING_MASK_3, + }, + .rx_err = { + ATH11K_RX_ERR_RING_MASK_0, + }, + .rx_wbm_rel = { + ATH11K_RX_WBM_REL_RING_MASK_0, + }, + .reo_status = { + ATH11K_REO_STATUS_RING_MASK_0, + }, + .rxdma2host = { + ATH11K_RXDMA2HOST_RING_MASK_0, + ATH11K_RXDMA2HOST_RING_MASK_1, + ATH11K_RXDMA2HOST_RING_MASK_2, + }, + .host2rxdma = { + ATH11K_HOST2RXDMA_RING_MASK_0, + ATH11K_HOST2RXDMA_RING_MASK_1, + ATH11K_HOST2RXDMA_RING_MASK_2, + }, +}; + diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 1958830c01ec..a8cdf4d08be4 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -99,6 +99,19 @@ enum ath11k_bus { ATH11K_BUS_PCI, }; +#define ATH11K_EXT_IRQ_GRP_NUM_MAX 11 + +struct ath11k_hw_ring_mask { + u8 tx[ATH11K_EXT_IRQ_GRP_NUM_MAX]; + u8 rx_mon_status[ATH11K_EXT_IRQ_GRP_NUM_MAX]; + u8 rx[ATH11K_EXT_IRQ_GRP_NUM_MAX]; + u8 rx_err[ATH11K_EXT_IRQ_GRP_NUM_MAX]; + u8 rx_wbm_rel[ATH11K_EXT_IRQ_GRP_NUM_MAX]; + u8 reo_status[ATH11K_EXT_IRQ_GRP_NUM_MAX]; + u8 rxdma2host[ATH11K_EXT_IRQ_GRP_NUM_MAX]; + u8 host2rxdma[ATH11K_EXT_IRQ_GRP_NUM_MAX]; +}; + struct ath11k_hw_ops { u8 (*get_hw_mac_from_pdev_id)(int pdev_id); }; @@ -116,12 +129,16 @@ struct ath11k_hw_params { } fw; const struct ath11k_hw_ops *hw_ops; + + const struct ath11k_hw_ring_mask *ring_mask; }; extern const struct ath11k_hw_ops ipq8074_ops; extern const struct ath11k_hw_ops ipq6018_ops; extern const struct ath11k_hw_ops qca6390_ops; +extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq8074; + static inline int ath11k_hw_get_mac_from_pdev_id(struct ath11k_hw_params *hw, int pdev_idx) -- cgit v1.2.3 From 6e0355afaeb23ccf0aaee37bda2883003fd4cd31 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 13 Aug 2020 12:04:20 +0300 Subject: ath11k: add simple PCI client driver for QCA6390 chipset QCA6390 is a PCI based 11ax chipset, split AHB into own kernel module ath11k_ahb.ko and add ath11k_pci.ko for PCI devices. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597309466-19688-5-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/Kconfig | 12 +++++ drivers/net/wireless/ath/ath11k/Makefile | 7 ++- drivers/net/wireless/ath/ath11k/ahb.c | 2 +- drivers/net/wireless/ath/ath11k/ce.c | 2 + drivers/net/wireless/ath/ath11k/core.c | 7 +++ drivers/net/wireless/ath/ath11k/debug.c | 5 ++ drivers/net/wireless/ath/ath11k/dp.c | 1 + drivers/net/wireless/ath/ath11k/hal.c | 1 + drivers/net/wireless/ath/ath11k/hif.h | 4 ++ drivers/net/wireless/ath/ath11k/pci.c | 88 ++++++++++++++++++++++++++++++++ 10 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 drivers/net/wireless/ath/ath11k/pci.c diff --git a/drivers/net/wireless/ath/ath11k/Kconfig b/drivers/net/wireless/ath/ath11k/Kconfig index 0fd44d83e0e9..2a792ddd6fea 100644 --- a/drivers/net/wireless/ath/ath11k/Kconfig +++ b/drivers/net/wireless/ath/ath11k/Kconfig @@ -12,6 +12,18 @@ config ATH11K If you choose to build a module, it'll be called ath11k. +config ATH11K_AHB + tristate "Atheros ath11k AHB support" + depends on ATH11K + help + This module adds support for AHB bus + +config ATH11K_PCI + tristate "Atheros ath11k PCI support" + depends on ATH11K && PCI + help + This module adds support for PCIE bus + config ATH11K_DEBUG bool "QCA ath11k debugging" depends on ATH11K diff --git a/drivers/net/wireless/ath/ath11k/Makefile b/drivers/net/wireless/ath/ath11k/Makefile index ee13a3becbcf..4d1807f52d92 100644 --- a/drivers/net/wireless/ath/ath11k/Makefile +++ b/drivers/net/wireless/ath/ath11k/Makefile @@ -4,7 +4,6 @@ ath11k-y += core.o \ hal.o \ hal_tx.o \ hal_rx.o \ - ahb.o \ wmi.o \ mac.o \ reg.o \ @@ -25,5 +24,11 @@ ath11k-$(CONFIG_ATH11K_TRACING) += trace.o ath11k-$(CONFIG_THERMAL) += thermal.o ath11k-$(CONFIG_ATH11K_SPECTRAL) += spectral.o +obj-$(CONFIG_ATH11K_AHB) += ath11k_ahb.o +ath11k_ahb-y += ahb.o + +obj-$(CONFIG_ATH11K_PCI) += ath11k_pci.o +ath11k_pci-y += pci.o + # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index e3228a4f485f..042019de0a81 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -952,5 +952,5 @@ static void ath11k_ahb_exit(void) } module_exit(ath11k_ahb_exit); -MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax wireless chip"); +MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN AHB devices"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index cdd40c8fc867..7ae1bef0ab30 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c @@ -752,6 +752,7 @@ void ath11k_ce_free_pipes(struct ath11k_base *ab) } } } +EXPORT_SYMBOL(ath11k_ce_free_pipes); int ath11k_ce_alloc_pipes(struct ath11k_base *ab) { @@ -806,3 +807,4 @@ int ath11k_ce_get_attr_flags(int ce_id) return host_ce_config_wlan[ce_id].flags; } +EXPORT_SYMBOL(ath11k_ce_get_attr_flags); diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 5638f0731634..2dfbe4276514 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -14,6 +14,7 @@ #include "hif.h" unsigned int ath11k_debug_mask; +EXPORT_SYMBOL(ath11k_debug_mask); module_param_named(debug_mask, ath11k_debug_mask, uint, 0644); MODULE_PARM_DESC(debug_mask, "Debugging mask"); @@ -788,11 +789,13 @@ void ath11k_core_deinit(struct ath11k_base *ab) ath11k_mac_destroy(ab); ath11k_core_soc_destroy(ab); } +EXPORT_SYMBOL(ath11k_core_deinit); void ath11k_core_free(struct ath11k_base *ab) { kfree(ab); } +EXPORT_SYMBOL(ath11k_core_free); struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size, enum ath11k_bus bus) @@ -825,3 +828,7 @@ err_sc_free: kfree(ab); return NULL; } +EXPORT_SYMBOL(ath11k_core_alloc); + +MODULE_DESCRIPTION("Core module for Qualcomm Atheros 802.11ax wireless LAN cards."); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/ath/ath11k/debug.c b/drivers/net/wireless/ath/ath11k/debug.c index 62a1aa0565a9..60b961e59189 100644 --- a/drivers/net/wireless/ath/ath11k/debug.c +++ b/drivers/net/wireless/ath/ath11k/debug.c @@ -62,6 +62,7 @@ void ath11k_info(struct ath11k_base *ab, const char *fmt, ...) /* TODO: Trace the log */ va_end(args); } +EXPORT_SYMBOL(ath11k_info); void ath11k_err(struct ath11k_base *ab, const char *fmt, ...) { @@ -76,6 +77,7 @@ void ath11k_err(struct ath11k_base *ab, const char *fmt, ...) /* TODO: Trace the log */ va_end(args); } +EXPORT_SYMBOL(ath11k_err); void ath11k_warn(struct ath11k_base *ab, const char *fmt, ...) { @@ -90,6 +92,7 @@ void ath11k_warn(struct ath11k_base *ab, const char *fmt, ...) /* TODO: Trace the log */ va_end(args); } +EXPORT_SYMBOL(ath11k_warn); #ifdef CONFIG_ATH11K_DEBUG void __ath11k_dbg(struct ath11k_base *ab, enum ath11k_debug_mask mask, @@ -110,6 +113,7 @@ void __ath11k_dbg(struct ath11k_base *ab, enum ath11k_debug_mask mask, va_end(args); } +EXPORT_SYMBOL(__ath11k_dbg); void ath11k_dbg_dump(struct ath11k_base *ab, enum ath11k_debug_mask mask, @@ -138,6 +142,7 @@ void ath11k_dbg_dump(struct ath11k_base *ab, } } } +EXPORT_SYMBOL(ath11k_dbg_dump); #endif diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index 73fcb4f7f3c4..d6a2fd5e641c 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -7,6 +7,7 @@ #include "core.h" #include "dp_tx.h" #include "hal_tx.h" +#include "hif.h" #include "debug.h" #include "dp_rx.h" #include "peer.h" diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index d63785178afa..c7b26478d3e7 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -1133,6 +1133,7 @@ void ath11k_hal_srng_deinit(struct ath11k_base *ab) ath11k_hal_free_cont_rdp(ab); ath11k_hal_free_cont_wrp(ab); } +EXPORT_SYMBOL(ath11k_hal_srng_deinit); void ath11k_hal_dump_srng_stats(struct ath11k_base *ab) { diff --git a/drivers/net/wireless/ath/ath11k/hif.h b/drivers/net/wireless/ath/ath11k/hif.h index 165f7e51c238..48ee55cebc81 100644 --- a/drivers/net/wireless/ath/ath11k/hif.h +++ b/drivers/net/wireless/ath/ath11k/hif.h @@ -3,6 +3,9 @@ * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. */ +#ifndef _HIF_H_ +#define _HIF_H_ + #include "core.h" struct ath11k_hif_ops { @@ -63,3 +66,4 @@ static inline int ath11k_hif_map_service_to_pipe(struct ath11k_base *sc, u16 ser { return sc->hif.ops->map_service_to_pipe(sc, service_id, ul_pipe, dl_pipe); } +#endif /* _HIF_H_ */ diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c new file mode 100644 index 000000000000..a88536d2c64b --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + */ + +#include +#include + +#include "core.h" +#include "debug.h" + +#define QCA6390_DEVICE_ID 0x1101 + +static const struct pci_device_id ath11k_pci_id_table[] = { + { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) }, + {0} +}; + +MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); + +static int ath11k_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *pci_dev) +{ + struct ath11k_base *ab; + enum ath11k_hw_rev hw_rev; + + dev_warn(&pdev->dev, "WARNING: ath11k PCI support is experimental!\n"); + + switch (pci_dev->device) { + case QCA6390_DEVICE_ID: + hw_rev = ATH11K_HW_QCA6390_HW20; + break; + default: + dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", + pci_dev->device); + return -ENOTSUPP; + } + + ab = ath11k_core_alloc(&pdev->dev, 0, ATH11K_BUS_PCI); + if (!ab) { + dev_err(&pdev->dev, "failed to allocate ath11k base\n"); + return -ENOMEM; + } + + ab->dev = &pdev->dev; + ab->hw_rev = hw_rev; + pci_set_drvdata(pdev, ab); + + return 0; +} + +static void ath11k_pci_remove(struct pci_dev *pdev) +{ + struct ath11k_base *ab = pci_get_drvdata(pdev); + + set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); + ath11k_core_free(ab); +} + +static struct pci_driver ath11k_pci_driver = { + .name = "ath11k_pci", + .id_table = ath11k_pci_id_table, + .probe = ath11k_pci_probe, + .remove = ath11k_pci_remove, +}; + +static int ath11k_pci_init(void) +{ + int ret; + + ret = pci_register_driver(&ath11k_pci_driver); + if (ret) + pr_err("failed to register ath11k pci driver: %d\n", + ret); + + return ret; +} +module_init(ath11k_pci_init); + +static void ath11k_pci_exit(void) +{ + pci_unregister_driver(&ath11k_pci_driver); +} + +module_exit(ath11k_pci_exit); + +MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices"); +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From 5762613ededb20f1893abf6aeda2d4091dd4178b Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 13 Aug 2020 12:04:21 +0300 Subject: ath11k: pci: setup resources Add support for setting up pci region and dma mask. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597309466-19688-6-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/pci.c | 106 +++++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath11k/pci.h | 17 ++++++ 2 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/ath/ath11k/pci.h diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index a88536d2c64b..9b1baf53ac5a 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -6,9 +6,13 @@ #include #include +#include "pci.h" #include "core.h" #include "debug.h" +#define ATH11K_PCI_BAR_NUM 0 +#define ATH11K_PCI_DMA_MASK 32 + #define QCA6390_DEVICE_ID 0x1101 static const struct pci_device_id ath11k_pci_id_table[] = { @@ -18,11 +22,95 @@ static const struct pci_device_id ath11k_pci_id_table[] = { MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); +static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) +{ + struct ath11k_base *ab = ab_pci->ab; + u16 device_id; + int ret = 0; + + pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); + if (device_id != ab_pci->dev_id) { + ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n", + device_id, ab_pci->dev_id); + ret = -EIO; + goto out; + } + + ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM); + if (ret) { + ath11k_err(ab, "failed to assign pci resource: %d\n", ret); + goto out; + } + + ret = pci_enable_device(pdev); + if (ret) { + ath11k_err(ab, "failed to enable pci device: %d\n", ret); + goto out; + } + + ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci"); + if (ret) { + ath11k_err(ab, "failed to request pci region: %d\n", ret); + goto disable_device; + } + + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); + if (ret) { + ath11k_err(ab, "failed to set pci dma mask to %d: %d\n", + ATH11K_PCI_DMA_MASK, ret); + goto release_region; + } + + ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); + if (ret) { + ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n", + ATH11K_PCI_DMA_MASK, ret); + goto release_region; + } + + pci_set_master(pdev); + + ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); + ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0); + if (!ab->mem) { + ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM); + ret = -EIO; + goto clear_master; + } + + ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem); + return 0; + +clear_master: + pci_clear_master(pdev); +release_region: + pci_release_region(pdev, ATH11K_PCI_BAR_NUM); +disable_device: + pci_disable_device(pdev); +out: + return ret; +} + +static void ath11k_pci_free_region(struct ath11k_pci *ab_pci) +{ + struct ath11k_base *ab = ab_pci->ab; + struct pci_dev *pci_dev = ab_pci->pdev; + + pci_iounmap(pci_dev, ab->mem); + ab->mem = NULL; + pci_clear_master(pci_dev); + pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM); + if (pci_is_enabled(pci_dev)) + pci_disable_device(pci_dev); +} + static int ath11k_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_dev) { struct ath11k_base *ab; + struct ath11k_pci *ab_pci; enum ath11k_hw_rev hw_rev; + int ret; dev_warn(&pdev->dev, "WARNING: ath11k PCI support is experimental!\n"); @@ -36,7 +124,7 @@ static int ath11k_pci_probe(struct pci_dev *pdev, return -ENOTSUPP; } - ab = ath11k_core_alloc(&pdev->dev, 0, ATH11K_BUS_PCI); + ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI); if (!ab) { dev_err(&pdev->dev, "failed to allocate ath11k base\n"); return -ENOMEM; @@ -45,15 +133,31 @@ static int ath11k_pci_probe(struct pci_dev *pdev, ab->dev = &pdev->dev; ab->hw_rev = hw_rev; pci_set_drvdata(pdev, ab); + ab_pci = ath11k_pci_priv(ab); + ab_pci->dev_id = pci_dev->device; + ab_pci->ab = ab; + pci_set_drvdata(pdev, ab); + + ret = ath11k_pci_claim(ab_pci, pdev); + if (ret) { + ath11k_err(ab, "failed to claim device: %d\n", ret); + goto err_free_core; + } return 0; + +err_free_core: + ath11k_core_free(ab); + return ret; } static void ath11k_pci_remove(struct pci_dev *pdev) { struct ath11k_base *ab = pci_get_drvdata(pdev); + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); + ath11k_pci_free_region(ab_pci); ath11k_core_free(ab); } diff --git a/drivers/net/wireless/ath/ath11k/pci.h b/drivers/net/wireless/ath/ath11k/pci.h new file mode 100644 index 000000000000..dfd30ec09818 --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/pci.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + */ + +#include "core.h" + +struct ath11k_pci { + struct pci_dev *pdev; + struct ath11k_base *ab; + u16 dev_id; +}; + +static inline struct ath11k_pci *ath11k_pci_priv(struct ath11k_base *ab) +{ + return (struct ath11k_pci *)ab->drv_priv; +} -- cgit v1.2.3 From 5697a564d369412ca988696f43dacad59b5f7efb Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 13 Aug 2020 12:04:22 +0300 Subject: ath11k: pci: add MSI config initialisation QCA6390 uses PCI MSI for CE/MHI/DP interrupt. Add MSI vector mapping and MSI enable/disable operations. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597309466-19688-7-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/debug.h | 1 + drivers/net/wireless/ath/ath11k/pci.c | 69 +++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/pci.h | 13 +++++++ 3 files changed, 83 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/debug.h b/drivers/net/wireless/ath/ath11k/debug.h index c30085406bfb..1cfe54859388 100644 --- a/drivers/net/wireless/ath/ath11k/debug.h +++ b/drivers/net/wireless/ath/ath11k/debug.h @@ -25,6 +25,7 @@ enum ath11k_debug_mask { ATH11K_DBG_REG = 0x00000200, ATH11K_DBG_TESTMODE = 0x00000400, ATH11k_DBG_HAL = 0x00000800, + ATH11K_DBG_PCI = 0x00001000, ATH11K_DBG_ANY = 0xffffffff, }; diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 9b1baf53ac5a..5ebbdbde81ef 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -4,6 +4,7 @@ */ #include +#include #include #include "pci.h" @@ -22,6 +23,62 @@ static const struct pci_device_id ath11k_pci_id_table[] = { MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); +static const struct ath11k_msi_config msi_config = { + .total_vectors = 32, + .total_users = 4, + .users = (struct ath11k_msi_user[]) { + { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, + { .name = "CE", .num_vectors = 10, .base_vector = 3 }, + { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, + { .name = "DP", .num_vectors = 18, .base_vector = 14 }, + }, +}; + +static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci) +{ + struct ath11k_base *ab = ab_pci->ab; + struct msi_desc *msi_desc; + int num_vectors; + int ret; + + num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, + msi_config.total_vectors, + msi_config.total_vectors, + PCI_IRQ_MSI); + if (num_vectors != msi_config.total_vectors) { + ath11k_err(ab, "failed to get %d MSI vectors, only %d available", + msi_config.total_vectors, num_vectors); + + if (num_vectors >= 0) + return -EINVAL; + else + return num_vectors; + } + + msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); + if (!msi_desc) { + ath11k_err(ab, "msi_desc is NULL!\n"); + ret = -EINVAL; + goto free_msi_vector; + } + + ab_pci->msi_ep_base_data = msi_desc->msg.data; + + ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data); + + return 0; + +free_msi_vector: + pci_free_irq_vectors(ab_pci->pdev); + + return ret; +} + +static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci) +{ + pci_free_irq_vectors(ab_pci->pdev); +} + static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) { struct ath11k_base *ab = ab_pci->ab; @@ -136,6 +193,7 @@ static int ath11k_pci_probe(struct pci_dev *pdev, ab_pci = ath11k_pci_priv(ab); ab_pci->dev_id = pci_dev->device; ab_pci->ab = ab; + ab_pci->pdev = pdev; pci_set_drvdata(pdev, ab); ret = ath11k_pci_claim(ab_pci, pdev); @@ -144,10 +202,20 @@ static int ath11k_pci_probe(struct pci_dev *pdev, goto err_free_core; } + ret = ath11k_pci_enable_msi(ab_pci); + if (ret) { + ath11k_err(ab, "failed to enable msi: %d\n", ret); + goto err_pci_free_region; + } + return 0; +err_pci_free_region: + ath11k_pci_free_region(ab_pci); + err_free_core: ath11k_core_free(ab); + return ret; } @@ -157,6 +225,7 @@ static void ath11k_pci_remove(struct pci_dev *pdev) struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); + ath11k_pci_disable_msi(ab_pci); ath11k_pci_free_region(ab_pci); ath11k_core_free(ab); } diff --git a/drivers/net/wireless/ath/ath11k/pci.h b/drivers/net/wireless/ath/ath11k/pci.h index dfd30ec09818..db75eae26f71 100644 --- a/drivers/net/wireless/ath/ath11k/pci.h +++ b/drivers/net/wireless/ath/ath11k/pci.h @@ -5,10 +5,23 @@ #include "core.h" +struct ath11k_msi_user { + char *name; + int num_vectors; + u32 base_vector; +}; + +struct ath11k_msi_config { + int total_vectors; + int total_users; + struct ath11k_msi_user *users; +}; + struct ath11k_pci { struct pci_dev *pdev; struct ath11k_base *ab; u16 dev_id; + u32 msi_ep_base_data; }; static inline struct ath11k_pci *ath11k_pci_priv(struct ath11k_base *ab) -- cgit v1.2.3 From b8246f88468440ac596238ff402bcb636053d657 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 13 Aug 2020 12:04:23 +0300 Subject: ath11k: implement ath11k_core_pre_init() This is needed to initialise hw_params before MHI registration starts. MHI needs location of firmware directory and that's delivered via hw_params. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597309466-19688-8-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/ahb.c | 4 ++++ drivers/net/wireless/ath/ath11k/core.c | 20 ++++++++++++++------ drivers/net/wireless/ath/ath11k/core.h | 1 + drivers/net/wireless/ath/ath11k/pci.c | 7 +++++++ 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 042019de0a81..f4c346bcc676 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -868,6 +868,10 @@ static int ath11k_ahb_probe(struct platform_device *pdev) ab->mem_len = resource_size(mem_res); platform_set_drvdata(pdev, ab); + ret = ath11k_core_pre_init(ab); + if (ret) + goto err_core_free; + ret = ath11k_hal_srng_init(ab); if (ret) goto err_core_free; diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 2dfbe4276514..5c84995baaf9 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -742,6 +742,20 @@ static int ath11k_init_hw_params(struct ath11k_base *ab) return 0; } +int ath11k_core_pre_init(struct ath11k_base *ab) +{ + int ret; + + ret = ath11k_init_hw_params(ab); + if (ret) { + ath11k_err(ab, "failed to get hw params: %d\n", ret); + return ret; + } + + return 0; +} +EXPORT_SYMBOL(ath11k_core_pre_init); + int ath11k_core_init(struct ath11k_base *ab) { struct device *dev = ab->dev; @@ -761,12 +775,6 @@ int ath11k_core_init(struct ath11k_base *ab) } ab->tgt_rproc = prproc; - ret = ath11k_init_hw_params(ab); - if (ret) { - ath11k_err(ab, "failed to get hw params %d\n", ret); - return ret; - } - ret = ath11k_core_soc_create(ab); if (ret) { ath11k_err(ab, "failed to create soc core: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index ca97ccf250a4..a0a7c7b003c1 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -841,6 +841,7 @@ struct ath11k_peer *ath11k_peer_find_by_addr(struct ath11k_base *ab, const u8 *addr); struct ath11k_peer *ath11k_peer_find_by_id(struct ath11k_base *ab, int peer_id); int ath11k_core_qmi_firmware_ready(struct ath11k_base *ab); +int ath11k_core_pre_init(struct ath11k_base *ab); int ath11k_core_init(struct ath11k_base *ath11k); void ath11k_core_deinit(struct ath11k_base *ath11k); struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size, diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 5ebbdbde81ef..ff401d2871f3 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -208,8 +208,15 @@ static int ath11k_pci_probe(struct pci_dev *pdev, goto err_pci_free_region; } + ret = ath11k_core_pre_init(ab); + if (ret) + goto err_pci_disable_msi; + return 0; +err_pci_disable_msi: + ath11k_pci_disable_msi(ab_pci); + err_pci_free_region: ath11k_pci_free_region(ab_pci); -- cgit v1.2.3 From 1399fb87ea3e96d26398a16cb95dc395a68c51bc Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 13 Aug 2020 12:04:24 +0300 Subject: ath11k: register MHI controller device for QCA6390 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modem Host Interface (MHI) is a communication protocol to communicate with external Qualcomm modems and Wi-Fi chipsets over high speed peripheral buses. Even though MHI doesn’t dictate underlying physical layer, protocol and MHI stack is structured for PCI based devices. Register directly with MHI subsystem as a MHI device driver for firmware download to QCA6390. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597309466-19688-9-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/Kconfig | 3 + drivers/net/wireless/ath/ath11k/Makefile | 2 +- drivers/net/wireless/ath/ath11k/hw.h | 1 + drivers/net/wireless/ath/ath11k/mhi.c | 423 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/mhi.h | 28 ++ drivers/net/wireless/ath/ath11k/pci.c | 77 ++++++ drivers/net/wireless/ath/ath11k/pci.h | 14 + 7 files changed, 547 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/ath/ath11k/mhi.c create mode 100644 drivers/net/wireless/ath/ath11k/mhi.h diff --git a/drivers/net/wireless/ath/ath11k/Kconfig b/drivers/net/wireless/ath/ath11k/Kconfig index 2a792ddd6fea..7e5094e0e7bb 100644 --- a/drivers/net/wireless/ath/ath11k/Kconfig +++ b/drivers/net/wireless/ath/ath11k/Kconfig @@ -21,6 +21,9 @@ config ATH11K_AHB config ATH11K_PCI tristate "Atheros ath11k PCI support" depends on ATH11K && PCI + select MHI_BUS + select QRTR + select QRTR_MHI help This module adds support for PCIE bus diff --git a/drivers/net/wireless/ath/ath11k/Makefile b/drivers/net/wireless/ath/ath11k/Makefile index 4d1807f52d92..bc4911f0339d 100644 --- a/drivers/net/wireless/ath/ath11k/Makefile +++ b/drivers/net/wireless/ath/ath11k/Makefile @@ -28,7 +28,7 @@ obj-$(CONFIG_ATH11K_AHB) += ath11k_ahb.o ath11k_ahb-y += ahb.o obj-$(CONFIG_ATH11K_PCI) += ath11k_pci.o -ath11k_pci-y += pci.o +ath11k_pci-y += mhi.o pci.o # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index a8cdf4d08be4..c02fd02839d4 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -72,6 +72,7 @@ #define ATH11K_BOARD_API2_FILE "board-2.bin" #define ATH11K_DEFAULT_BOARD_FILE "board.bin" #define ATH11K_DEFAULT_CAL_FILE "caldata.bin" +#define ATH11K_AMSS_FILE "amss.bin" enum ath11k_hw_rate_cck { ATH11K_HW_RATE_CCK_LP_11M = 0, diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c new file mode 100644 index 000000000000..62d39ef6741f --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -0,0 +1,423 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* Copyright (c) 2020 The Linux Foundation. All rights reserved. */ + +#include +#include + +#include "core.h" +#include "debug.h" +#include "mhi.h" + +#define MHI_TIMEOUT_DEFAULT_MS 90000 + +static struct mhi_channel_config ath11k_mhi_channels[] = { + { + .num = 0, + .name = "LOOPBACK", + .num_elements = 32, + .event_ring = 0, + .dir = DMA_TO_DEVICE, + .ee_mask = 0x4, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .auto_start = false, + }, + { + .num = 1, + .name = "LOOPBACK", + .num_elements = 32, + .event_ring = 0, + .dir = DMA_FROM_DEVICE, + .ee_mask = 0x4, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .auto_start = false, + }, + { + .num = 20, + .name = "IPCR", + .num_elements = 64, + .event_ring = 1, + .dir = DMA_TO_DEVICE, + .ee_mask = 0x4, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .auto_start = true, + }, + { + .num = 21, + .name = "IPCR", + .num_elements = 64, + .event_ring = 1, + .dir = DMA_FROM_DEVICE, + .ee_mask = 0x4, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = true, + .auto_start = true, + }, +}; + +static struct mhi_event_config ath11k_mhi_events[] = { + { + .num_elements = 32, + .irq_moderation_ms = 0, + .irq = 1, + .mode = MHI_DB_BRST_DISABLE, + .data_type = MHI_ER_CTRL, + .hardware_event = false, + .client_managed = false, + .offload_channel = false, + }, + { + .num_elements = 256, + .irq_moderation_ms = 1, + .irq = 2, + .mode = MHI_DB_BRST_DISABLE, + .priority = 1, + .hardware_event = false, + .client_managed = false, + .offload_channel = false, + }, +}; + +static struct mhi_controller_config ath11k_mhi_config = { + .max_channels = 128, + .timeout_ms = 2000, + .use_bounce_buf = false, + .buf_len = 0, + .num_channels = ARRAY_SIZE(ath11k_mhi_channels), + .ch_cfg = ath11k_mhi_channels, + .num_events = ARRAY_SIZE(ath11k_mhi_events), + .event_cfg = ath11k_mhi_events, +}; + +static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci) +{ + struct ath11k_base *ab = ab_pci->ab; + u32 user_base_data, base_vector; + int ret, num_vectors, i; + int *irq; + + ret = ath11k_pci_get_user_msi_assignment(ab_pci, + "MHI", &num_vectors, + &user_base_data, &base_vector); + if (ret) + return ret; + + ath11k_dbg(ab, ATH11K_DBG_PCI, "Number of assigned MSI for MHI is %d, base vector is %d\n", + num_vectors, base_vector); + + irq = kcalloc(num_vectors, sizeof(int), GFP_KERNEL); + if (!irq) + return -ENOMEM; + + for (i = 0; i < num_vectors; i++) + irq[i] = ath11k_pci_get_msi_irq(ab->dev, + base_vector + i); + + ab_pci->mhi_ctrl->irq = irq; + ab_pci->mhi_ctrl->nr_irqs = num_vectors; + + return 0; +} + +static int ath11k_mhi_op_runtime_get(struct mhi_controller *mhi_cntrl) +{ + return 0; +} + +static void ath11k_mhi_op_runtime_put(struct mhi_controller *mhi_cntrl) +{ +} + +static void ath11k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl, + enum mhi_callback cb) +{ +} + +static int ath11k_mhi_op_read_reg(struct mhi_controller *mhi_cntrl, + void __iomem *addr, + u32 *out) +{ + *out = readl(addr); + + return 0; +} + +static void ath11k_mhi_op_write_reg(struct mhi_controller *mhi_cntrl, + void __iomem *addr, + u32 val) +{ + writel(val, addr); +} + +int ath11k_mhi_register(struct ath11k_pci *ab_pci) +{ + struct ath11k_base *ab = ab_pci->ab; + struct mhi_controller *mhi_ctrl; + int ret; + + mhi_ctrl = kzalloc(sizeof(*mhi_ctrl), GFP_KERNEL); + if (!mhi_ctrl) + return PTR_ERR(mhi_ctrl); + + ath11k_core_create_firmware_path(ab, ATH11K_AMSS_FILE, + ab_pci->amss_path, + sizeof(ab_pci->amss_path)); + + ab_pci->mhi_ctrl = mhi_ctrl; + mhi_ctrl->cntrl_dev = ab->dev; + mhi_ctrl->fw_image = ab_pci->amss_path; + mhi_ctrl->regs = ab->mem; + + ret = ath11k_mhi_get_msi(ab_pci); + if (ret) { + ath11k_err(ab, "failed to get msi for mhi\n"); + kfree(mhi_ctrl); + return ret; + } + + mhi_ctrl->iova_start = 0; + mhi_ctrl->iova_stop = 0xffffffff; + mhi_ctrl->sbl_size = SZ_512K; + mhi_ctrl->seg_len = SZ_512K; + mhi_ctrl->fbc_download = true; + mhi_ctrl->runtime_get = ath11k_mhi_op_runtime_get; + mhi_ctrl->runtime_put = ath11k_mhi_op_runtime_put; + mhi_ctrl->status_cb = ath11k_mhi_op_status_cb; + mhi_ctrl->read_reg = ath11k_mhi_op_read_reg; + mhi_ctrl->write_reg = ath11k_mhi_op_write_reg; + + ret = mhi_register_controller(mhi_ctrl, &ath11k_mhi_config); + if (ret) { + ath11k_err(ab, "failed to register to mhi bus, err = %d\n", ret); + kfree(mhi_ctrl); + return ret; + } + + return 0; +} + +void ath11k_mhi_unregister(struct ath11k_pci *ab_pci) +{ + struct mhi_controller *mhi_ctrl = ab_pci->mhi_ctrl; + + mhi_unregister_controller(mhi_ctrl); + kfree(mhi_ctrl->irq); +} + +static char *ath11k_mhi_state_to_str(enum ath11k_mhi_state mhi_state) +{ + switch (mhi_state) { + case ATH11K_MHI_INIT: + return "INIT"; + case ATH11K_MHI_DEINIT: + return "DEINIT"; + case ATH11K_MHI_POWER_ON: + return "POWER_ON"; + case ATH11K_MHI_POWER_OFF: + return "POWER_OFF"; + case ATH11K_MHI_FORCE_POWER_OFF: + return "FORCE_POWER_OFF"; + case ATH11K_MHI_SUSPEND: + return "SUSPEND"; + case ATH11K_MHI_RESUME: + return "RESUME"; + case ATH11K_MHI_TRIGGER_RDDM: + return "TRIGGER_RDDM"; + case ATH11K_MHI_RDDM_DONE: + return "RDDM_DONE"; + default: + return "UNKNOWN"; + } +}; + +static void ath11k_mhi_set_state_bit(struct ath11k_pci *ab_pci, + enum ath11k_mhi_state mhi_state) +{ + struct ath11k_base *ab = ab_pci->ab; + + switch (mhi_state) { + case ATH11K_MHI_INIT: + set_bit(ATH11K_MHI_INIT, &ab_pci->mhi_state); + break; + case ATH11K_MHI_DEINIT: + clear_bit(ATH11K_MHI_INIT, &ab_pci->mhi_state); + break; + case ATH11K_MHI_POWER_ON: + set_bit(ATH11K_MHI_POWER_ON, &ab_pci->mhi_state); + break; + case ATH11K_MHI_POWER_OFF: + case ATH11K_MHI_FORCE_POWER_OFF: + clear_bit(ATH11K_MHI_POWER_ON, &ab_pci->mhi_state); + clear_bit(ATH11K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state); + clear_bit(ATH11K_MHI_RDDM_DONE, &ab_pci->mhi_state); + break; + case ATH11K_MHI_SUSPEND: + set_bit(ATH11K_MHI_SUSPEND, &ab_pci->mhi_state); + break; + case ATH11K_MHI_RESUME: + clear_bit(ATH11K_MHI_SUSPEND, &ab_pci->mhi_state); + break; + case ATH11K_MHI_TRIGGER_RDDM: + set_bit(ATH11K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state); + break; + case ATH11K_MHI_RDDM_DONE: + set_bit(ATH11K_MHI_RDDM_DONE, &ab_pci->mhi_state); + break; + default: + ath11k_err(ab, "unhandled mhi state (%d)\n", mhi_state); + } +} + +static int ath11k_mhi_check_state_bit(struct ath11k_pci *ab_pci, + enum ath11k_mhi_state mhi_state) +{ + struct ath11k_base *ab = ab_pci->ab; + + switch (mhi_state) { + case ATH11K_MHI_INIT: + if (!test_bit(ATH11K_MHI_INIT, &ab_pci->mhi_state)) + return 0; + break; + case ATH11K_MHI_DEINIT: + case ATH11K_MHI_POWER_ON: + if (test_bit(ATH11K_MHI_INIT, &ab_pci->mhi_state) && + !test_bit(ATH11K_MHI_POWER_ON, &ab_pci->mhi_state)) + return 0; + break; + case ATH11K_MHI_FORCE_POWER_OFF: + if (test_bit(ATH11K_MHI_POWER_ON, &ab_pci->mhi_state)) + return 0; + break; + case ATH11K_MHI_POWER_OFF: + case ATH11K_MHI_SUSPEND: + if (test_bit(ATH11K_MHI_POWER_ON, &ab_pci->mhi_state) && + !test_bit(ATH11K_MHI_SUSPEND, &ab_pci->mhi_state)) + return 0; + break; + case ATH11K_MHI_RESUME: + if (test_bit(ATH11K_MHI_SUSPEND, &ab_pci->mhi_state)) + return 0; + break; + case ATH11K_MHI_TRIGGER_RDDM: + if (test_bit(ATH11K_MHI_POWER_ON, &ab_pci->mhi_state) && + !test_bit(ATH11K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state)) + return 0; + break; + case ATH11K_MHI_RDDM_DONE: + return 0; + default: + ath11k_err(ab, "unhandled mhi state: %s(%d)\n", + ath11k_mhi_state_to_str(mhi_state), mhi_state); + } + + ath11k_err(ab, "failed to set mhi state %s(%d) in current mhi state (0x%lx)\n", + ath11k_mhi_state_to_str(mhi_state), mhi_state, + ab_pci->mhi_state); + + return -EINVAL; +} + +static int ath11k_mhi_set_state(struct ath11k_pci *ab_pci, + enum ath11k_mhi_state mhi_state) +{ + struct ath11k_base *ab = ab_pci->ab; + int ret; + + ret = ath11k_mhi_check_state_bit(ab_pci, mhi_state); + if (ret) + goto out; + + ath11k_dbg(ab, ATH11K_DBG_PCI, "setting mhi state: %s(%d)\n", + ath11k_mhi_state_to_str(mhi_state), mhi_state); + + switch (mhi_state) { + case ATH11K_MHI_INIT: + ret = mhi_prepare_for_power_up(ab_pci->mhi_ctrl); + break; + case ATH11K_MHI_DEINIT: + mhi_unprepare_after_power_down(ab_pci->mhi_ctrl); + ret = 0; + break; + case ATH11K_MHI_POWER_ON: + ret = mhi_async_power_up(ab_pci->mhi_ctrl); + break; + case ATH11K_MHI_POWER_OFF: + mhi_power_down(ab_pci->mhi_ctrl, true); + ret = 0; + break; + case ATH11K_MHI_FORCE_POWER_OFF: + mhi_power_down(ab_pci->mhi_ctrl, false); + ret = 0; + break; + case ATH11K_MHI_SUSPEND: + break; + case ATH11K_MHI_RESUME: + break; + case ATH11K_MHI_TRIGGER_RDDM: + ret = mhi_force_rddm_mode(ab_pci->mhi_ctrl); + break; + case ATH11K_MHI_RDDM_DONE: + break; + default: + ath11k_err(ab, "unhandled MHI state (%d)\n", mhi_state); + ret = -EINVAL; + } + + if (ret) + goto out; + + ath11k_mhi_set_state_bit(ab_pci, mhi_state); + + return 0; + +out: + ath11k_err(ab, "failed to set mhi state: %s(%d)\n", + ath11k_mhi_state_to_str(mhi_state), mhi_state); + return ret; +} + +int ath11k_mhi_start(struct ath11k_pci *ab_pci) +{ + int ret; + + ab_pci->mhi_ctrl->timeout_ms = MHI_TIMEOUT_DEFAULT_MS; + + ret = ath11k_mhi_set_state(ab_pci, ATH11K_MHI_INIT); + if (ret) + goto out; + + ret = ath11k_mhi_set_state(ab_pci, ATH11K_MHI_POWER_ON); + if (ret) + goto out; + + return 0; + +out: + return ret; +} + +void ath11k_mhi_stop(struct ath11k_pci *ab_pci) +{ + ath11k_mhi_set_state(ab_pci, ATH11K_MHI_RESUME); + ath11k_mhi_set_state(ab_pci, ATH11K_MHI_POWER_OFF); + ath11k_mhi_set_state(ab_pci, ATH11K_MHI_DEINIT); +} + diff --git a/drivers/net/wireless/ath/ath11k/mhi.h b/drivers/net/wireless/ath/ath11k/mhi.h new file mode 100644 index 000000000000..3c91881b4fbd --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/mhi.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + */ +#ifndef _ATH11K_MHI_H +#define _ATH11K_MHI_H + +#include "pci.h" + +enum ath11k_mhi_state { + ATH11K_MHI_INIT, + ATH11K_MHI_DEINIT, + ATH11K_MHI_POWER_ON, + ATH11K_MHI_POWER_OFF, + ATH11K_MHI_FORCE_POWER_OFF, + ATH11K_MHI_SUSPEND, + ATH11K_MHI_RESUME, + ATH11K_MHI_TRIGGER_RDDM, + ATH11K_MHI_RDDM, + ATH11K_MHI_RDDM_DONE, +}; + +int ath11k_mhi_start(struct ath11k_pci *ar_pci); +void ath11k_mhi_stop(struct ath11k_pci *ar_pci); +int ath11k_mhi_register(struct ath11k_pci *ar_pci); +void ath11k_mhi_unregister(struct ath11k_pci *ar_pci); + +#endif diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index ff401d2871f3..6f7789fa23d6 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -9,6 +9,8 @@ #include "pci.h" #include "core.h" +#include "hif.h" +#include "mhi.h" #include "debug.h" #define ATH11K_PCI_BAR_NUM 0 @@ -34,6 +36,40 @@ static const struct ath11k_msi_config msi_config = { }, }; +int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + + return pci_irq_vector(pci_dev, vector); +} + +int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name, + int *num_vectors, u32 *user_base_data, + u32 *base_vector) +{ + struct ath11k_base *ab = ab_pci->ab; + int idx; + + for (idx = 0; idx < msi_config.total_users; idx++) { + if (strcmp(user_name, msi_config.users[idx].name) == 0) { + *num_vectors = msi_config.users[idx].num_vectors; + *user_base_data = msi_config.users[idx].base_vector + + ab_pci->msi_ep_base_data; + *base_vector = msi_config.users[idx].base_vector; + + ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", + user_name, *num_vectors, *user_base_data, + *base_vector); + + return 0; + } + } + + ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name); + + return -EINVAL; +} + static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci) { struct ath11k_base *ab = ab_pci->ab; @@ -161,6 +197,32 @@ static void ath11k_pci_free_region(struct ath11k_pci *ab_pci) pci_disable_device(pci_dev); } +static int ath11k_pci_power_up(struct ath11k_base *ab) +{ + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + int ret; + + ret = ath11k_mhi_start(ab_pci); + if (ret) { + ath11k_err(ab, "failed to start mhi: %d\n", ret); + return ret; + } + + return 0; +} + +static void ath11k_pci_power_down(struct ath11k_base *ab) +{ + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + + ath11k_mhi_stop(ab_pci); +} + +static __maybe_unused const struct ath11k_hif_ops ath11k_pci_hif_ops = { + .power_down = ath11k_pci_power_down, + .power_up = ath11k_pci_power_up, +}; + static int ath11k_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_dev) { @@ -212,6 +274,12 @@ static int ath11k_pci_probe(struct pci_dev *pdev, if (ret) goto err_pci_disable_msi; + ret = ath11k_mhi_register(ab_pci); + if (ret) { + ath11k_err(ab, "failed to register mhi: %d\n", ret); + goto err_pci_disable_msi; + } + return 0; err_pci_disable_msi: @@ -232,16 +300,25 @@ static void ath11k_pci_remove(struct pci_dev *pdev) struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); + ath11k_mhi_unregister(ab_pci); ath11k_pci_disable_msi(ab_pci); ath11k_pci_free_region(ab_pci); ath11k_core_free(ab); } +static void ath11k_pci_shutdown(struct pci_dev *pdev) +{ + struct ath11k_base *ab = pci_get_drvdata(pdev); + + ath11k_pci_power_down(ab); +} + static struct pci_driver ath11k_pci_driver = { .name = "ath11k_pci", .id_table = ath11k_pci_id_table, .probe = ath11k_pci_probe, .remove = ath11k_pci_remove, + .shutdown = ath11k_pci_shutdown, }; static int ath11k_pci_init(void) diff --git a/drivers/net/wireless/ath/ath11k/pci.h b/drivers/net/wireless/ath/ath11k/pci.h index db75eae26f71..85e033069d7a 100644 --- a/drivers/net/wireless/ath/ath11k/pci.h +++ b/drivers/net/wireless/ath/ath11k/pci.h @@ -2,6 +2,10 @@ /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. */ +#ifndef _ATH11K_PCI_H +#define _ATH11K_PCI_H + +#include #include "core.h" @@ -21,10 +25,20 @@ struct ath11k_pci { struct pci_dev *pdev; struct ath11k_base *ab; u16 dev_id; + char amss_path[100]; u32 msi_ep_base_data; + struct mhi_controller *mhi_ctrl; + unsigned long mhi_state; }; static inline struct ath11k_pci *ath11k_pci_priv(struct ath11k_base *ab) { return (struct ath11k_pci *)ab->drv_priv; } + +int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ar_pci, char *user_name, + int *num_vectors, u32 *user_base_data, + u32 *base_vector); +int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector); + +#endif -- cgit v1.2.3 From 7f4beda2ba0393ecb04b4ae3017f819041236c43 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 13 Aug 2020 12:04:25 +0300 Subject: ath11k: pci: add HAL, CE and core initialisation Define CE pipe/qmi config and setup pci irq for the same. Call ath11k_core_init(). Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597309466-19688-10-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/ce.c | 2 + drivers/net/wireless/ath/ath11k/core.c | 1 + drivers/net/wireless/ath/ath11k/hal.c | 1 + drivers/net/wireless/ath/ath11k/pci.c | 390 ++++++++++++++++++++++++++++++++- 4 files changed, 393 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index 7ae1bef0ab30..2fff171b35f8 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c @@ -619,6 +619,7 @@ void ath11k_ce_cleanup_pipes(struct ath11k_base *ab) /* NOTE: Should we also clean up tx buffer in all pipes? */ } } +EXPORT_SYMBOL(ath11k_ce_cleanup_pipes); void ath11k_ce_rx_post_buf(struct ath11k_base *ab) { @@ -780,6 +781,7 @@ int ath11k_ce_alloc_pipes(struct ath11k_base *ab) return 0; } +EXPORT_SYMBOL(ath11k_ce_alloc_pipes); /* For Big Endian Host, Copy Engine byte_swap is enabled * When Copy Engine does byte_swap, need to byte swap again for the diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 5c84995baaf9..741093de3a83 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -783,6 +783,7 @@ int ath11k_core_init(struct ath11k_base *ab) return 0; } +EXPORT_SYMBOL(ath11k_core_init); void ath11k_core_deinit(struct ath11k_base *ab) { diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index c7b26478d3e7..fe4df2b4a2cc 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -1127,6 +1127,7 @@ err_free_cont_rdp: err_hal: return ret; } +EXPORT_SYMBOL(ath11k_hal_srng_init); void ath11k_hal_srng_deinit(struct ath11k_base *ab) { diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 6f7789fa23d6..d1068766972d 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -16,6 +16,8 @@ #define ATH11K_PCI_BAR_NUM 0 #define ATH11K_PCI_DMA_MASK 32 +#define ATH11K_PCI_IRQ_CE0_OFFSET 3 + #define QCA6390_DEVICE_ID 0x1101 static const struct pci_device_id ath11k_pci_id_table[] = { @@ -36,6 +38,241 @@ static const struct ath11k_msi_config msi_config = { }, }; +/* Target firmware's Copy Engine configuration. */ +static const struct ce_pipe_config target_ce_config_wlan[] = { + /* CE0: host->target HTC control and raw streams */ + { + .pipenum = __cpu_to_le32(0), + .pipedir = __cpu_to_le32(PIPEDIR_OUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE1: target->host HTT + HTC control */ + { + .pipenum = __cpu_to_le32(1), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE2: target->host WMI */ + { + .pipenum = __cpu_to_le32(2), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE3: host->target WMI */ + { + .pipenum = __cpu_to_le32(3), + .pipedir = __cpu_to_le32(PIPEDIR_OUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE4: host->target HTT */ + { + .pipenum = __cpu_to_le32(4), + .pipedir = __cpu_to_le32(PIPEDIR_OUT), + .nentries = __cpu_to_le32(256), + .nbytes_max = __cpu_to_le32(256), + .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), + .reserved = __cpu_to_le32(0), + }, + + /* CE5: target->host Pktlog */ + { + .pipenum = __cpu_to_le32(5), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE6: Reserved for target autonomous hif_memcpy */ + { + .pipenum = __cpu_to_le32(6), + .pipedir = __cpu_to_le32(PIPEDIR_INOUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(16384), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + + /* CE7 used only by Host */ + { + .pipenum = __cpu_to_le32(7), + .pipedir = __cpu_to_le32(PIPEDIR_INOUT_H2H), + .nentries = __cpu_to_le32(0), + .nbytes_max = __cpu_to_le32(0), + .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), + .reserved = __cpu_to_le32(0), + }, + + /* CE8 target->host used only by IPA */ + { + .pipenum = __cpu_to_le32(8), + .pipedir = __cpu_to_le32(PIPEDIR_INOUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(16384), + .flags = __cpu_to_le32(CE_ATTR_FLAGS), + .reserved = __cpu_to_le32(0), + }, + /* CE 9, 10, 11 are used by MHI driver */ +}; + +/* Map from service/endpoint to Copy Engine. + * This table is derived from the CE_PCI TABLE, above. + * It is passed to the Target at startup for use by firmware. + */ +static const struct service_to_pipe target_service_to_ce_map_wlan[] = { + { + __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VO), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VO), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BK), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BK), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BE), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BE), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VI), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VI), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + + { + __cpu_to_le32(ATH11K_HTC_SVC_ID_RSVD_CTRL), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(0), + }, + { + __cpu_to_le32(ATH11K_HTC_SVC_ID_RSVD_CTRL), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + + { + __cpu_to_le32(ATH11K_HTC_SVC_ID_HTT_DATA_MSG), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(4), + }, + { + __cpu_to_le32(ATH11K_HTC_SVC_ID_HTT_DATA_MSG), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(1), + }, + + /* (Additions here) */ + + { /* must be last */ + __cpu_to_le32(0), + __cpu_to_le32(0), + __cpu_to_le32(0), + }, +}; + +static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { + "bhi", + "mhi-er0", + "mhi-er1", + "ce0", + "ce1", + "ce2", + "ce3", + "ce4", + "ce5", + "ce6", + "ce7", + "ce8", + "ce9", + "ce10", + "ce11", + "host2wbm-desc-feed", + "host2reo-re-injection", + "host2reo-command", + "host2rxdma-monitor-ring3", + "host2rxdma-monitor-ring2", + "host2rxdma-monitor-ring1", + "reo2ost-exception", + "wbm2host-rx-release", + "reo2host-status", + "reo2host-destination-ring4", + "reo2host-destination-ring3", + "reo2host-destination-ring2", + "reo2host-destination-ring1", + "rxdma2host-monitor-destination-mac3", + "rxdma2host-monitor-destination-mac2", + "rxdma2host-monitor-destination-mac1", + "ppdu-end-interrupts-mac3", + "ppdu-end-interrupts-mac2", + "ppdu-end-interrupts-mac1", + "rxdma2host-monitor-status-ring-mac3", + "rxdma2host-monitor-status-ring-mac2", + "rxdma2host-monitor-status-ring-mac1", + "host2rxdma-host-buf-ring-mac3", + "host2rxdma-host-buf-ring-mac2", + "host2rxdma-host-buf-ring-mac1", + "rxdma2host-destination-ring-mac3", + "rxdma2host-destination-ring-mac2", + "rxdma2host-destination-ring-mac1", + "host2tcl-input-ring4", + "host2tcl-input-ring3", + "host2tcl-input-ring2", + "host2tcl-input-ring1", + "wbm2host-tx-completions-ring3", + "wbm2host-tx-completions-ring2", + "wbm2host-tx-completions-ring1", + "tcl2host-status-ring", +}; + int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) { struct pci_dev *pci_dev = to_pci_dev(dev); @@ -70,6 +307,106 @@ int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_nam return -EINVAL; } +static void ath11k_pci_free_irq(struct ath11k_base *ab) +{ + int i, irq_idx; + + for (i = 0; i < CE_COUNT; i++) { + if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) + continue; + irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; + free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); + } +} + +static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) +{ + u32 irq_idx; + + irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; + disable_irq_nosync(ab->irq_num[irq_idx]); +} + +static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) +{ + struct ath11k_ce_pipe *ce_pipe = arg; + + ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num); + + return IRQ_HANDLED; +} + +static int ath11k_pci_config_irq(struct ath11k_base *ab) +{ + struct ath11k_ce_pipe *ce_pipe; + u32 msi_data_start; + u32 msi_data_count; + u32 msi_irq_start; + unsigned int msi_data; + int irq, i, ret, irq_idx; + + ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), + "CE", &msi_data_count, + &msi_data_start, &msi_irq_start); + if (ret) + return ret; + + /* Configure CE irqs */ + for (i = 0; i < CE_COUNT; i++) { + msi_data = (i % msi_data_count) + msi_irq_start; + irq = ath11k_pci_get_msi_irq(ab->dev, msi_data); + ce_pipe = &ab->ce.ce_pipe[i]; + + if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) + continue; + + irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; + + ret = request_irq(irq, ath11k_pci_ce_interrupt_handler, + IRQF_SHARED, irq_name[irq_idx], + ce_pipe); + if (ret) { + ath11k_err(ab, "failed to request irq %d: %d\n", + irq_idx, ret); + return ret; + } + + ab->irq_num[irq_idx] = irq; + } + + return 0; +} + +static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) +{ + struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; + + cfg->tgt_ce = target_ce_config_wlan; + cfg->tgt_ce_len = ARRAY_SIZE(target_ce_config_wlan); + + cfg->svc_to_ce_map = target_service_to_ce_map_wlan; + cfg->svc_to_ce_map_len = ARRAY_SIZE(target_service_to_ce_map_wlan); +} + +static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) +{ + u32 irq_idx; + + irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; + enable_irq(ab->irq_num[irq_idx]); +} + +static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab) +{ + int i; + + for (i = 0; i < CE_COUNT; i++) { + if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) + continue; + ath11k_pci_ce_irq_enable(ab, i); + } +} + static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci) { struct ath11k_base *ab = ab_pci->ab; @@ -218,7 +555,21 @@ static void ath11k_pci_power_down(struct ath11k_base *ab) ath11k_mhi_stop(ab_pci); } -static __maybe_unused const struct ath11k_hif_ops ath11k_pci_hif_ops = { +static void ath11k_pci_stop(struct ath11k_base *ab) +{ + ath11k_ce_cleanup_pipes(ab); +} + +static int ath11k_pci_start(struct ath11k_base *ab) +{ + ath11k_pci_ce_irqs_enable(ab); + + return 0; +} + +static const struct ath11k_hif_ops ath11k_pci_hif_ops = { + .start = ath11k_pci_start, + .stop = ath11k_pci_stop, .power_down = ath11k_pci_power_down, .power_up = ath11k_pci_power_up, }; @@ -256,6 +607,7 @@ static int ath11k_pci_probe(struct pci_dev *pdev, ab_pci->dev_id = pci_dev->device; ab_pci->ab = ab; ab_pci->pdev = pdev; + ab->hif.ops = &ath11k_pci_hif_ops; pci_set_drvdata(pdev, ab); ret = ath11k_pci_claim(ab_pci, pdev); @@ -280,8 +632,43 @@ static int ath11k_pci_probe(struct pci_dev *pdev, goto err_pci_disable_msi; } + ret = ath11k_hal_srng_init(ab); + if (ret) + goto err_mhi_unregister; + + ret = ath11k_ce_alloc_pipes(ab); + if (ret) { + ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret); + goto err_hal_srng_deinit; + } + + ath11k_pci_init_qmi_ce_config(ab); + + ret = ath11k_pci_config_irq(ab); + if (ret) { + ath11k_err(ab, "failed to config irq: %d\n", ret); + goto err_ce_free; + } + + ret = ath11k_core_init(ab); + if (ret) { + ath11k_err(ab, "failed to init core: %d\n", ret); + goto err_free_irq; + } return 0; +err_free_irq: + ath11k_pci_free_irq(ab); + +err_ce_free: + ath11k_ce_free_pipes(ab); + +err_hal_srng_deinit: + ath11k_hal_srng_deinit(ab); + +err_mhi_unregister: + ath11k_mhi_unregister(ab_pci); + err_pci_disable_msi: ath11k_pci_disable_msi(ab_pci); @@ -303,6 +690,7 @@ static void ath11k_pci_remove(struct pci_dev *pdev) ath11k_mhi_unregister(ab_pci); ath11k_pci_disable_msi(ab_pci); ath11k_pci_free_region(ab_pci); + ath11k_pci_free_irq(ab); ath11k_core_free(ab); } -- cgit v1.2.3 From 1ff8ed786d5d8ed6d109affe6d732dfc85a45b2e Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Thu, 13 Aug 2020 12:04:26 +0300 Subject: ath11k: use remoteproc only with AHB devices QCA6390 and other PCI devices use MHI based firmware loading and do not use remoteproc, so enable it only for AHB devices. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597309466-19688-11-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/Kconfig | 2 +- drivers/net/wireless/ath/ath11k/ahb.c | 6 +++++- drivers/net/wireless/ath/ath11k/core.c | 29 ++++++++++++++++++++++++++--- drivers/net/wireless/ath/ath11k/core.h | 10 +++++++++- drivers/net/wireless/ath/ath11k/pci.c | 7 ++++++- 5 files changed, 47 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/Kconfig b/drivers/net/wireless/ath/ath11k/Kconfig index 7e5094e0e7bb..ad5cc6cac05b 100644 --- a/drivers/net/wireless/ath/ath11k/Kconfig +++ b/drivers/net/wireless/ath/ath11k/Kconfig @@ -2,7 +2,6 @@ config ATH11K tristate "Qualcomm Technologies 802.11ax chipset support" depends on MAC80211 && HAS_DMA - depends on REMOTEPROC depends on CRYPTO_MICHAEL_MIC select ATH_COMMON select QCOM_QMI_HELPERS @@ -15,6 +14,7 @@ config ATH11K config ATH11K_AHB tristate "Atheros ath11k AHB support" depends on ATH11K + depends on REMOTEPROC help This module adds support for AHB bus diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index f4c346bcc676..f00c4cc76d74 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -25,6 +25,10 @@ static const struct of_device_id ath11k_ahb_of_match[] = { MODULE_DEVICE_TABLE(of, ath11k_ahb_of_match); +static const struct ath11k_bus_params ath11k_ahb_bus_params = { + .mhi_support = false, +}; + /* Target firmware's Copy Engine configuration. */ static const struct ce_pipe_config target_ce_config_wlan[] = { /* CE0: host->target HTC control and raw streams */ @@ -855,7 +859,7 @@ static int ath11k_ahb_probe(struct platform_device *pdev) return ret; } - ab = ath11k_core_alloc(&pdev->dev, 0, ATH11K_BUS_AHB); + ab = ath11k_core_alloc(&pdev->dev, 0, ATH11K_BUS_AHB, &ath11k_ahb_bus_params); if (!ab) { dev_err(&pdev->dev, "failed to allocate ath11k base\n"); return -ENOMEM; diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 741093de3a83..22657dac7749 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -756,12 +756,14 @@ int ath11k_core_pre_init(struct ath11k_base *ab) } EXPORT_SYMBOL(ath11k_core_pre_init); -int ath11k_core_init(struct ath11k_base *ab) +static int ath11k_core_get_rproc(struct ath11k_base *ab) { struct device *dev = ab->dev; struct rproc *prproc; phandle rproc_phandle; - int ret; + + if (ab->bus_params.mhi_support) + return 0; if (of_property_read_u32(dev->of_node, "qcom,rproc", &rproc_phandle)) { ath11k_err(ab, "failed to get q6_rproc handle\n"); @@ -775,6 +777,25 @@ int ath11k_core_init(struct ath11k_base *ab) } ab->tgt_rproc = prproc; + return 0; +} + +int ath11k_core_init(struct ath11k_base *ab) +{ + int ret; + + ret = ath11k_core_get_rproc(ab); + if (ret) { + ath11k_err(ab, "failed to get rproc: %d\n", ret); + return ret; + } + + ret = ath11k_init_hw_params(ab); + if (ret) { + ath11k_err(ab, "failed to get hw params %d\n", ret); + return ret; + } + ret = ath11k_core_soc_create(ab); if (ret) { ath11k_err(ab, "failed to create soc core: %d\n", ret); @@ -807,7 +828,8 @@ void ath11k_core_free(struct ath11k_base *ab) EXPORT_SYMBOL(ath11k_core_free); struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size, - enum ath11k_bus bus) + enum ath11k_bus bus, + const struct ath11k_bus_params *bus_params) { struct ath11k_base *ab; @@ -830,6 +852,7 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size, INIT_WORK(&ab->restart_work, ath11k_core_restart); timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0); ab->dev = dev; + ab->bus_params = *bus_params; return ab; diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index a0a7c7b003c1..0309b13e38c9 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -580,6 +580,10 @@ struct ath11k_board_data { size_t len; }; +struct ath11k_bus_params { + bool mhi_support; +}; + /* IPQ8074 HW channel counters frequency value in hertz */ #define IPQ8074_CC_FREQ_HERTZ 320000 @@ -668,7 +672,10 @@ struct ath11k_base { u32 ext_service_bitmap[WMI_SERVICE_EXT_BM_SIZE]; bool pdevs_macaddr_valid; int bd_api; + struct ath11k_hw_params hw_params; + struct ath11k_bus_params bus_params; + const struct firmware *cal_file; /* Below regd's are protected by ab->data_lock */ @@ -845,7 +852,8 @@ int ath11k_core_pre_init(struct ath11k_base *ab); int ath11k_core_init(struct ath11k_base *ath11k); void ath11k_core_deinit(struct ath11k_base *ath11k); struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size, - enum ath11k_bus bus); + enum ath11k_bus bus, + const struct ath11k_bus_params *bus_params); void ath11k_core_free(struct ath11k_base *ath11k); int ath11k_core_fetch_bdf(struct ath11k_base *ath11k, struct ath11k_board_data *bd); diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index d1068766972d..d09faaf747ba 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -27,6 +27,10 @@ static const struct pci_device_id ath11k_pci_id_table[] = { MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); +static const struct ath11k_bus_params ath11k_pci_bus_params = { + .mhi_support = true, +}; + static const struct ath11k_msi_config msi_config = { .total_vectors = 32, .total_users = 4, @@ -594,7 +598,8 @@ static int ath11k_pci_probe(struct pci_dev *pdev, return -ENOTSUPP; } - ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI); + ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI, + &ath11k_pci_bus_params); if (!ab) { dev_err(&pdev->dev, "failed to allocate ath11k base\n"); return -ENOMEM; -- cgit v1.2.3 From 569704544778bea03f78df95ce87383a8724acff Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Fri, 14 Aug 2020 10:10:20 +0300 Subject: ath11k: add support for m3 firmware PCI devices like QCA6390 have a separate firmware image for the m3 micro-controller. Add support to load the firmware using m3.bin file. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597389030-13887-2-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/ahb.c | 1 + drivers/net/wireless/ath/ath11k/core.h | 1 + drivers/net/wireless/ath/ath11k/hw.h | 1 + drivers/net/wireless/ath/ath11k/pci.c | 1 + drivers/net/wireless/ath/ath11k/qmi.c | 82 +++++++++++++++++++++++++++++++--- drivers/net/wireless/ath/ath11k/qmi.h | 7 +++ 6 files changed, 86 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index f00c4cc76d74..746e84c4526c 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -27,6 +27,7 @@ MODULE_DEVICE_TABLE(of, ath11k_ahb_of_match); static const struct ath11k_bus_params ath11k_ahb_bus_params = { .mhi_support = false, + .m3_fw_support = false, }; /* Target firmware's Copy Engine configuration. */ diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 0309b13e38c9..b30abd611f0d 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -582,6 +582,7 @@ struct ath11k_board_data { struct ath11k_bus_params { bool mhi_support; + bool m3_fw_support; }; /* IPQ8074 HW channel counters frequency value in hertz */ diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index c02fd02839d4..5b443a212c85 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -73,6 +73,7 @@ #define ATH11K_DEFAULT_BOARD_FILE "board.bin" #define ATH11K_DEFAULT_CAL_FILE "caldata.bin" #define ATH11K_AMSS_FILE "amss.bin" +#define ATH11K_M3_FILE "m3.bin" enum ath11k_hw_rate_cck { ATH11K_HW_RATE_CCK_LP_11M = 0, diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index d09faaf747ba..802461d1261a 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -29,6 +29,7 @@ MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); static const struct ath11k_bus_params ath11k_pci_bus_params = { .mhi_support = true, + .m3_fw_support = true, }; static const struct ath11k_msi_config msi_config = { diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index 50812df6527d..0d7441e6ff17 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -1516,11 +1516,17 @@ static int ath11k_qmi_host_cap_send(struct ath11k_base *ab) req.bdf_support_valid = 1; req.bdf_support = 1; - req.m3_support_valid = 0; - req.m3_support = 0; - - req.m3_cache_support_valid = 0; - req.m3_cache_support = 0; + if (ab->bus_params.m3_fw_support) { + req.m3_support_valid = 1; + req.m3_support = 1; + req.m3_cache_support_valid = 1; + req.m3_cache_support = 1; + } else { + req.m3_support_valid = 0; + req.m3_support = 0; + req.m3_cache_support_valid = 0; + req.m3_cache_support = 0; + } req.cal_done_valid = 1; req.cal_done = ab->qmi.cal_done; @@ -1908,8 +1914,57 @@ out: return ret; } +static int ath11k_qmi_m3_load(struct ath11k_base *ab) +{ + struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; + const struct firmware *fw; + char path[100]; + int ret; + + if (m3_mem->vaddr || m3_mem->size) + return 0; + + fw = ath11k_core_firmware_request(ab, ATH11K_M3_FILE); + if (IS_ERR(fw)) { + ret = PTR_ERR(fw); + ath11k_core_create_firmware_path(ab, ATH11K_M3_FILE, + path, sizeof(path)); + ath11k_err(ab, "failed to load %s: %d\n", path, ret); + return ret; + } + + m3_mem->vaddr = dma_alloc_coherent(ab->dev, + fw->size, &m3_mem->paddr, + GFP_KERNEL); + if (!m3_mem->vaddr) { + ath11k_err(ab, "failed to allocate memory for M3 with size %zu\n", + fw->size); + release_firmware(fw); + return -ENOMEM; + } + + memcpy(m3_mem->vaddr, fw->data, fw->size); + m3_mem->size = fw->size; + release_firmware(fw); + + return 0; +} + +static void ath11k_qmi_m3_free(struct ath11k_base *ab) +{ + struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; + + if (!ab->bus_params.m3_fw_support || !m3_mem->vaddr) + return; + + dma_free_coherent(ab->dev, m3_mem->size, + m3_mem->vaddr, m3_mem->paddr); + m3_mem->vaddr = NULL; +} + static int ath11k_qmi_wlanfw_m3_info_send(struct ath11k_base *ab) { + struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; struct qmi_wlanfw_m3_info_req_msg_v01 req; struct qmi_wlanfw_m3_info_resp_msg_v01 resp; struct qmi_txn txn = {}; @@ -1917,8 +1972,20 @@ static int ath11k_qmi_wlanfw_m3_info_send(struct ath11k_base *ab) memset(&req, 0, sizeof(req)); memset(&resp, 0, sizeof(resp)); - req.addr = 0; - req.size = 0; + + if (ab->bus_params.m3_fw_support) { + ret = ath11k_qmi_m3_load(ab); + if (ret) { + ath11k_err(ab, "failed to load m3 firmware: %d", ret); + return ret; + } + + req.addr = m3_mem->paddr; + req.size = m3_mem->size; + } else { + req.addr = 0; + req.size = 0; + } ret = qmi_txn_init(&ab->qmi.handle, &txn, qmi_wlanfw_m3_info_resp_msg_v01_ei, &resp); @@ -2424,5 +2491,6 @@ void ath11k_qmi_deinit_service(struct ath11k_base *ab) qmi_handle_release(&ab->qmi.handle); cancel_work_sync(&ab->qmi.event_work); destroy_workqueue(ab->qmi.event_wq); + ath11k_qmi_m3_free(ab); } diff --git a/drivers/net/wireless/ath/ath11k/qmi.h b/drivers/net/wireless/ath/ath11k/qmi.h index 3307be5be687..dd9e498a2056 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.h +++ b/drivers/net/wireless/ath/ath11k/qmi.h @@ -96,6 +96,12 @@ struct target_info { char fw_build_id[ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 + 1]; }; +struct m3_mem_region { + u32 size; + dma_addr_t paddr; + void *vaddr; +}; + struct ath11k_qmi { struct ath11k_base *ab; struct qmi_handle handle; @@ -110,6 +116,7 @@ struct ath11k_qmi { u32 target_mem_mode; u8 cal_done; struct target_info target; + struct m3_mem_region m3_mem; }; #define QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN 189 -- cgit v1.2.3 From 6eb6ea5138287306da5c8553504e07d20c100fa3 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Fri, 14 Aug 2020 10:10:21 +0300 Subject: ath11k: add board file support for PCI devices PCI devices like QCA6390 load the board file differently, add support for that and the method is chosen using bus_params variables. Add support to create board name for different targets. This board name is used to parse the board data from board-2.bin for ahb/pci based targets. As struct target_mem_chunk::vaddr was changed from 'u32' to 'u32 *' in ath11k_qmi_assign_target_mem_chunk() vaddr assignments were changed to NULL to avoid a compilation warning. IPQ8074 does not use the vaddr field for anything so that change does not affect functionality. At the moment this only supports board files with BIN type. Support for ELF type, which seems to be more popular on QCA6390 devices, needs to be added later. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597389030-13887-3-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/ahb.c | 2 + drivers/net/wireless/ath/ath11k/core.c | 7 +- drivers/net/wireless/ath/ath11k/core.h | 15 ++++ drivers/net/wireless/ath/ath11k/pci.c | 2 + drivers/net/wireless/ath/ath11k/qmi.c | 144 +++++++++++++++++++++++++++++++-- drivers/net/wireless/ath/ath11k/qmi.h | 7 +- 6 files changed, 167 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 746e84c4526c..06e599cbfbf9 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -28,6 +28,8 @@ MODULE_DEVICE_TABLE(of, ath11k_ahb_of_match); static const struct ath11k_bus_params ath11k_ahb_bus_params = { .mhi_support = false, .m3_fw_support = false, + .fixed_bdf_addr = true, + .fixed_mem_region = true, }; /* Target firmware's Copy Engine configuration. */ diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 22657dac7749..a3a53debc24f 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -50,11 +50,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { static int ath11k_core_create_board_name(struct ath11k_base *ab, char *name, size_t name_len) { - /* Note: bus is fixed to ahb. When other bus type supported, - * make it to dynamic. - */ scnprintf(name, name_len, - "bus=ahb,qmi-chip-id=%d,qmi-board-id=%d", + "bus=%s,qmi-chip-id=%d,qmi-board-id=%d", + ath11k_bus_str(ab->hif.bus), ab->qmi.target.chip_id, ab->qmi.target.board_id); @@ -853,6 +851,7 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size, timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0); ab->dev = dev; ab->bus_params = *bus_params; + ab->hif.bus = bus; return ab; diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index b30abd611f0d..6e351e7bded8 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -583,6 +583,8 @@ struct ath11k_board_data { struct ath11k_bus_params { bool mhi_support; bool m3_fw_support; + bool fixed_bdf_addr; + bool fixed_mem_region; }; /* IPQ8074 HW channel counters frequency value in hertz */ @@ -647,6 +649,7 @@ struct ath11k_base { unsigned long mem_len; struct { + enum ath11k_bus bus; const struct ath11k_hif_ops *ops; } hif; @@ -905,4 +908,16 @@ static inline void ath11k_core_create_firmware_path(struct ath11k_base *ab, ab->hw_params.fw.dir, filename); } +static inline const char *ath11k_bus_str(enum ath11k_bus bus) +{ + switch (bus) { + case ATH11K_BUS_PCI: + return "pci"; + case ATH11K_BUS_AHB: + return "ahb"; + } + + return "unknown"; +} + #endif /* _CORE_H_ */ diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 802461d1261a..dd3122b47d35 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -30,6 +30,8 @@ MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); static const struct ath11k_bus_params ath11k_pci_bus_params = { .mhi_support = true, .m3_fw_support = true, + .fixed_bdf_addr = false, + .fixed_mem_region = false, }; static const struct ath11k_msi_config msi_config = { diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index 0d7441e6ff17..b182d6181057 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -1680,7 +1680,48 @@ out: return ret; } +static void ath11k_qmi_free_target_mem_chunk(struct ath11k_base *ab) +{ + int i; + + if (ab->bus_params.fixed_mem_region) + return; + + for (i = 0; i < ab->qmi.mem_seg_count; i++) { + if (!ab->qmi.target_mem[i].vaddr) + continue; + + dma_free_coherent(ab->dev, + ab->qmi.target_mem[i].size, + ab->qmi.target_mem[i].vaddr, + ab->qmi.target_mem[i].paddr); + ab->qmi.target_mem[i].vaddr = NULL; + } +} + static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab) +{ + int i; + struct target_mem_chunk *chunk; + + for (i = 0; i < ab->qmi.mem_seg_count; i++) { + chunk = &ab->qmi.target_mem[i]; + chunk->vaddr = dma_alloc_coherent(ab->dev, + chunk->size, + &chunk->paddr, + GFP_KERNEL); + if (!chunk->vaddr) { + ath11k_err(ab, "failed to alloc memory, size: 0x%x, type: %u\n", + chunk->size, + chunk->type); + return -EINVAL; + } + } + + return 0; +} + +static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab) { int i, idx; @@ -1688,7 +1729,7 @@ static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab) switch (ab->qmi.target_mem[i].type) { case BDF_MEM_REGION_TYPE: ab->qmi.target_mem[idx].paddr = ab->hw_params.bdf_addr; - ab->qmi.target_mem[idx].vaddr = ab->hw_params.bdf_addr; + ab->qmi.target_mem[idx].vaddr = NULL; ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size; ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type; idx++; @@ -1700,7 +1741,7 @@ static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab) } /* TODO ath11k does not support cold boot calibration */ ab->qmi.target_mem[idx].paddr = 0; - ab->qmi.target_mem[idx].vaddr = 0; + ab->qmi.target_mem[idx].vaddr = NULL; ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size; ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type; idx++; @@ -1842,7 +1883,7 @@ out: return ret; } -static int ath11k_qmi_load_bdf(struct ath11k_base *ab) +static int ath11k_qmi_load_bdf_fixed_addr(struct ath11k_base *ab) { struct qmi_wlanfw_bdf_download_req_msg_v01 *req; struct qmi_wlanfw_bdf_download_resp_msg_v01 resp; @@ -1914,6 +1955,92 @@ out: return ret; } +static int ath11k_qmi_load_bdf_qmi(struct ath11k_base *ab) +{ + struct qmi_wlanfw_bdf_download_req_msg_v01 *req; + struct qmi_wlanfw_bdf_download_resp_msg_v01 resp; + struct ath11k_board_data bd; + unsigned int remaining; + struct qmi_txn txn = {}; + int ret; + const u8 *temp; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + memset(&resp, 0, sizeof(resp)); + + memset(&bd, 0, sizeof(bd)); + ret = ath11k_core_fetch_bdf(ab, &bd); + if (ret) { + ath11k_warn(ab, "qmi failed to load bdf:\n"); + goto out; + } + + temp = bd.data; + remaining = bd.len; + + while (remaining) { + req->valid = 1; + req->file_id_valid = 1; + req->file_id = ab->qmi.target.board_id; + req->total_size_valid = 1; + req->total_size = bd.len; + req->seg_id_valid = 1; + req->data_valid = 1; + req->data_len = ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE; + req->bdf_type = ATH11K_QMI_BDF_TYPE_BIN; + req->bdf_type_valid = 1; + req->end_valid = 1; + req->end = 0; + + if (remaining > QMI_WLANFW_MAX_DATA_SIZE_V01) { + req->data_len = QMI_WLANFW_MAX_DATA_SIZE_V01; + } else { + req->data_len = remaining; + req->end = 1; + } + + memcpy(req->data, temp, req->data_len); + + ret = qmi_txn_init(&ab->qmi.handle, &txn, + qmi_wlanfw_bdf_download_resp_msg_v01_ei, + &resp); + if (ret < 0) + goto out_qmi_bdf; + + ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, + QMI_WLANFW_BDF_DOWNLOAD_REQ_V01, + QMI_WLANFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_LEN, + qmi_wlanfw_bdf_download_req_msg_v01_ei, req); + if (ret < 0) { + qmi_txn_cancel(&txn); + goto out_qmi_bdf; + } + + ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS)); + if (ret < 0) + goto out_qmi_bdf; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath11k_warn(ab, "qmi BDF download failed, result: %d, err: %d\n", + resp.resp.result, resp.resp.error); + ret = resp.resp.result; + goto out_qmi_bdf; + } + remaining -= req->data_len; + temp += req->data_len; + req->seg_id++; + } + +out_qmi_bdf: + ath11k_core_free_bdf(ab, &bd); + +out: + kfree(req); + return ret; +} + static int ath11k_qmi_m3_load(struct ath11k_base *ab) { struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; @@ -2242,7 +2369,10 @@ static void ath11k_qmi_event_load_bdf(struct ath11k_qmi *qmi) return; } - ret = ath11k_qmi_load_bdf(ab); + if (ab->bus_params.fixed_bdf_addr) + ret = ath11k_qmi_load_bdf_fixed_addr(ab); + else + ret = ath11k_qmi_load_bdf_qmi(ab); if (ret < 0) { ath11k_warn(ab, "qmi failed to load board data file:%d\n", ret); return; @@ -2281,7 +2411,10 @@ static void ath11k_qmi_msg_mem_request_cb(struct qmi_handle *qmi_hdl, msg->mem_seg[i].type, msg->mem_seg[i].size); } - ret = ath11k_qmi_alloc_target_mem_chunk(ab); + if (ab->bus_params.fixed_mem_region) + ret = ath11k_qmi_assign_target_mem_chunk(ab); + else + ret = ath11k_qmi_alloc_target_mem_chunk(ab); if (ret < 0) { ath11k_warn(ab, "qmi failed to alloc target memory:%d\n", ret); return; @@ -2492,5 +2625,6 @@ void ath11k_qmi_deinit_service(struct ath11k_base *ab) cancel_work_sync(&ab->qmi.event_work); destroy_workqueue(ab->qmi.event_wq); ath11k_qmi_m3_free(ab); + ath11k_qmi_free_target_mem_chunk(ab); } diff --git a/drivers/net/wireless/ath/ath11k/qmi.h b/drivers/net/wireless/ath/ath11k/qmi.h index dd9e498a2056..cd484a4d0216 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.h +++ b/drivers/net/wireless/ath/ath11k/qmi.h @@ -40,6 +40,11 @@ enum ath11k_qmi_file_type { ATH11K_QMI_MAX_FILE_TYPE, }; +enum ath11k_qmi_bdf_type { + ATH11K_QMI_BDF_TYPE_BIN = 0, + ATH11K_QMI_BDF_TYPE_ELF = 1, +}; + enum ath11k_qmi_event_type { ATH11K_QMI_EVENT_SERVER_ARRIVE, ATH11K_QMI_EVENT_SERVER_EXIT, @@ -83,7 +88,7 @@ struct target_mem_chunk { u32 size; u32 type; dma_addr_t paddr; - u32 vaddr; + u32 *vaddr; }; struct target_info { -- cgit v1.2.3 From eb8de0490e1f819c50c1b5b0a5558a9897dd75f0 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Fri, 14 Aug 2020 10:10:22 +0300 Subject: ath11k: fill appropriate QMI service instance id for QCA6390 QMI service instance id is used for qmi service lookup, IPQ8074 and QCA6390 uses different instance id for service lookup. Fill appropriate QMI service instance id for respective targets. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597389030-13887-4-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/ahb.c | 1 + drivers/net/wireless/ath/ath11k/pci.c | 1 + drivers/net/wireless/ath/ath11k/qmi.c | 2 +- drivers/net/wireless/ath/ath11k/qmi.h | 3 +++ 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 06e599cbfbf9..2e0d90c022bb 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -581,6 +581,7 @@ static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab) cfg->tgt_ce = target_ce_config_wlan; cfg->svc_to_ce_map_len = ARRAY_SIZE(target_service_to_ce_map_wlan); cfg->svc_to_ce_map = target_service_to_ce_map_wlan; + ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ8074; } static void ath11k_ahb_free_ext_irq(struct ath11k_base *ab) diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index dd3122b47d35..47ee5689a5e2 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -393,6 +393,7 @@ static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) cfg->svc_to_ce_map = target_service_to_ce_map_wlan; cfg->svc_to_ce_map_len = ARRAY_SIZE(target_service_to_ce_map_wlan); + ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390; } static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index b182d6181057..acf7a3f2fe77 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -2610,7 +2610,7 @@ int ath11k_qmi_init_service(struct ath11k_base *ab) ret = qmi_add_lookup(&ab->qmi.handle, ATH11K_QMI_WLFW_SERVICE_ID_V01, ATH11K_QMI_WLFW_SERVICE_VERS_V01, - ATH11K_QMI_WLFW_SERVICE_INS_ID_V01); + ab->qmi.service_ins_id); if (ret < 0) { ath11k_warn(ab, "failed to add qmi lookup\n"); return ret; diff --git a/drivers/net/wireless/ath/ath11k/qmi.h b/drivers/net/wireless/ath/ath11k/qmi.h index cd484a4d0216..d55ce6cf7222 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.h +++ b/drivers/net/wireless/ath/ath11k/qmi.h @@ -18,6 +18,8 @@ #define ATH11K_QMI_WLFW_SERVICE_ID_V01 0x45 #define ATH11K_QMI_WLFW_SERVICE_VERS_V01 0x01 #define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01 0x02 +#define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390 0x01 +#define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ8074 0x02 #define ATH11K_QMI_WLANFW_MAX_TIMESTAMP_LEN_V01 32 #define ATH11K_QMI_RESP_LEN_MAX 8192 #define ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01 32 @@ -122,6 +124,7 @@ struct ath11k_qmi { u8 cal_done; struct target_info target; struct m3_mem_region m3_mem; + unsigned int service_ins_id; }; #define QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN 189 -- cgit v1.2.3 From 654e959ae0a19b90045d0e4d90a602ae2828a855 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Fri, 14 Aug 2020 10:10:23 +0300 Subject: ath11k: pci: add read32() and write32() hif operations Add support for bus read/write/window selection operations for reading hardware memory. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597389030-13887-5-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/pci.c | 55 +++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/pci.h | 4 +++ 2 files changed, 59 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 47ee5689a5e2..10c281ece3d4 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -18,6 +18,12 @@ #define ATH11K_PCI_IRQ_CE0_OFFSET 3 +#define WINDOW_ENABLE_BIT 0x40000000 +#define WINDOW_REG_ADDRESS 0x310c +#define WINDOW_VALUE_MASK GENMASK(24, 19) +#define WINDOW_START 0x80000 +#define WINDOW_RANGE_MASK GENMASK(18, 0) + #define QCA6390_DEVICE_ID 0x1101 static const struct pci_device_id ath11k_pci_id_table[] = { @@ -280,6 +286,52 @@ static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { "tcl2host-status-ring", }; +static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset) +{ + struct ath11k_base *ab = ab_pci->ab; + + u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset); + + lockdep_assert_held(&ab_pci->window_lock); + + if (window != ab_pci->register_window) { + iowrite32(WINDOW_ENABLE_BIT | window, + ab->mem + WINDOW_REG_ADDRESS); + ab_pci->register_window = window; + } +} + +static void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value) +{ + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + + if (offset < WINDOW_START) { + iowrite32(value, ab->mem + offset); + } else { + spin_lock_bh(&ab_pci->window_lock); + ath11k_pci_select_window(ab_pci, offset); + iowrite32(value, ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK)); + spin_unlock_bh(&ab_pci->window_lock); + } +} + +static u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset) +{ + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + u32 val; + + if (offset < WINDOW_START) { + val = ioread32(ab->mem + offset); + } else { + spin_lock_bh(&ab_pci->window_lock); + ath11k_pci_select_window(ab_pci, offset); + val = ioread32(ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK)); + spin_unlock_bh(&ab_pci->window_lock); + } + + return val; +} + int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) { struct pci_dev *pci_dev = to_pci_dev(dev); @@ -578,6 +630,8 @@ static int ath11k_pci_start(struct ath11k_base *ab) static const struct ath11k_hif_ops ath11k_pci_hif_ops = { .start = ath11k_pci_start, .stop = ath11k_pci_stop, + .read32 = ath11k_pci_read32, + .write32 = ath11k_pci_write32, .power_down = ath11k_pci_power_down, .power_up = ath11k_pci_power_up, }; @@ -618,6 +672,7 @@ static int ath11k_pci_probe(struct pci_dev *pdev, ab_pci->pdev = pdev; ab->hif.ops = &ath11k_pci_hif_ops; pci_set_drvdata(pdev, ab); + spin_lock_init(&ab_pci->window_lock); ret = ath11k_pci_claim(ab_pci, pdev); if (ret) { diff --git a/drivers/net/wireless/ath/ath11k/pci.h b/drivers/net/wireless/ath/ath11k/pci.h index 85e033069d7a..0a262c7307fd 100644 --- a/drivers/net/wireless/ath/ath11k/pci.h +++ b/drivers/net/wireless/ath/ath11k/pci.h @@ -29,6 +29,10 @@ struct ath11k_pci { u32 msi_ep_base_data; struct mhi_controller *mhi_ctrl; unsigned long mhi_state; + u32 register_window; + + /* protects register_window above */ + spinlock_t window_lock; }; static inline struct ath11k_pci *ath11k_pci_priv(struct ath11k_base *ab) -- cgit v1.2.3 From c4eacabee22415194e8cc7e8dd4913897b058927 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Fri, 14 Aug 2020 10:10:24 +0300 Subject: ath11k: configure copy engine msi address in CE srng Fill msi base address and msi data to be programmed in CE srang. This is used by the srng to generate the msi interrupt. Needed for PCI support. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597389030-13887-6-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/ce.c | 30 ++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/hal.h | 2 ++ drivers/net/wireless/ath/ath11k/hif.h | 26 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/pci.c | 25 +++++++++++++++++++++++++ 4 files changed, 83 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index 2fff171b35f8..a457fe7f7049 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c @@ -5,6 +5,7 @@ #include "dp_rx.h" #include "debug.h" +#include "hif.h" static const struct ce_attr host_ce_config_wlan[] = { /* CE0: host->target HTC control and raw streams */ @@ -352,6 +353,31 @@ static void ath11k_ce_send_done_cb(struct ath11k_ce_pipe *pipe) } } +static void ath11k_ce_srng_msi_ring_params_setup(struct ath11k_base *ab, u32 ce_id, + struct hal_srng_params *ring_params) +{ + u32 msi_data_start; + u32 msi_data_count; + u32 msi_irq_start; + u32 addr_lo; + u32 addr_hi; + int ret; + + ret = ath11k_get_user_msi_vector(ab, "CE", + &msi_data_count, &msi_data_start, + &msi_irq_start); + + if (ret) + return; + + ath11k_get_msi_address(ab, &addr_lo, &addr_hi); + + ring_params->msi_addr = addr_lo; + ring_params->msi_addr |= (dma_addr_t)(((uint64_t)addr_hi) << 32); + ring_params->msi_data = (ce_id % msi_data_count) + msi_data_start; + ring_params->flags |= HAL_SRNG_FLAGS_MSI_INTR; +} + static int ath11k_ce_init_ring(struct ath11k_base *ab, struct ath11k_ce_ring *ce_ring, int ce_id, enum hal_ring_type type) @@ -395,6 +421,10 @@ static int ath11k_ce_init_ring(struct ath11k_base *ab, ret, ce_id); return ret; } + + if (!(CE_ATTR_DIS_INTR & host_ce_config_wlan[ce_id].flags)) + ath11k_ce_srng_msi_ring_params_setup(ab, ce_id, ¶ms); + ce_ring->hal_ring_id = ret; return 0; diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h index 780a3e11b609..6d9a6938870c 100644 --- a/drivers/net/wireless/ath/ath11k/hal.h +++ b/drivers/net/wireless/ath/ath11k/hal.h @@ -458,6 +458,8 @@ struct hal_srng_params { u32 flags; u32 max_buffer_len; u32 low_threshold; + dma_addr_t msi_addr; + u32 msi_data; /* Add more params as needed */ }; diff --git a/drivers/net/wireless/ath/ath11k/hif.h b/drivers/net/wireless/ath/ath11k/hif.h index 48ee55cebc81..dbe5568916e8 100644 --- a/drivers/net/wireless/ath/ath11k/hif.h +++ b/drivers/net/wireless/ath/ath11k/hif.h @@ -19,6 +19,11 @@ struct ath11k_hif_ops { void (*power_down)(struct ath11k_base *sc); int (*map_service_to_pipe)(struct ath11k_base *sc, u16 service_id, u8 *ul_pipe, u8 *dl_pipe); + int (*get_user_msi_vector)(struct ath11k_base *ab, char *user_name, + int *num_vectors, u32 *user_base_data, + u32 *base_vector); + void (*get_msi_address)(struct ath11k_base *ab, u32 *msi_addr_lo, + u32 *msi_addr_hi); }; static inline int ath11k_hif_start(struct ath11k_base *sc) @@ -66,4 +71,25 @@ static inline int ath11k_hif_map_service_to_pipe(struct ath11k_base *sc, u16 ser { return sc->hif.ops->map_service_to_pipe(sc, service_id, ul_pipe, dl_pipe); } + +static inline int ath11k_get_user_msi_vector(struct ath11k_base *ab, char *user_name, + int *num_vectors, u32 *user_base_data, + u32 *base_vector) +{ + if (!ab->hif.ops->get_user_msi_vector) + return -EOPNOTSUPP; + + return ab->hif.ops->get_user_msi_vector(ab, user_name, num_vectors, + user_base_data, + base_vector); +} + +static inline void ath11k_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, + u32 *msi_addr_hi) +{ + if (!ab->hif.ops->get_msi_address) + return; + + ab->hif.ops->get_msi_address(ab, msi_addr_lo, msi_addr_hi); +} #endif /* _HIF_H_ */ diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 10c281ece3d4..af08f0542867 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -339,6 +339,18 @@ int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) return pci_irq_vector(pci_dev, vector); } +static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, + u32 *msi_addr_hi) +{ + struct pci_dev *pci_dev = to_pci_dev(ab->dev); + + pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, + msi_addr_lo); + + pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, + msi_addr_hi); +} + int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name, int *num_vectors, u32 *user_base_data, u32 *base_vector) @@ -366,6 +378,17 @@ int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_nam return -EINVAL; } +static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, + int *num_vectors, u32 *user_base_data, + u32 *base_vector) +{ + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + + return ath11k_pci_get_user_msi_assignment(ab_pci, user_name, + num_vectors, user_base_data, + base_vector); +} + static void ath11k_pci_free_irq(struct ath11k_base *ab) { int i, irq_idx; @@ -634,6 +657,8 @@ static const struct ath11k_hif_ops ath11k_pci_hif_ops = { .write32 = ath11k_pci_write32, .power_down = ath11k_pci_power_down, .power_up = ath11k_pci_power_up, + .get_msi_address = ath11k_pci_get_msi_address, + .get_user_msi_vector = ath11k_get_user_msi_assignment, }; static int ath11k_pci_probe(struct pci_dev *pdev, -- cgit v1.2.3 From 2c3960c2253dc8028a8928e8161e030eec3ebe4a Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Fri, 14 Aug 2020 10:10:25 +0300 Subject: ath11k: setup ce tasklet for control path CE srng is used for control path and CE srng processing is done using tasklet bottom half. Setup ce tasklet initialization and scheduling for control path. Needed for PCI support. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Govind Singh Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597389030-13887-7-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/ce.c | 2 + drivers/net/wireless/ath/ath11k/ce.h | 2 + drivers/net/wireless/ath/ath11k/pci.c | 116 +++++++++++++++++++++++++++++++--- 3 files changed, 112 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index a457fe7f7049..59cb403b8597 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c @@ -524,6 +524,7 @@ void ath11k_ce_poll_send_completed(struct ath11k_base *ab, u8 pipe_id) if ((pipe->attr_flags & CE_ATTR_DIS_INTR) && pipe->send_cb) pipe->send_cb(pipe); } +EXPORT_SYMBOL(ath11k_ce_per_engine_service); int ath11k_ce_send(struct ath11k_base *ab, struct sk_buff *skb, u8 pipe_id, u16 transfer_id) @@ -673,6 +674,7 @@ void ath11k_ce_rx_post_buf(struct ath11k_base *ab) } } } +EXPORT_SYMBOL(ath11k_ce_rx_post_buf); void ath11k_ce_rx_replenish_retry(struct timer_list *t) { diff --git a/drivers/net/wireless/ath/ath11k/ce.h b/drivers/net/wireless/ath/ath11k/ce.h index 688f357e6eaf..6e3a37909ade 100644 --- a/drivers/net/wireless/ath/ath11k/ce.h +++ b/drivers/net/wireless/ath/ath11k/ce.h @@ -181,4 +181,6 @@ int ath11k_ce_alloc_pipes(struct ath11k_base *ab); void ath11k_ce_free_pipes(struct ath11k_base *ab); int ath11k_ce_get_attr_flags(int ce_id); void ath11k_ce_poll_send_completed(struct ath11k_base *ab, u8 pipe_id); +int ath11k_ce_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, + u8 *ul_pipe, u8 *dl_pipe); #endif diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index af08f0542867..d5dcbb928baf 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -401,6 +401,14 @@ static void ath11k_pci_free_irq(struct ath11k_base *ab) } } +static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) +{ + u32 irq_idx; + + irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; + enable_irq(ab->irq_num[irq_idx]); +} + static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) { u32 irq_idx; @@ -409,11 +417,46 @@ static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) disable_irq_nosync(ab->irq_num[irq_idx]); } +static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab) +{ + int i; + + for (i = 0; i < CE_COUNT; i++) { + if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) + continue; + ath11k_pci_ce_irq_disable(ab, i); + } +} + +static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab) +{ + int i; + int irq_idx; + + for (i = 0; i < CE_COUNT; i++) { + if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) + continue; + + irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; + synchronize_irq(ab->irq_num[irq_idx]); + } +} + +static void ath11k_pci_ce_tasklet(unsigned long data) +{ + struct ath11k_ce_pipe *ce_pipe = (struct ath11k_ce_pipe *)data; + + ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); + + ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num); +} + static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) { struct ath11k_ce_pipe *ce_pipe = arg; ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num); + tasklet_schedule(&ce_pipe->intr_tq); return IRQ_HANDLED; } @@ -444,6 +487,9 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab) irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; + tasklet_init(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet, + (unsigned long)ce_pipe); + ret = request_irq(irq, ath11k_pci_ce_interrupt_handler, IRQF_SHARED, irq_name[irq_idx], ce_pipe); @@ -471,14 +517,6 @@ static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390; } -static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) -{ - u32 irq_idx; - - irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; - enable_irq(ab->irq_num[irq_idx]); -} - static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab) { int i; @@ -638,14 +676,75 @@ static void ath11k_pci_power_down(struct ath11k_base *ab) ath11k_mhi_stop(ab_pci); } +static void ath11k_pci_kill_tasklets(struct ath11k_base *ab) +{ + int i; + + for (i = 0; i < CE_COUNT; i++) { + struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; + + if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) + continue; + + tasklet_kill(&ce_pipe->intr_tq); + } +} + static void ath11k_pci_stop(struct ath11k_base *ab) { + ath11k_pci_ce_irqs_disable(ab); + ath11k_pci_sync_ce_irqs(ab); + ath11k_pci_kill_tasklets(ab); ath11k_ce_cleanup_pipes(ab); } static int ath11k_pci_start(struct ath11k_base *ab) { ath11k_pci_ce_irqs_enable(ab); + ath11k_ce_rx_post_buf(ab); + + return 0; +} + +static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, + u8 *ul_pipe, u8 *dl_pipe) +{ + const struct service_to_pipe *entry; + bool ul_set = false, dl_set = false; + int i; + + for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) { + entry = &target_service_to_ce_map_wlan[i]; + + if (__le32_to_cpu(entry->service_id) != service_id) + continue; + + switch (__le32_to_cpu(entry->pipedir)) { + case PIPEDIR_NONE: + break; + case PIPEDIR_IN: + WARN_ON(dl_set); + *dl_pipe = __le32_to_cpu(entry->pipenum); + dl_set = true; + break; + case PIPEDIR_OUT: + WARN_ON(ul_set); + *ul_pipe = __le32_to_cpu(entry->pipenum); + ul_set = true; + break; + case PIPEDIR_INOUT: + WARN_ON(dl_set); + WARN_ON(ul_set); + *dl_pipe = __le32_to_cpu(entry->pipenum); + *ul_pipe = __le32_to_cpu(entry->pipenum); + dl_set = true; + ul_set = true; + break; + } + } + + if (WARN_ON(!ul_set || !dl_set)) + return -ENOENT; return 0; } @@ -659,6 +758,7 @@ static const struct ath11k_hif_ops ath11k_pci_hif_ops = { .power_up = ath11k_pci_power_up, .get_msi_address = ath11k_pci_get_msi_address, .get_user_msi_vector = ath11k_get_user_msi_assignment, + .map_service_to_pipe = ath11k_pci_map_service_to_pipe, }; static int ath11k_pci_probe(struct pci_dev *pdev, -- cgit v1.2.3 From 26f3a021b37ccca6c76c8c7c90ff684f8468e350 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Fri, 14 Aug 2020 10:10:26 +0300 Subject: ath11k: allocate smaller chunks of memory for firmware On x86 it's sometimes difficult to allocate a large contigous DMA memory, so instead allocate blocks of small chunk memory. In ath11k_qmi_msg_mem_request_cb() the error handling was cleaned up to avoid an unused variable warning. Also changed the test from (ret < 0) to just (ret) as the functions don't return any positive values. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597389030-13887-8-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/qmi.c | 42 +++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index acf7a3f2fe77..b386ab4bd806 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -1640,19 +1640,30 @@ static int ath11k_qmi_respond_fw_mem_request(struct ath11k_base *ab) memset(&resp, 0, sizeof(resp)); - req->mem_seg_len = ab->qmi.mem_seg_count; + /* For QCA6390 by default FW requests a block of ~4M contiguous + * DMA memory, it's hard to allocate from OS. So host returns + * failure to FW and FW will then request mulitple blocks of small + * chunk size memory. + */ + if (!ab->bus_params.fixed_mem_region && ab->qmi.mem_seg_count <= 2) { + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi delays mem_request %d\n", + ab->qmi.mem_seg_count); + memset(req, 0, sizeof(*req)); + } else { + req->mem_seg_len = ab->qmi.mem_seg_count; + + for (i = 0; i < req->mem_seg_len ; i++) { + req->mem_seg[i].addr = ab->qmi.target_mem[i].paddr; + req->mem_seg[i].size = ab->qmi.target_mem[i].size; + req->mem_seg[i].type = ab->qmi.target_mem[i].type; + } + } ret = qmi_txn_init(&ab->qmi.handle, &txn, qmi_wlanfw_respond_mem_resp_msg_v01_ei, &resp); if (ret < 0) goto out; - for (i = 0; i < req->mem_seg_len ; i++) { - req->mem_seg[i].addr = ab->qmi.target_mem[i].paddr; - req->mem_seg[i].size = ab->qmi.target_mem[i].size; - req->mem_seg[i].type = ab->qmi.target_mem[i].type; - } - ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, QMI_WLANFW_RESPOND_MEM_REQ_V01, QMI_WLANFW_RESPOND_MEM_REQ_MSG_V01_MAX_LEN, @@ -2411,13 +2422,20 @@ static void ath11k_qmi_msg_mem_request_cb(struct qmi_handle *qmi_hdl, msg->mem_seg[i].type, msg->mem_seg[i].size); } - if (ab->bus_params.fixed_mem_region) + if (ab->bus_params.fixed_mem_region) { ret = ath11k_qmi_assign_target_mem_chunk(ab); - else + if (ret) { + ath11k_warn(ab, "qmi failed to assign target memory: %d\n", + ret); + return; + } + } else if (msg->mem_seg_len > 2) { ret = ath11k_qmi_alloc_target_mem_chunk(ab); - if (ret < 0) { - ath11k_warn(ab, "qmi failed to alloc target memory:%d\n", ret); - return; + if (ret) { + ath11k_warn(ab, "qmi failed to alloc target memory: %d\n", + ret); + return; + } } ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_REQUEST_MEM, NULL); -- cgit v1.2.3 From f44dd33e6336294df23ec61f1bbe37a372f5f130 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Fri, 14 Aug 2020 10:10:27 +0300 Subject: ath11k: fix memory OOB access in qmi_decode The decoded_size is wrongly assigned in ath11k_qmi_msg_handlers and it results in out of boundary access in qmi_decode. The correct decoded_size should be calculated from the related ind_msg structure. This issue is exposed with QCA6390 because it needs 11 small memory chunks which are stored in qmi_wlanfw_request_mem_ind_msg_v01 and hence the decoded_size exceeds the wrongly assigend decoded_size. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597389030-13887-9-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/qmi.c | 8 ++++---- drivers/net/wireless/ath/ath11k/qmi.h | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index b386ab4bd806..529886b1f068 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -2477,21 +2477,21 @@ static const struct qmi_msg_handler ath11k_qmi_msg_handlers[] = { .type = QMI_INDICATION, .msg_id = QMI_WLFW_REQUEST_MEM_IND_V01, .ei = qmi_wlanfw_request_mem_ind_msg_v01_ei, - .decoded_size = sizeof(qmi_wlanfw_request_mem_ind_msg_v01_ei), + .decoded_size = sizeof(struct qmi_wlanfw_request_mem_ind_msg_v01), .fn = ath11k_qmi_msg_mem_request_cb, }, { .type = QMI_INDICATION, .msg_id = QMI_WLFW_FW_MEM_READY_IND_V01, .ei = qmi_wlanfw_mem_ready_ind_msg_v01_ei, - .decoded_size = sizeof(qmi_wlanfw_mem_ready_ind_msg_v01_ei), + .decoded_size = sizeof(struct qmi_wlanfw_fw_mem_ready_ind_msg_v01), .fn = ath11k_qmi_msg_mem_ready_cb, }, { .type = QMI_INDICATION, .msg_id = QMI_WLFW_FW_READY_IND_V01, .ei = qmi_wlanfw_fw_ready_ind_msg_v01_ei, - .decoded_size = sizeof(qmi_wlanfw_fw_ready_ind_msg_v01_ei), + .decoded_size = sizeof(struct qmi_wlanfw_fw_ready_ind_msg_v01), .fn = ath11k_qmi_msg_fw_ready_cb, }, { @@ -2499,7 +2499,7 @@ static const struct qmi_msg_handler ath11k_qmi_msg_handlers[] = { .msg_id = QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01, .ei = qmi_wlanfw_cold_boot_cal_done_ind_msg_v01_ei, .decoded_size = - sizeof(qmi_wlanfw_cold_boot_cal_done_ind_msg_v01_ei), + sizeof(struct qmi_wlanfw_fw_cold_cal_done_ind_msg_v01), .fn = ath11k_qmi_msg_cold_boot_cal_done_cb, }, }; diff --git a/drivers/net/wireless/ath/ath11k/qmi.h b/drivers/net/wireless/ath/ath11k/qmi.h index d55ce6cf7222..60e904683165 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.h +++ b/drivers/net/wireless/ath/ath11k/qmi.h @@ -267,6 +267,14 @@ struct qmi_wlanfw_fw_mem_ready_ind_msg_v01 { char placeholder; }; +struct qmi_wlanfw_fw_ready_ind_msg_v01 { + char placeholder; +}; + +struct qmi_wlanfw_fw_cold_cal_done_ind_msg_v01 { + char placeholder; +}; + #define QMI_WLANFW_CAP_REQ_MSG_V01_MAX_LEN 0 #define QMI_WLANFW_CAP_RESP_MSG_V01_MAX_LEN 207 #define QMI_WLANFW_CAP_REQ_V01 0x0024 -- cgit v1.2.3 From 6c809d04c542e24508c26102e6c7c5e2c967032d Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Fri, 14 Aug 2020 10:10:28 +0300 Subject: ath11k: fix KASAN warning of ath11k_qmi_wlanfw_wlan_cfg_send It's caused by reading memory out of boundary from target_ce_config_wlan. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597389030-13887-10-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/qmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index 529886b1f068..12991a835b8b 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -2233,7 +2233,7 @@ static int ath11k_qmi_wlanfw_wlan_cfg_send(struct ath11k_base *ab) req->tgt_cfg_valid = 1; /* This is number of CE configs */ req->tgt_cfg_len = ab->qmi.ce_cfg.tgt_ce_len; - for (pipe_num = 0; pipe_num <= req->tgt_cfg_len ; pipe_num++) { + for (pipe_num = 0; pipe_num < req->tgt_cfg_len ; pipe_num++) { req->tgt_cfg[pipe_num].pipe_num = ce_cfg[pipe_num].pipenum; req->tgt_cfg[pipe_num].pipe_dir = ce_cfg[pipe_num].pipedir; req->tgt_cfg[pipe_num].nentries = ce_cfg[pipe_num].nentries; -- cgit v1.2.3 From 727fae1478a5e7c65efa171a9639555da6ffa62a Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Fri, 14 Aug 2020 10:10:29 +0300 Subject: ath11k: enable internal sleep clock On x86 and other non-qcom platforms, host needs to explicitly tell the firmware to use the internal sleep clock. Some QCA6390 modules have OTP burnt with external sleep clock selected, and these modules can't work expectedly unless firmware selects internal sleep clock. Add a field to hw_params to support this difference. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597389030-13887-11-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/core.c | 2 ++ drivers/net/wireless/ath/ath11k/hw.h | 2 ++ drivers/net/wireless/ath/ath11k/qmi.c | 17 +++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index a3a53debc24f..f1c07583836f 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -31,6 +31,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .bdf_addr = 0x4B0C0000, .hw_ops = &ipq8074_ops, .ring_mask = &ath11k_hw_ring_mask_ipq8074, + .internal_sleep_clock = false, }, { .name = "qca6390 hw2.0", @@ -44,6 +45,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .bdf_addr = 0x4B0C0000, .hw_ops = &qca6390_ops, .ring_mask = &ath11k_hw_ring_mask_ipq8074, + .internal_sleep_clock = true, }, }; diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 5b443a212c85..aacd092dbddb 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -133,6 +133,8 @@ struct ath11k_hw_params { const struct ath11k_hw_ops *hw_ops; const struct ath11k_hw_ring_mask *ring_mask; + + bool internal_sleep_clock; }; extern const struct ath11k_hw_ops ipq8074_ops; diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index 12991a835b8b..b81897131f0a 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -9,6 +9,9 @@ #include #include +#define SLEEP_CLOCK_SELECT_INTERNAL_BIT 0x02 +#define HOST_CSTATE_BIT 0x04 + static struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, @@ -1531,6 +1534,20 @@ static int ath11k_qmi_host_cap_send(struct ath11k_base *ab) req.cal_done_valid = 1; req.cal_done = ab->qmi.cal_done; + if (ab->hw_params.internal_sleep_clock) { + req.nm_modem_valid = 1; + + /* Notify firmware that this is non-qualcomm platform. */ + req.nm_modem |= HOST_CSTATE_BIT; + + /* Notify firmware about the sleep clock selection, + * nm_modem_bit[1] is used for this purpose. Host driver on + * non-qualcomm platforms should select internal sleep + * clock. + */ + req.nm_modem |= SLEEP_CLOCK_SELECT_INTERNAL_BIT; + } + ret = qmi_txn_init(&ab->qmi.handle, &txn, qmi_wlanfw_host_cap_resp_msg_v01_ei, &resp); if (ret < 0) -- cgit v1.2.3 From f7eb4b04ce6f81f945bd71288f8e9fc4f284c169 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 14 Aug 2020 10:10:30 +0300 Subject: ath11k: hal: create hw_srng_config dynamically On QCA6390 reg_start and reg_size values are different from IPQ8074 so we need to change the values runtime. As we can't modify a static const variable hw_srng_config directly, instead use it as a template, copy it and modify the copy with correct values. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597389030-13887-12-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/dbring.c | 2 +- drivers/net/wireless/ath/ath11k/dp.c | 8 +-- drivers/net/wireless/ath/ath11k/dp_rx.c | 4 +- drivers/net/wireless/ath/ath11k/dp_tx.c | 2 +- drivers/net/wireless/ath/ath11k/hal.c | 119 +++++++++++++++++-------------- drivers/net/wireless/ath/ath11k/hal.h | 6 +- drivers/net/wireless/ath/ath11k/hal_rx.c | 2 +- drivers/net/wireless/ath/ath11k/hal_tx.c | 2 +- 8 files changed, 79 insertions(+), 66 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/dbring.c b/drivers/net/wireless/ath/ath11k/dbring.c index cf20db370123..5e1f5437b418 100644 --- a/drivers/net/wireless/ath/ath11k/dbring.c +++ b/drivers/net/wireless/ath/ath11k/dbring.c @@ -168,7 +168,7 @@ int ath11k_dbring_buf_setup(struct ath11k *ar, srng = &ab->hal.srng_list[ring->refill_srng.ring_id]; ring->bufs_max = ring->refill_srng.size / - ath11k_hal_srng_get_entrysize(HAL_RXDMA_DIR_BUF); + ath11k_hal_srng_get_entrysize(ab, HAL_RXDMA_DIR_BUF); ring->buf_sz = db_cap->min_buf_sz; ring->buf_align = db_cap->min_buf_align; diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index d6a2fd5e641c..a3c4d36f850d 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -112,8 +112,8 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, int mac_id, int num_entries) { struct hal_srng_params params = { 0 }; - int entry_sz = ath11k_hal_srng_get_entrysize(type); - int max_entries = ath11k_hal_srng_get_max_entries(type); + int entry_sz = ath11k_hal_srng_get_entrysize(ab, type); + int max_entries = ath11k_hal_srng_get_max_entries(ab, type); int ret; if (max_entries < 0 || entry_sz < 0) @@ -368,7 +368,7 @@ static int ath11k_dp_scatter_idle_link_desc_setup(struct ath11k_base *ab, u32 end_offset; n_entries_per_buf = HAL_WBM_IDLE_SCATTER_BUF_SIZE / - ath11k_hal_srng_get_entrysize(HAL_WBM_IDLE_LINK); + ath11k_hal_srng_get_entrysize(ab, HAL_WBM_IDLE_LINK); num_scatter_buf = DIV_ROUND_UP(size, HAL_WBM_IDLE_SCATTER_BUF_SIZE); if (num_scatter_buf > DP_IDLE_SCATTER_BUFS_MAX) @@ -566,7 +566,7 @@ int ath11k_dp_link_desc_setup(struct ath11k_base *ab, return ret; /* Setup link desc idle list for HW internal usage */ - entry_sz = ath11k_hal_srng_get_entrysize(ring_type); + entry_sz = ath11k_hal_srng_get_entrysize(ab, ring_type); tot_mem_sz = entry_sz * n_link_desc; /* Setup scatter desc list when the total memory requirement is more */ diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 5680b99a4f5c..66002de04aec 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -416,7 +416,7 @@ static int ath11k_dp_rxdma_ring_buf_setup(struct ath11k *ar, int num_entries; num_entries = rx_ring->refill_buf_ring.size / - ath11k_hal_srng_get_entrysize(ringtype); + ath11k_hal_srng_get_entrysize(ar->ab, ringtype); rx_ring->bufs_max = num_entries; ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, rx_ring, num_entries, @@ -4834,7 +4834,7 @@ int ath11k_dp_rx_pdev_mon_attach(struct ath11k *ar) dp_srng = &dp->rxdma_mon_desc_ring; n_link_desc = dp_srng->size / - ath11k_hal_srng_get_entrysize(HAL_RXDMA_MONITOR_DESC); + ath11k_hal_srng_get_entrysize(ar->ab, HAL_RXDMA_MONITOR_DESC); mon_desc_srng = &ar->ab->hal.srng_list[dp->rxdma_mon_desc_ring.ring_id]; diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index 1af76775b1a8..b83b5176a5df 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -720,7 +720,7 @@ int ath11k_dp_tx_htt_srng_setup(struct ath11k_base *ab, u32 ring_id, cmd->ring_base_addr_hi = (u64)params.ring_base_paddr >> HAL_ADDR_MSB_REG_SHIFT; - ret = ath11k_hal_srng_get_entrysize(ring_type); + ret = ath11k_hal_srng_get_entrysize(ab, ring_type); if (ret < 0) goto err_free; diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index fe4df2b4a2cc..25f2270be195 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -8,7 +8,7 @@ #include "hal_desc.h" #include "hif.h" -static const struct hal_srng_config hw_srng_config[] = { +static const struct hal_srng_config hw_srng_config_template[] = { /* TODO: max_rings can populated by querying HW capabilities */ { /* REO_DST */ .start_ring_id = HAL_SRNG_RING_ID_REO2SW1, @@ -16,14 +16,6 @@ static const struct hal_srng_config hw_srng_config[] = { .entry_size = sizeof(struct hal_reo_dest_ring) >> 2, .lmac_ring = false, .ring_dir = HAL_SRNG_DIR_DST, - .reg_start = { - HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_BASE_LSB, - HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_HP, - }, - .reg_size = { - HAL_REO2_RING_BASE_LSB - HAL_REO1_RING_BASE_LSB, - HAL_REO2_RING_HP - HAL_REO1_RING_HP, - }, .max_size = HAL_REO_REO2SW1_RING_BASE_MSB_RING_SIZE, }, { /* REO_EXCEPTION */ @@ -36,10 +28,6 @@ static const struct hal_srng_config hw_srng_config[] = { .entry_size = sizeof(struct hal_reo_dest_ring) >> 2, .lmac_ring = false, .ring_dir = HAL_SRNG_DIR_DST, - .reg_start = { - HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_TCL_RING_BASE_LSB, - HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_TCL_RING_HP, - }, .max_size = HAL_REO_REO2TCL_RING_BASE_MSB_RING_SIZE, }, { /* REO_REINJECT */ @@ -48,10 +36,6 @@ static const struct hal_srng_config hw_srng_config[] = { .entry_size = sizeof(struct hal_reo_entrance_ring) >> 2, .lmac_ring = false, .ring_dir = HAL_SRNG_DIR_SRC, - .reg_start = { - HAL_SEQ_WCSS_UMAC_REO_REG + HAL_SW2REO_RING_BASE_LSB, - HAL_SEQ_WCSS_UMAC_REO_REG + HAL_SW2REO_RING_HP, - }, .max_size = HAL_REO_SW2REO_RING_BASE_MSB_RING_SIZE, }, { /* REO_CMD */ @@ -61,10 +45,6 @@ static const struct hal_srng_config hw_srng_config[] = { sizeof(struct hal_reo_get_queue_stats)) >> 2, .lmac_ring = false, .ring_dir = HAL_SRNG_DIR_SRC, - .reg_start = { - HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_CMD_RING_BASE_LSB, - HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_CMD_HP, - }, .max_size = HAL_REO_CMD_RING_BASE_MSB_RING_SIZE, }, { /* REO_STATUS */ @@ -74,11 +54,6 @@ static const struct hal_srng_config hw_srng_config[] = { sizeof(struct hal_reo_get_queue_stats_status)) >> 2, .lmac_ring = false, .ring_dir = HAL_SRNG_DIR_DST, - .reg_start = { - HAL_SEQ_WCSS_UMAC_REO_REG + - HAL_REO_STATUS_RING_BASE_LSB, - HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_STATUS_HP, - }, .max_size = HAL_REO_STATUS_RING_BASE_MSB_RING_SIZE, }, { /* TCL_DATA */ @@ -88,14 +63,6 @@ static const struct hal_srng_config hw_srng_config[] = { sizeof(struct hal_tcl_data_cmd)) >> 2, .lmac_ring = false, .ring_dir = HAL_SRNG_DIR_SRC, - .reg_start = { - HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_BASE_LSB, - HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_HP, - }, - .reg_size = { - HAL_TCL2_RING_BASE_LSB - HAL_TCL1_RING_BASE_LSB, - HAL_TCL2_RING_HP - HAL_TCL1_RING_HP, - }, .max_size = HAL_SW2TCL1_RING_BASE_MSB_RING_SIZE, }, { /* TCL_CMD */ @@ -105,10 +72,6 @@ static const struct hal_srng_config hw_srng_config[] = { sizeof(struct hal_tcl_gse_cmd)) >> 2, .lmac_ring = false, .ring_dir = HAL_SRNG_DIR_SRC, - .reg_start = { - HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_RING_BASE_LSB, - HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_RING_HP, - }, .max_size = HAL_SW2TCL1_CMD_RING_BASE_MSB_RING_SIZE, }, { /* TCL_STATUS */ @@ -118,11 +81,6 @@ static const struct hal_srng_config hw_srng_config[] = { sizeof(struct hal_tcl_status_ring)) >> 2, .lmac_ring = false, .ring_dir = HAL_SRNG_DIR_DST, - .reg_start = { - HAL_SEQ_WCSS_UMAC_TCL_REG + - HAL_TCL_STATUS_RING_BASE_LSB, - HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_HP, - }, .max_size = HAL_TCL_STATUS_RING_BASE_MSB_RING_SIZE, }, { /* CE_SRC */ @@ -344,7 +302,7 @@ static void ath11k_hal_free_cont_wrp(struct ath11k_base *ab) static void ath11k_hal_ce_dst_setup(struct ath11k_base *ab, struct hal_srng *srng, int ring_num) { - const struct hal_srng_config *srng_config = &hw_srng_config[HAL_CE_DST]; + struct hal_srng_config *srng_config = &ab->hal.srng_config[HAL_CE_DST]; u32 addr; u32 val; @@ -550,7 +508,7 @@ static int ath11k_hal_srng_get_ring_id(struct ath11k_base *ab, enum hal_ring_type type, int ring_num, int mac_id) { - const struct hal_srng_config *srng_config = &hw_srng_config[type]; + struct hal_srng_config *srng_config = &ab->hal.srng_config[type]; int ring_id; if (ring_num >= srng_config->max_rings) { @@ -568,26 +526,26 @@ static int ath11k_hal_srng_get_ring_id(struct ath11k_base *ab, return ring_id; } -int ath11k_hal_srng_get_entrysize(u32 ring_type) +int ath11k_hal_srng_get_entrysize(struct ath11k_base *ab, u32 ring_type) { - const struct hal_srng_config *srng_config; + struct hal_srng_config *srng_config; if (WARN_ON(ring_type >= HAL_MAX_RING_TYPES)) return -EINVAL; - srng_config = &hw_srng_config[ring_type]; + srng_config = &ab->hal.srng_config[ring_type]; return (srng_config->entry_size << 2); } -int ath11k_hal_srng_get_max_entries(u32 ring_type) +int ath11k_hal_srng_get_max_entries(struct ath11k_base *ab, u32 ring_type) { - const struct hal_srng_config *srng_config; + struct hal_srng_config *srng_config; if (WARN_ON(ring_type >= HAL_MAX_RING_TYPES)) return -EINVAL; - srng_config = &hw_srng_config[ring_type]; + srng_config = &ab->hal.srng_config[ring_type]; return (srng_config->max_size / srng_config->entry_size); } @@ -1003,7 +961,7 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type, struct hal_srng_params *params) { struct ath11k_hal *hal = &ab->hal; - const struct hal_srng_config *srng_config = &hw_srng_config[type]; + struct hal_srng_config *srng_config = &ab->hal.srng_config[type]; struct hal_srng *srng; int ring_id; u32 lmac_idx; @@ -1102,6 +1060,56 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type, return ring_id; } +static int ath11k_hal_srng_create_config(struct ath11k_base *ab) +{ + struct ath11k_hal *hal = &ab->hal; + struct hal_srng_config *s; + + hal->srng_config = kmemdup(hw_srng_config_template, + sizeof(hw_srng_config_template), + GFP_KERNEL); + if (!hal->srng_config) + return -ENOMEM; + + s = &hal->srng_config[HAL_REO_DST]; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_BASE_LSB; + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_HP; + s->reg_size[0] = HAL_REO2_RING_BASE_LSB - HAL_REO1_RING_BASE_LSB; + s->reg_size[1] = HAL_REO2_RING_HP - HAL_REO1_RING_HP; + + s = &hal->srng_config[HAL_REO_EXCEPTION]; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_TCL_RING_BASE_LSB; + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_TCL_RING_HP; + + s = &hal->srng_config[HAL_REO_REINJECT]; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_SW2REO_RING_BASE_LSB; + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_SW2REO_RING_HP; + + s = &hal->srng_config[HAL_REO_CMD]; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_CMD_RING_BASE_LSB; + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_CMD_HP; + + s = &hal->srng_config[HAL_REO_STATUS]; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_STATUS_RING_BASE_LSB; + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_STATUS_HP; + + s = &hal->srng_config[HAL_TCL_DATA]; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_BASE_LSB; + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_HP; + s->reg_size[0] = HAL_TCL2_RING_BASE_LSB - HAL_TCL1_RING_BASE_LSB; + s->reg_size[1] = HAL_TCL2_RING_HP - HAL_TCL1_RING_HP; + + s = &hal->srng_config[HAL_TCL_CMD]; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_RING_BASE_LSB; + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_RING_HP; + + s = &hal->srng_config[HAL_TCL_STATUS]; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_BASE_LSB; + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_HP; + + return 0; +} + int ath11k_hal_srng_init(struct ath11k_base *ab) { struct ath11k_hal *hal = &ab->hal; @@ -1109,7 +1117,9 @@ int ath11k_hal_srng_init(struct ath11k_base *ab) memset(hal, 0, sizeof(*hal)); - hal->srng_config = hw_srng_config; + ret = ath11k_hal_srng_create_config(ab); + if (ret) + goto err_hal; ret = ath11k_hal_alloc_cont_rdp(ab); if (ret) @@ -1131,8 +1141,11 @@ EXPORT_SYMBOL(ath11k_hal_srng_init); void ath11k_hal_srng_deinit(struct ath11k_base *ab) { + struct ath11k_hal *hal = &ab->hal; + ath11k_hal_free_cont_rdp(ab); ath11k_hal_free_cont_wrp(ab); + kfree(hal->srng_config); } EXPORT_SYMBOL(ath11k_hal_srng_deinit); diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h index 6d9a6938870c..40c51d80430c 100644 --- a/drivers/net/wireless/ath/ath11k/hal.h +++ b/drivers/net/wireless/ath/ath11k/hal.h @@ -841,7 +841,7 @@ struct ath11k_hal { struct hal_srng srng_list[HAL_SRNG_RING_ID_MAX]; /* SRNG configuration table */ - const struct hal_srng_config *srng_config; + struct hal_srng_config *srng_config; /* Remote pointer memory for HW/FW updates */ struct { @@ -887,8 +887,8 @@ void ath11k_hal_ce_src_set_desc(void *buf, dma_addr_t paddr, u32 len, u32 id, u8 byte_swap_data); void ath11k_hal_ce_dst_set_desc(void *buf, dma_addr_t paddr); u32 ath11k_hal_ce_dst_status_get_length(void *buf); -int ath11k_hal_srng_get_entrysize(u32 ring_type); -int ath11k_hal_srng_get_max_entries(u32 ring_type); +int ath11k_hal_srng_get_entrysize(struct ath11k_base *ab, u32 ring_type); +int ath11k_hal_srng_get_max_entries(struct ath11k_base *ab, u32 ring_type); void ath11k_hal_srng_get_params(struct ath11k_base *ab, struct hal_srng *srng, struct hal_srng_params *params); u32 *ath11k_hal_srng_dst_get_next_entry(struct ath11k_base *ab, diff --git a/drivers/net/wireless/ath/ath11k/hal_rx.c b/drivers/net/wireless/ath/ath11k/hal_rx.c index 129c9e1efeb9..b30f1931313d 100644 --- a/drivers/net/wireless/ath/ath11k/hal_rx.c +++ b/drivers/net/wireless/ath/ath11k/hal_rx.c @@ -786,7 +786,7 @@ void ath11k_hal_reo_init_cmd_ring(struct ath11k_base *ab, memset(¶ms, 0, sizeof(params)); - entry_size = ath11k_hal_srng_get_entrysize(HAL_REO_CMD); + entry_size = ath11k_hal_srng_get_entrysize(ab, HAL_REO_CMD); ath11k_hal_srng_get_params(ab, srng, ¶ms); entry = (u8 *)params.ring_base_vaddr; diff --git a/drivers/net/wireless/ath/ath11k/hal_tx.c b/drivers/net/wireless/ath/ath11k/hal_tx.c index 81937c29ffca..a755aa86c5de 100644 --- a/drivers/net/wireless/ath/ath11k/hal_tx.c +++ b/drivers/net/wireless/ath/ath11k/hal_tx.c @@ -141,7 +141,7 @@ void ath11k_hal_tx_init_data_ring(struct ath11k_base *ab, struct hal_srng *srng) memset(¶ms, 0, sizeof(params)); - entry_size = ath11k_hal_srng_get_entrysize(HAL_TCL_DATA); + entry_size = ath11k_hal_srng_get_entrysize(ab, HAL_TCL_DATA); ath11k_hal_srng_get_params(ab, srng, ¶ms); desc = (u8 *)params.ring_base_vaddr; -- cgit v1.2.3 From 273411d5bcd01acdd6eda5fe45fb10f9f4a3deaa Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 27 Jul 2020 14:49:30 -0500 Subject: ath5k: Use fallthrough pseudo-keyword Replace the existing /* fall through */ comments and its variants with the new pseudo-keyword macro fallthrough[1]. [1] https://www.kernel.org/doc/html/v5.7/process/deprecated.html?highlight=fallthrough#implicit-switch-case-fall-through Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200727194930.GA1491@embeddedor --- drivers/net/wireless/ath/ath5k/eeprom.c | 4 ++-- drivers/net/wireless/ath/ath5k/pcu.c | 4 ++-- drivers/net/wireless/ath/ath5k/phy.c | 6 +++--- drivers/net/wireless/ath/ath5k/reset.c | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index 307f1fea0a88..1fbc2c19848f 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -1172,13 +1172,13 @@ ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode) offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11B) + AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; - /* fall through */ + fallthrough; case AR5K_EEPROM_MODE_11B: if (AR5K_EEPROM_HDR_11A(ee->ee_header)) offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11A) + AR5K_EEPROM_N_5GHZ_CHAN / 2; - /* fall through */ + fallthrough; case AR5K_EEPROM_MODE_11A: break; default: diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 05140d8baa36..7e9c3f0f8607 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -670,7 +670,7 @@ ath5k_hw_init_beacon_timers(struct ath5k_hw *ah, u32 next_beacon, u32 interval) break; case NL80211_IFTYPE_ADHOC: AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM); - /* fall through */ + fallthrough; default: /* On non-STA modes timer1 is used as next DMA * beacon alert (DBA) timer and timer2 as next @@ -913,7 +913,7 @@ ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE | (ah->ah_version == AR5K_AR5210 ? AR5K_STA_ID1_PWR_SV : 0); - /* fall through */ + fallthrough; case NL80211_IFTYPE_MONITOR: pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE | (ah->ah_version == AR5K_AR5210 ? diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index ae08572c4b58..00f9e347d414 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -3229,10 +3229,10 @@ ath5k_write_pwr_to_pdadc_table(struct ath5k_hw *ah, u8 ee_mode) switch (pdcurves) { case 3: reg |= AR5K_REG_SM(pdg_to_idx[2], AR5K_PHY_TPC_RG1_PDGAIN_3); - /* Fall through */ + fallthrough; case 2: reg |= AR5K_REG_SM(pdg_to_idx[1], AR5K_PHY_TPC_RG1_PDGAIN_2); - /* Fall through */ + fallthrough; case 1: reg |= AR5K_REG_SM(pdg_to_idx[0], AR5K_PHY_TPC_RG1_PDGAIN_1); break; @@ -3353,7 +3353,7 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah, table_min[pdg] = table_max[pdg] - 126; } - /* Fall through */ + fallthrough; case AR5K_PWRTABLE_PWR_TO_PCDAC: case AR5K_PWRTABLE_PWR_TO_PDADC: diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 56d7925a0c2c..9fdb5283b39c 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -522,7 +522,7 @@ ath5k_hw_set_power_mode(struct ath5k_hw *ah, enum ath5k_power_mode mode, switch (mode) { case AR5K_PM_AUTO: staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA; - /* fallthrough */ + fallthrough; case AR5K_PM_NETWORK_SLEEP: if (set_chip) ath5k_hw_reg_write(ah, -- cgit v1.2.3 From 3a059c76f4eb8ff9cffc40eb591e9e3aca360666 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 14 Aug 2020 12:39:12 +0100 Subject: ath5k: pcu: Add a description for 'band' remove one for 'mode' Fixes the following W=1 kernel build warning(s): drivers/net/wireless/ath/ath5k/pcu.c:115: warning: Function parameter or member 'band' not described in 'ath5k_hw_get_frame_duration' drivers/net/wireless/ath/ath5k/pcu.c:955: warning: Excess function parameter 'mode' description in 'ath5k_hw_pcu_init' Cc: Jiri Slaby Cc: Nick Kossifidis Cc: Luis Chamberlain Cc: Kalle Valo Cc: "David S. Miller" Cc: Jakub Kicinski Cc: Reyk Floeter Cc: "W. S. Bell" Cc: Luis Rodriguez Cc: Pavel Roskin Cc: linux-wireless@vger.kernel.org Cc: netdev@vger.kernel.org Signed-off-by: Lee Jones Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200814113933.1903438-10-lee.jones@linaro.org --- drivers/net/wireless/ath/ath5k/pcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 7e9c3f0f8607..f2db7cf16566 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -101,6 +101,7 @@ static const unsigned int ack_rates_high[] = /** * ath5k_hw_get_frame_duration() - Get tx time of a frame * @ah: The &struct ath5k_hw + * @band: One of enum nl80211_band * @len: Frame's length in bytes * @rate: The @struct ieee80211_rate * @shortpre: Indicate short preample @@ -945,7 +946,6 @@ ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) * ath5k_hw_pcu_init() - Initialize PCU * @ah: The &struct ath5k_hw * @op_mode: One of enum nl80211_iftype - * @mode: One of enum ath5k_driver_mode * * This function is used to initialize PCU by setting current * operation mode and various other settings. -- cgit v1.2.3 From 691c7a4d4fd70f8a7b2b9057e0a72ddc06a30fdb Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 14 Aug 2020 12:39:16 +0100 Subject: wil6210: Demote non-kerneldoc headers to standard comment blocks No effort has been made to document any of the function parameters here. Fixes the following W=1 kernel build warning(s): drivers/net/wireless/ath/wil6210/cfg80211.c:1749: warning: Function parameter or member 'ies' not described in '_wil_cfg80211_find_ie' drivers/net/wireless/ath/wil6210/cfg80211.c:1749: warning: Function parameter or member 'ies_len' not described in '_wil_cfg80211_find_ie' drivers/net/wireless/ath/wil6210/cfg80211.c:1749: warning: Function parameter or member 'ie' not described in '_wil_cfg80211_find_ie' drivers/net/wireless/ath/wil6210/cfg80211.c:1749: warning: Function parameter or member 'ie_len' not described in '_wil_cfg80211_find_ie' drivers/net/wireless/ath/wil6210/cfg80211.c:1780: warning: Function parameter or member 'ies1' not described in '_wil_cfg80211_merge_extra_ies' drivers/net/wireless/ath/wil6210/cfg80211.c:1780: warning: Function parameter or member 'ies1_len' not described in '_wil_cfg80211_merge_extra_ies' drivers/net/wireless/ath/wil6210/cfg80211.c:1780: warning: Function parameter or member 'ies2' not described in '_wil_cfg80211_merge_extra_ies' drivers/net/wireless/ath/wil6210/cfg80211.c:1780: warning: Function parameter or member 'ies2_len' not described in '_wil_cfg80211_merge_extra_ies' drivers/net/wireless/ath/wil6210/cfg80211.c:1780: warning: Function parameter or member 'merged_ies' not described in '_wil_cfg80211_merge_extra_ies' drivers/net/wireless/ath/wil6210/cfg80211.c:1780: warning: Function parameter or member 'merged_len' not described in '_wil_cfg80211_merge_extra_ies' Cc: Maya Erez Cc: Kalle Valo Cc: "David S. Miller" Cc: Jakub Kicinski Cc: linux-wireless@vger.kernel.org Cc: wil6210@qti.qualcomm.com Cc: netdev@vger.kernel.org Signed-off-by: Lee Jones Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200814113933.1903438-14-lee.jones@linaro.org --- drivers/net/wireless/ath/wil6210/cfg80211.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 0851d2bede89..1c42410d68e1 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1739,7 +1739,7 @@ static int wil_cancel_remain_on_channel(struct wiphy *wiphy, return wil_p2p_cancel_listen(vif, cookie); } -/** +/* * find a specific IE in a list of IEs * return a pointer to the beginning of IE in the list * or NULL if not found @@ -1766,7 +1766,7 @@ static const u8 *_wil_cfg80211_find_ie(const u8 *ies, u16 ies_len, const u8 *ie, ies_len); } -/** +/* * merge the IEs in two lists into a single list. * do not include IEs from the second list which exist in the first list. * add only vendor specific IEs from second list to keep -- cgit v1.2.3 From 1d4f5c15cf65ef10c67558d8906af5f2b08021cb Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 14 Aug 2020 12:39:23 +0100 Subject: ath5k: Fix kerneldoc formatting issue Kerneldoc expects attributes/parameters to be in '@*.: ' format and gets confused if the variable does not follow the type/attribute definitions. Fixes the following W=1 kernel build warning(s): drivers/net/wireless/ath/ath5k/base.c:1111: warning: Function parameter or member 'ah' not described in 'ath5k_drain_tx_buffs' Cc: Jiri Slaby Cc: Nick Kossifidis Cc: Luis Chamberlain Cc: Kalle Valo Cc: "David S. Miller" Cc: Jakub Kicinski Cc: Alexei Starovoitov Cc: Daniel Borkmann Cc: Jesper Dangaard Brouer Cc: John Fastabend Cc: "Luis R. Rodriguez" Cc: linux-wireless@vger.kernel.org Cc: netdev@vger.kernel.org Cc: bpf@vger.kernel.org Signed-off-by: Lee Jones Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200814113933.1903438-21-lee.jones@linaro.org --- drivers/net/wireless/ath/ath5k/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 65a4c142640d..b70acefdc3fb 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1098,7 +1098,7 @@ err: /** * ath5k_drain_tx_buffs - Empty tx buffers * - * @ah The &struct ath5k_hw + * @ah: The &struct ath5k_hw * * Empty tx buffers from all queues in preparation * of a reset or during shutdown. -- cgit v1.2.3 From 8238bf0d4b67c8f91c4d85bebbfd8c03185e9ceb Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 27 Jul 2020 14:51:11 -0500 Subject: ath6kl: Use fallthrough pseudo-keyword Replace the existing /* fall through */ comments and its variants with the new pseudo-keyword macro fallthrough[1]. [1] https://www.kernel.org/doc/html/v5.7/process/deprecated.html?highlight=fallthrough#implicit-switch-case-fall-through Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200727195111.GA1603@embeddedor --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 6 +++--- drivers/net/wireless/ath/ath6kl/main.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 67f8f2aa7a53..9c83e9a4299b 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3897,19 +3897,19 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) switch (ar->hw.cap) { case WMI_11AN_CAP: ht = true; - /* fall through */ + fallthrough; case WMI_11A_CAP: band_5gig = true; break; case WMI_11GN_CAP: ht = true; - /* fall through */ + fallthrough; case WMI_11G_CAP: band_2gig = true; break; case WMI_11AGN_CAP: ht = true; - /* fall through */ + fallthrough; case WMI_11AG_CAP: band_2gig = true; band_5gig = true; diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 5e7ea838a921..210218298e13 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -389,7 +389,7 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel) if (!ik->valid || ik->key_type != WAPI_CRYPT) break; /* for WAPI, we need to set the delayed group key, continue: */ - /* fall through */ + fallthrough; case WPA_PSK_AUTH: case WPA2_PSK_AUTH: case (WPA_PSK_AUTH | WPA2_PSK_AUTH): -- cgit v1.2.3 From 42f5fe34a701769763c299c49a89595e60871dcf Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 6 Aug 2020 13:19:58 +0100 Subject: ath6kl: fix spelling mistake "initilisation" -> "initialization" There is a spelling mistake in an ath6kl_err error message. Fix it. Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200806121958.60700-1-colin.king@canonical.com --- drivers/net/wireless/ath/ath6kl/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index aa1c71a76ef7..3f5e7bde0f05 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1752,7 +1752,7 @@ static int __ath6kl_init_hw_start(struct ath6kl *ar) ret = ath6kl_init_service_ep(ar); if (ret) { - ath6kl_err("Endpoint service initilisation failed: %d\n", ret); + ath6kl_err("Endpoint service initialization failed: %d\n", ret); goto err_cleanup_scatter; } -- cgit v1.2.3 From 54f9ab7b870934b70e5a21786d951fbcf663970f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 13 Aug 2020 17:13:15 +0300 Subject: ath6kl: prevent potential array overflow in ath6kl_add_new_sta() The value for "aid" comes from skb->data so Smatch marks it as untrusted. If it's invalid then it can result in an out of bounds array access in ath6kl_add_new_sta(). Fixes: 572e27c00c9d ("ath6kl: Fix AP mode connect event parsing and TIM updates") Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200813141315.GB457408@mwanda --- drivers/net/wireless/ath/ath6kl/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 210218298e13..d3aa9e7a37c2 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -430,6 +430,9 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr, ath6kl_dbg(ATH6KL_DBG_TRC, "new station %pM aid=%d\n", mac_addr, aid); + if (aid < 1 || aid > AP_MAX_NUM_STA) + return; + if (assoc_req_len > sizeof(struct ieee80211_hdr_3addr)) { struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) assoc_info; -- cgit v1.2.3 From 4bad3a2041b5391678834f2611cbf7b7c66ca8f7 Mon Sep 17 00:00:00 2001 From: Alexander Wetzel Date: Tue, 4 Aug 2020 18:41:51 +0200 Subject: ath9k: add NL80211_EXT_FEATURE_CAN_REPLACE_PTK0 support The ath9k driver was so far only able to rekey PTK0 keys correctly due to the best effort queue flush added with commit 62872a9b9a10 ("mac80211: Fix PTK rekey freezes and clear text leak"). Add the needed queue flush and set NL80211_EXT_FEATURE_CAN_REPLACE_PTK0 to tell mac80211 that the driver can now rekey PTK0 keys correctly and no longer needs the best effort flush. Effectively this prevents mac80211 to warn when rekeying a PTK0 key only. Signed-off-by: Alexander Wetzel Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200804164152.175375-1-alexander@wetzel-home.de --- drivers/net/wireless/ath/ath9k/init.c | 1 + drivers/net/wireless/ath/ath9k/main.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 289a2444d534..ea1d17a265a7 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -1014,6 +1014,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); } int ath9k_init_device(u16 devid, struct ath_softc *sc, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 0ea3b80f664c..411eece01bb1 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -19,6 +19,9 @@ #include "ath9k.h" #include "btcoex.h" +static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop); + u8 ath9k_parse_mpdudensity(u8 mpdudensity) { /* @@ -1701,6 +1704,15 @@ static int ath9k_set_key(struct ieee80211_hw *hw, return -EOPNOTSUPP; } + /* There may be MPDUs queued for the outgoing PTK key. Flush queues to + * make sure these are not send unencrypted or with a wrong (new) key + */ + if (cmd == DISABLE_KEY && key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { + ieee80211_stop_queues(hw); + ath9k_flush(hw, vif, 0, true); + ieee80211_wake_queues(hw); + } + mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); ath_dbg(common, CONFIG, "Set HW Key %d\n", cmd); -- cgit v1.2.3 From 5024f21c159f8c1668f581fff37140741c0b1ba9 Mon Sep 17 00:00:00 2001 From: Masashi Honma Date: Sun, 9 Aug 2020 08:32:58 +0900 Subject: ath9k_htc: Use appropriate rs_datalen type kernel test robot says: drivers/net/wireless/ath/ath9k/htc_drv_txrx.c:987:20: sparse: warning: incorrect type in assignment (different base types) drivers/net/wireless/ath/ath9k/htc_drv_txrx.c:987:20: sparse: expected restricted __be16 [usertype] rs_datalen drivers/net/wireless/ath/ath9k/htc_drv_txrx.c:987:20: sparse: got unsigned short [usertype] drivers/net/wireless/ath/ath9k/htc_drv_txrx.c:988:13: sparse: warning: restricted __be16 degrades to integer drivers/net/wireless/ath/ath9k/htc_drv_txrx.c:1001:13: sparse: warning: restricted __be16 degrades to integer Indeed rs_datalen has host byte order, so modify it's own type. Reported-by: kernel test robot Fixes: cd486e627e67 ("ath9k_htc: Discard undersized packets") Signed-off-by: Masashi Honma Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200808233258.4596-1-masashi.honma@gmail.com --- drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index b353995bdd45..f4c2a8d83f50 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -974,7 +974,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, struct ath_htc_rx_status *rxstatus; struct ath_rx_status rx_stats; bool decrypt_error = false; - __be16 rs_datalen; + u16 rs_datalen; bool is_phyerr; if (skb->len < HTC_RX_FRAME_HEADER_SIZE) { -- cgit v1.2.3 From 2705cd7558e718a7240c64eb0afb2edad5f8c190 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 13 Aug 2020 17:12:53 +0300 Subject: ath9k: Fix potential out of bounds in ath9k_htc_txcompletion_cb() The value of "htc_hdr->endpoint_id" comes from skb->data so Smatch marks it as untrusted so we have to check it before using it as an array offset. This is similar to a bug that syzkaller found in commit e4ff08a4d727 ("ath9k: Fix use-after-free Write in ath9k_htc_rx_msg") so it is probably a real issue. Fixes: fb9987d0f748 ("ath9k_htc: Support for AR9271 chipset.") Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200813141253.GA457408@mwanda --- drivers/net/wireless/ath/ath9k/htc_hst.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index d2e062eaf561..510e61e97dbc 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -339,6 +339,8 @@ void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, if (skb) { htc_hdr = (struct htc_frame_hdr *) skb->data; + if (htc_hdr->endpoint_id >= ARRAY_SIZE(htc_handle->endpoint)) + goto ret; endpoint = &htc_handle->endpoint[htc_hdr->endpoint_id]; skb_pull(skb, sizeof(struct htc_frame_hdr)); -- cgit v1.2.3 From 1885c0f76dc023e249024074f0578203704fa73c Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 27 Jul 2020 14:38:21 -0500 Subject: ath10k: Use fallthrough pseudo-keyword Replace the existing /* fall through */ comments and its variants with the new pseudo-keyword macro fallthrough[1]. Also, remove unnecessary fall-through markings when it is the case. [1] https://www.kernel.org/doc/html/v5.7/process/deprecated.html?highlight=fallthrough#implicit-switch-case-fall-through Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200727193821.GA981@embeddedor --- drivers/net/wireless/ath/ath10k/core.c | 2 +- drivers/net/wireless/ath/ath10k/htt_rx.c | 2 +- drivers/net/wireless/ath/ath10k/htt_tx.c | 6 +++--- drivers/net/wireless/ath/ath10k/mac.c | 18 +++++++++--------- drivers/net/wireless/ath/ath10k/wow.c | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index c4f098c4431f..2f48086e323b 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2321,7 +2321,7 @@ static void ath10k_core_restart(struct work_struct *work) break; case ATH10K_STATE_RESTARTED: ar->state = ATH10K_STATE_WEDGED; - /* fall through */ + fallthrough; case ATH10K_STATE_WEDGED: ath10k_warn(ar, "device is wedged, will not restart\n"); break; diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 69ad4ca1a87c..136cbf001c5b 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -3025,7 +3025,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) ath10k_htt_rx_h_enqueue(ar, &amsdu, status); break; case -EAGAIN: - /* fall through */ + fallthrough; default: /* Should not happen. */ ath10k_warn(ar, "failed to extract amsdu: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index bbe869575855..1fc0a312ab58 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -1314,7 +1314,7 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm case ATH10K_HW_TXRX_RAW: case ATH10K_HW_TXRX_NATIVE_WIFI: flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; - /* fall through */ + fallthrough; case ATH10K_HW_TXRX_ETHERNET: flags0 |= SM(txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); break; @@ -1460,7 +1460,7 @@ static int ath10k_htt_tx_32(struct ath10k_htt *htt, case ATH10K_HW_TXRX_RAW: case ATH10K_HW_TXRX_NATIVE_WIFI: flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; - /* fall through */ + fallthrough; case ATH10K_HW_TXRX_ETHERNET: if (ar->hw_params.continuous_frag_desc) { ext_desc_t = htt->frag_desc.vaddr_desc_32; @@ -1662,7 +1662,7 @@ static int ath10k_htt_tx_64(struct ath10k_htt *htt, case ATH10K_HW_TXRX_RAW: case ATH10K_HW_TXRX_NATIVE_WIFI: flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; - /* fall through */ + fallthrough; case ATH10K_HW_TXRX_ETHERNET: if (ar->hw_params.continuous_frag_desc) { ext_desc_t = htt->frag_desc.vaddr_desc_64; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index de3922e98dd8..78e97ec7b047 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2473,17 +2473,17 @@ ath10k_peer_assoc_h_vht_limit(u16 tx_mcs_set, idx_limit = -1; switch (idx_limit) { - case 0: /* fall through */ - case 1: /* fall through */ - case 2: /* fall through */ - case 3: /* fall through */ - case 4: /* fall through */ - case 5: /* fall through */ - case 6: /* fall through */ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: default: /* see ath10k_mac_can_set_bitrate_mask() */ WARN_ON(1); - /* fall through */ + fallthrough; case -1: mcs = IEEE80211_VHT_MCS_NOT_SUPPORTED; break; @@ -4243,7 +4243,7 @@ void __ath10k_scan_finish(struct ath10k *ar) } else if (ar->scan.roc_notify) { ieee80211_remain_on_channel_expired(ar->hw); } - /* fall through */ + fallthrough; case ATH10K_SCAN_STARTING: ar->scan.state = ATH10K_SCAN_IDLE; ar->scan_channel = NULL; diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c index 8c26adddd034..7d65c115669f 100644 --- a/drivers/net/wireless/ath/ath10k/wow.c +++ b/drivers/net/wireless/ath/ath10k/wow.c @@ -275,7 +275,7 @@ static int ath10k_vif_wow_set_wakeups(struct ath10k_vif *arvif, switch (arvif->vdev_type) { case WMI_VDEV_TYPE_IBSS: __set_bit(WOW_BEACON_EVENT, &wow_mask); - /* fall through */ + fallthrough; case WMI_VDEV_TYPE_AP: __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask); __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask); -- cgit v1.2.3 From 454530a9950b5a26d4998908249564cedfc4babc Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 2 Aug 2020 14:22:27 +0200 Subject: ath10k: Fix the size used in a 'dma_free_coherent()' call in an error handling path Update the size used in 'dma_free_coherent()' in order to match the one used in the corresponding 'dma_alloc_coherent()'. Fixes: 1863008369ae ("ath10k: fix shadow register implementation for WCN3990") Signed-off-by: Christophe JAILLET Reviewed-by: Rakesh Pillai Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200802122227.678637-1-christophe.jaillet@wanadoo.fr --- drivers/net/wireless/ath/ath10k/ce.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index ffdd4b995f33..7be95c4a441f 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -1567,7 +1567,7 @@ ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id, ret = ath10k_ce_alloc_shadow_base(ar, src_ring, nentries); if (ret) { dma_free_coherent(ar->dev, - (nentries * sizeof(struct ce_desc_64) + + (nentries * sizeof(struct ce_desc) + CE_DESC_RING_ALIGN), src_ring->base_addr_owner_space_unaligned, base_addr); -- cgit v1.2.3 From 3b9fb6791e7113679b1eb472e6ce1659e80f5797 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Sun, 2 Aug 2020 01:48:24 +0100 Subject: wcn36xx: Fix reported 802.11n rx_highest rate wcn3660/wcn3680 Qualcomm's document "80-WL007-1 Rev. J" states that the highest rx rate for the WCN3660 and WCN3680 on MCS 7 is 150 Mbps not the 72 Mbps stated here. This patch fixes the data-rate declared in the 5GHz table. Fixes: 8e84c2582169 ("wcn36xx: mac80211 driver for Qualcomm WCN3660/WCN3680 hardware") Signed-off-by: Bryan O'Donoghue Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200802004824.1307124-1-bryan.odonoghue@linaro.org --- drivers/net/wireless/ath/wcn36xx/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index c19648f2d73a..868de9d4a14a 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -163,7 +163,7 @@ static struct ieee80211_supported_band wcn_band_5ghz = { .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, .mcs = { .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - .rx_highest = cpu_to_le16(72), + .rx_highest = cpu_to_le16(150), .tx_params = IEEE80211_HT_MCS_TX_DEFINED, } } -- cgit v1.2.3 From ad0dc0426468852a97067980879ca035fe138a6d Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 17 Aug 2020 13:31:40 +0300 Subject: ath10k: move enable_pll_clk call to ath10k_core_start() There's no reason to have call for enable_pll_clk in ath10k_bmi_start(), move it to ath10k_core_start() instead. This way it's possible to call ath10k_bmi_start() from sdio.c during firmware dump creation. And also the function call is more visible when it's in core.c. No functional changes, compile tested only. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597421745-4329-1-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath10k/bmi.c | 8 -------- drivers/net/wireless/ath/ath10k/core.c | 7 +++++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c index 5b6db6e66f65..8b9d537c8900 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.c +++ b/drivers/net/wireless/ath/ath10k/bmi.c @@ -12,17 +12,9 @@ void ath10k_bmi_start(struct ath10k *ar) { - int ret; - ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi start\n"); ar->bmi.done_sent = false; - - /* Enable hardware clock to speed up firmware download */ - if (ar->hw_params.hw_ops->enable_pll_clk) { - ret = ar->hw_params.hw_ops->enable_pll_clk(ar); - ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi enable pll ret %d\n", ret); - } } int ath10k_bmi_done(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 2f48086e323b..fe075b384a0b 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2615,6 +2615,13 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, ar->running_fw->fw_file.fw_features)) { ath10k_bmi_start(ar); + /* Enable hardware clock to speed up firmware download */ + if (ar->hw_params.hw_ops->enable_pll_clk) { + status = ar->hw_params.hw_ops->enable_pll_clk(ar); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot enable pll ret %d\n", + status); + } + if (ath10k_init_configure_target(ar)) { status = -EINVAL; goto err; -- cgit v1.2.3 From 6976433c4778027e7afa55edb7fed4dc74849530 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Mon, 17 Aug 2020 13:31:46 +0300 Subject: ath11k: hal: create register values dynamically QCA6390 has different register offset compared to IPQ8074, so need to attach the register offset dynamically based on hw_params. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597576599-8857-2-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/core.c | 2 + drivers/net/wireless/ath/ath11k/hal.h | 72 +++++++++++----------- drivers/net/wireless/ath/ath11k/hw.c | 105 +++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/hw.h | 49 +++++++++++++++ 4 files changed, 192 insertions(+), 36 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index f1c07583836f..613a8a6721ba 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -32,6 +32,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .hw_ops = &ipq8074_ops, .ring_mask = &ath11k_hw_ring_mask_ipq8074, .internal_sleep_clock = false, + .regs = &ipq8074_regs, }, { .name = "qca6390 hw2.0", @@ -46,6 +47,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .hw_ops = &qca6390_ops, .ring_mask = &ath11k_hw_ring_mask_ipq8074, .internal_sleep_clock = true, + .regs = &qca6390_regs, }, }; diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h index 40c51d80430c..f52fd61d685d 100644 --- a/drivers/net/wireless/ath/ath11k/hal.h +++ b/drivers/net/wireless/ath/ath11k/hal.h @@ -46,19 +46,19 @@ struct ath11k_base; /* SW2TCL(x) R0 ring configuration address */ #define HAL_TCL1_RING_CMN_CTRL_REG 0x00000014 #define HAL_TCL1_RING_DSCP_TID_MAP 0x0000002c -#define HAL_TCL1_RING_BASE_LSB 0x00000510 -#define HAL_TCL1_RING_BASE_MSB 0x00000514 -#define HAL_TCL1_RING_ID 0x00000518 -#define HAL_TCL1_RING_MISC 0x00000520 -#define HAL_TCL1_RING_TP_ADDR_LSB 0x0000052c -#define HAL_TCL1_RING_TP_ADDR_MSB 0x00000530 -#define HAL_TCL1_RING_CONSUMER_INT_SETUP_IX0 0x00000540 -#define HAL_TCL1_RING_CONSUMER_INT_SETUP_IX1 0x00000544 -#define HAL_TCL1_RING_MSI1_BASE_LSB 0x00000558 -#define HAL_TCL1_RING_MSI1_BASE_MSB 0x0000055c -#define HAL_TCL1_RING_MSI1_DATA 0x00000560 -#define HAL_TCL2_RING_BASE_LSB 0x00000568 -#define HAL_TCL_RING_BASE_LSB 0x00000618 +#define HAL_TCL1_RING_BASE_LSB ab->hw_params.regs->hal_tcl1_ring_base_lsb +#define HAL_TCL1_RING_BASE_MSB ab->hw_params.regs->hal_tcl1_ring_base_msb +#define HAL_TCL1_RING_ID ab->hw_params.regs->hal_tcl1_ring_id +#define HAL_TCL1_RING_MISC ab->hw_params.regs->hal_tcl1_ring_misc +#define HAL_TCL1_RING_TP_ADDR_LSB ab->hw_params.regs->hal_tcl1_ring_tp_addr_lsb +#define HAL_TCL1_RING_TP_ADDR_MSB ab->hw_params.regs->hal_tcl1_ring_tp_addr_msb +#define HAL_TCL1_RING_CONSUMER_INT_SETUP_IX0 ab->hw_params.regs->hal_tcl1_ring_consumer_int_setup_ix0 +#define HAL_TCL1_RING_CONSUMER_INT_SETUP_IX1 ab->hw_params.regs->hal_tcl1_ring_consumer_int_setup_ix1 +#define HAL_TCL1_RING_MSI1_BASE_LSB ab->hw_params.regs->hal_tcl1_ring_msi1_base_lsb +#define HAL_TCL1_RING_MSI1_BASE_MSB ab->hw_params.regs->hal_tcl1_ring_msi1_base_msb +#define HAL_TCL1_RING_MSI1_DATA ab->hw_params.regs->hal_tcl1_ring_msi1_data +#define HAL_TCL2_RING_BASE_LSB ab->hw_params.regs->hal_tcl2_ring_base_lsb +#define HAL_TCL_RING_BASE_LSB ab->hw_params.regs->hal_tcl_ring_base_lsb #define HAL_TCL1_RING_MSI1_BASE_LSB_OFFSET \ (HAL_TCL1_RING_MSI1_BASE_LSB - HAL_TCL1_RING_BASE_LSB) @@ -91,7 +91,7 @@ struct ath11k_base; (HAL_TCL1_RING_TP - HAL_TCL1_RING_HP) /* TCL STATUS ring address */ -#define HAL_TCL_STATUS_RING_BASE_LSB 0x00000720 +#define HAL_TCL_STATUS_RING_BASE_LSB ab->hw_params.regs->hal_tcl_status_ring_base_lsb #define HAL_TCL_STATUS_RING_HP 0x00002030 /* REO2SW(x) R0 ring configuration address */ @@ -100,21 +100,21 @@ struct ath11k_base; #define HAL_REO1_DEST_RING_CTRL_IX_1 0x00000008 #define HAL_REO1_DEST_RING_CTRL_IX_2 0x0000000c #define HAL_REO1_DEST_RING_CTRL_IX_3 0x00000010 -#define HAL_REO1_RING_BASE_LSB 0x0000029c -#define HAL_REO1_RING_BASE_MSB 0x000002a0 -#define HAL_REO1_RING_ID 0x000002a4 -#define HAL_REO1_RING_MISC 0x000002ac -#define HAL_REO1_RING_HP_ADDR_LSB 0x000002b0 -#define HAL_REO1_RING_HP_ADDR_MSB 0x000002b4 -#define HAL_REO1_RING_PRODUCER_INT_SETUP 0x000002c0 -#define HAL_REO1_RING_MSI1_BASE_LSB 0x000002e4 -#define HAL_REO1_RING_MSI1_BASE_MSB 0x000002e8 -#define HAL_REO1_RING_MSI1_DATA 0x000002ec -#define HAL_REO2_RING_BASE_LSB 0x000002f4 -#define HAL_REO1_AGING_THRESH_IX_0 0x00000564 -#define HAL_REO1_AGING_THRESH_IX_1 0x00000568 -#define HAL_REO1_AGING_THRESH_IX_2 0x0000056c -#define HAL_REO1_AGING_THRESH_IX_3 0x00000570 + #define HAL_REO1_RING_BASE_LSB ab->hw_params.regs->hal_reo1_ring_base_lsb +#define HAL_REO1_RING_BASE_MSB ab->hw_params.regs->hal_reo1_ring_base_msb +#define HAL_REO1_RING_ID ab->hw_params.regs->hal_reo1_ring_id +#define HAL_REO1_RING_MISC ab->hw_params.regs->hal_reo1_ring_misc +#define HAL_REO1_RING_HP_ADDR_LSB ab->hw_params.regs->hal_reo1_ring_hp_addr_lsb +#define HAL_REO1_RING_HP_ADDR_MSB ab->hw_params.regs->hal_reo1_ring_hp_addr_msb +#define HAL_REO1_RING_PRODUCER_INT_SETUP ab->hw_params.regs->hal_reo1_ring_producer_int_setup +#define HAL_REO1_RING_MSI1_BASE_LSB ab->hw_params.regs->hal_reo1_ring_msi1_base_lsb +#define HAL_REO1_RING_MSI1_BASE_MSB ab->hw_params.regs->hal_reo1_ring_msi1_base_msb +#define HAL_REO1_RING_MSI1_DATA ab->hw_params.regs->hal_reo1_ring_msi1_data +#define HAL_REO2_RING_BASE_LSB ab->hw_params.regs->hal_reo2_ring_base_lsb +#define HAL_REO1_AGING_THRESH_IX_0 ab->hw_params.regs->hal_reo1_aging_thresh_ix_0 +#define HAL_REO1_AGING_THRESH_IX_1 ab->hw_params.regs->hal_reo1_aging_thresh_ix_1 +#define HAL_REO1_AGING_THRESH_IX_2 ab->hw_params.regs->hal_reo1_aging_thresh_ix_2 +#define HAL_REO1_AGING_THRESH_IX_3 ab->hw_params.regs->hal_reo1_aging_thresh_ix_3 #define HAL_REO1_RING_MSI1_BASE_LSB_OFFSET \ (HAL_REO1_RING_MSI1_BASE_LSB - HAL_REO1_RING_BASE_LSB) @@ -134,17 +134,17 @@ struct ath11k_base; #define HAL_REO1_RING_MISC_OFFSET (HAL_REO1_RING_MISC - HAL_REO1_RING_BASE_LSB) /* REO2SW(x) R2 ring pointers (head/tail) address */ -#define HAL_REO1_RING_HP 0x00003038 -#define HAL_REO1_RING_TP 0x0000303c -#define HAL_REO2_RING_HP 0x00003040 +#define HAL_REO1_RING_HP ab->hw_params.regs->hal_reo1_ring_hp +#define HAL_REO1_RING_TP ab->hw_params.regs->hal_reo1_ring_tp +#define HAL_REO2_RING_HP ab->hw_params.regs->hal_reo2_ring_hp #define HAL_REO1_RING_TP_OFFSET (HAL_REO1_RING_TP - HAL_REO1_RING_HP) /* REO2TCL R0 ring configuration address */ -#define HAL_REO_TCL_RING_BASE_LSB 0x000003fc +#define HAL_REO_TCL_RING_BASE_LSB ab->hw_params.regs->hal_reo_tcl_ring_base_lsb /* REO2TCL R2 ring pointer (head/tail) address */ -#define HAL_REO_TCL_RING_HP 0x00003058 +#define HAL_REO_TCL_RING_HP ab->hw_params.regs->hal_reo_tcl_ring_hp /* REO CMD R0 address */ #define HAL_REO_CMD_RING_BASE_LSB 0x00000194 @@ -168,8 +168,8 @@ struct ath11k_base; #define HAL_CE_DST_STATUS_RING_HP 0x00000408 /* REO status address */ -#define HAL_REO_STATUS_RING_BASE_LSB 0x00000504 -#define HAL_REO_STATUS_HP 0x00003070 +#define HAL_REO_STATUS_RING_BASE_LSB ab->hw_params.regs->hal_reo_status_ring_base_lsb +#define HAL_REO_STATUS_HP ab->hw_params.regs->hal_reo_status_hp /* WBM Idle R0 address */ #define HAL_WBM_IDLE_LINK_RING_BASE_LSB 0x00000860 diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index f7354476d673..51ddd418bc3b 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -3,6 +3,11 @@ * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. */ +#include +#include +#include + +#include "hw.h" #include "core.h" /* Map from pdev index to hw mac index */ @@ -104,3 +109,103 @@ const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq8074 = { }, }; +const struct ath11k_hw_regs ipq8074_regs = { + /* SW2TCL(x) R0 ring configuration address */ + .hal_tcl1_ring_base_lsb = 0x00000510, + .hal_tcl1_ring_base_msb = 0x00000514, + .hal_tcl1_ring_id = 0x00000518, + .hal_tcl1_ring_misc = 0x00000520, + .hal_tcl1_ring_tp_addr_lsb = 0x0000052c, + .hal_tcl1_ring_tp_addr_msb = 0x00000530, + .hal_tcl1_ring_consumer_int_setup_ix0 = 0x00000540, + .hal_tcl1_ring_consumer_int_setup_ix1 = 0x00000544, + .hal_tcl1_ring_msi1_base_lsb = 0x00000558, + .hal_tcl1_ring_msi1_base_msb = 0x0000055c, + .hal_tcl1_ring_msi1_data = 0x00000560, + .hal_tcl2_ring_base_lsb = 0x00000568, + .hal_tcl_ring_base_lsb = 0x00000618, + + /* TCL STATUS ring address */ + .hal_tcl_status_ring_base_lsb = 0x00000720, + + /* REO2SW(x) R0 ring configuration address */ + .hal_reo1_ring_base_lsb = 0x0000029c, + .hal_reo1_ring_base_msb = 0x000002a0, + .hal_reo1_ring_id = 0x000002a4, + .hal_reo1_ring_misc = 0x000002ac, + .hal_reo1_ring_hp_addr_lsb = 0x000002b0, + .hal_reo1_ring_hp_addr_msb = 0x000002b4, + .hal_reo1_ring_producer_int_setup = 0x000002c0, + .hal_reo1_ring_msi1_base_lsb = 0x000002e4, + .hal_reo1_ring_msi1_base_msb = 0x000002e8, + .hal_reo1_ring_msi1_data = 0x000002ec, + .hal_reo2_ring_base_lsb = 0x000002f4, + .hal_reo1_aging_thresh_ix_0 = 0x00000564, + .hal_reo1_aging_thresh_ix_1 = 0x00000568, + .hal_reo1_aging_thresh_ix_2 = 0x0000056c, + .hal_reo1_aging_thresh_ix_3 = 0x00000570, + + /* REO2SW(x) R2 ring pointers (head/tail) address */ + .hal_reo1_ring_hp = 0x00003038, + .hal_reo1_ring_tp = 0x0000303c, + .hal_reo2_ring_hp = 0x00003040, + + /* REO2TCL R0 ring configuration address */ + .hal_reo_tcl_ring_base_lsb = 0x000003fc, + .hal_reo_tcl_ring_hp = 0x00003058, + + /* REO status address */ + .hal_reo_status_ring_base_lsb = 0x00000504, + .hal_reo_status_hp = 0x00003070, + +}; + +const struct ath11k_hw_regs qca6390_regs = { + /* SW2TCL(x) R0 ring configuration address */ + .hal_tcl1_ring_base_lsb = 0x00000684, + .hal_tcl1_ring_base_msb = 0x00000688, + .hal_tcl1_ring_id = 0x0000068c, + .hal_tcl1_ring_misc = 0x00000694, + .hal_tcl1_ring_tp_addr_lsb = 0x000006a0, + .hal_tcl1_ring_tp_addr_msb = 0x000006a4, + .hal_tcl1_ring_consumer_int_setup_ix0 = 0x000006b4, + .hal_tcl1_ring_consumer_int_setup_ix1 = 0x000006b8, + .hal_tcl1_ring_msi1_base_lsb = 0x000006cc, + .hal_tcl1_ring_msi1_base_msb = 0x000006d0, + .hal_tcl1_ring_msi1_data = 0x000006d4, + .hal_tcl2_ring_base_lsb = 0x000006dc, + .hal_tcl_ring_base_lsb = 0x0000078c, + + /* TCL STATUS ring address */ + .hal_tcl_status_ring_base_lsb = 0x00000894, + + /* REO2SW(x) R0 ring configuration address */ + .hal_reo1_ring_base_lsb = 0x00000244, + .hal_reo1_ring_base_msb = 0x00000248, + .hal_reo1_ring_id = 0x0000024c, + .hal_reo1_ring_misc = 0x00000254, + .hal_reo1_ring_hp_addr_lsb = 0x00000258, + .hal_reo1_ring_hp_addr_msb = 0x0000025c, + .hal_reo1_ring_producer_int_setup = 0x00000268, + .hal_reo1_ring_msi1_base_lsb = 0x0000028c, + .hal_reo1_ring_msi1_base_msb = 0x00000290, + .hal_reo1_ring_msi1_data = 0x00000294, + .hal_reo2_ring_base_lsb = 0x0000029c, + .hal_reo1_aging_thresh_ix_0 = 0x0000050c, + .hal_reo1_aging_thresh_ix_1 = 0x00000510, + .hal_reo1_aging_thresh_ix_2 = 0x00000514, + .hal_reo1_aging_thresh_ix_3 = 0x00000518, + + /* REO2SW(x) R2 ring pointers (head/tail) address */ + .hal_reo1_ring_hp = 0x00003030, + .hal_reo1_ring_tp = 0x00003034, + .hal_reo2_ring_hp = 0x00003038, + + /* REO2TCL R0 ring configuration address */ + .hal_reo_tcl_ring_base_lsb = 0x000003a4, + .hal_reo_tcl_ring_hp = 0x00003050, + + /* REO status address */ + .hal_reo_status_ring_base_lsb = 0x000004ac, + .hal_reo_status_hp = 0x00003068, +}; diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index aacd092dbddb..eb1d8a2beffd 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -135,6 +135,8 @@ struct ath11k_hw_params { const struct ath11k_hw_ring_mask *ring_mask; bool internal_sleep_clock; + + const struct ath11k_hw_regs *regs; }; extern const struct ath11k_hw_ops ipq8074_ops; @@ -170,4 +172,51 @@ enum ath11k_bd_ie_type { ATH11K_BD_IE_BOARD_EXT = 1, }; +struct ath11k_hw_regs { + u32 hal_tcl1_ring_base_lsb; + u32 hal_tcl1_ring_base_msb; + u32 hal_tcl1_ring_id; + u32 hal_tcl1_ring_misc; + u32 hal_tcl1_ring_tp_addr_lsb; + u32 hal_tcl1_ring_tp_addr_msb; + u32 hal_tcl1_ring_consumer_int_setup_ix0; + u32 hal_tcl1_ring_consumer_int_setup_ix1; + u32 hal_tcl1_ring_msi1_base_lsb; + u32 hal_tcl1_ring_msi1_base_msb; + u32 hal_tcl1_ring_msi1_data; + u32 hal_tcl2_ring_base_lsb; + u32 hal_tcl_ring_base_lsb; + + u32 hal_tcl_status_ring_base_lsb; + + u32 hal_reo1_ring_base_lsb; + u32 hal_reo1_ring_base_msb; + u32 hal_reo1_ring_id; + u32 hal_reo1_ring_misc; + u32 hal_reo1_ring_hp_addr_lsb; + u32 hal_reo1_ring_hp_addr_msb; + u32 hal_reo1_ring_producer_int_setup; + u32 hal_reo1_ring_msi1_base_lsb; + u32 hal_reo1_ring_msi1_base_msb; + u32 hal_reo1_ring_msi1_data; + u32 hal_reo2_ring_base_lsb; + u32 hal_reo1_aging_thresh_ix_0; + u32 hal_reo1_aging_thresh_ix_1; + u32 hal_reo1_aging_thresh_ix_2; + u32 hal_reo1_aging_thresh_ix_3; + + u32 hal_reo1_ring_hp; + u32 hal_reo1_ring_tp; + u32 hal_reo2_ring_hp; + + u32 hal_reo_tcl_ring_base_lsb; + u32 hal_reo_tcl_ring_hp; + + u32 hal_reo_status_ring_base_lsb; + u32 hal_reo_status_hp; +}; + +extern const struct ath11k_hw_regs ipq8074_regs; +extern const struct ath11k_hw_regs qca6390_regs; + #endif -- cgit v1.2.3 From 2b5e665bedf7a9ce64abf4cb55d2f1df4bb8d4f6 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 17 Aug 2020 13:31:47 +0300 Subject: ath11k: hal: cleanup dynamic register macros Now some of the HAL register macros access ab variable in a hidden way, make ab variable visible in the macro by adding it as an argument. This is done in a separate patch to keep the patches simple. No functional changes. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597576599-8857-3-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/hal.c | 66 ++++++------ drivers/net/wireless/ath/ath11k/hal.h | 171 +++++++++++++++++-------------- drivers/net/wireless/ath/ath11k/hal_rx.c | 8 +- 3 files changed, 133 insertions(+), 112 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index 25f2270be195..ae4dc6c39e64 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -329,7 +329,7 @@ static void ath11k_hal_srng_dst_hw_init(struct ath11k_base *ab, if (srng->flags & HAL_SRNG_FLAGS_MSI_INTR) { ath11k_hif_write32(ab, reg_base + - HAL_REO1_RING_MSI1_BASE_LSB_OFFSET, + HAL_REO1_RING_MSI1_BASE_LSB_OFFSET(ab), (u32)srng->msi_addr); val = FIELD_PREP(HAL_REO1_RING_MSI1_BASE_MSB_ADDR, @@ -337,10 +337,10 @@ static void ath11k_hal_srng_dst_hw_init(struct ath11k_base *ab, HAL_ADDR_MSB_REG_SHIFT)) | HAL_REO1_RING_MSI1_BASE_MSB_MSI1_ENABLE; ath11k_hif_write32(ab, reg_base + - HAL_REO1_RING_MSI1_BASE_MSB_OFFSET, val); + HAL_REO1_RING_MSI1_BASE_MSB_OFFSET(ab), val); ath11k_hif_write32(ab, - reg_base + HAL_REO1_RING_MSI1_DATA_OFFSET, + reg_base + HAL_REO1_RING_MSI1_DATA_OFFSET(ab), srng->msi_data); } @@ -351,11 +351,11 @@ static void ath11k_hal_srng_dst_hw_init(struct ath11k_base *ab, HAL_ADDR_MSB_REG_SHIFT)) | FIELD_PREP(HAL_REO1_RING_BASE_MSB_RING_SIZE, (srng->entry_size * srng->num_entries)); - ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_BASE_MSB_OFFSET, val); + ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_BASE_MSB_OFFSET(ab), val); val = FIELD_PREP(HAL_REO1_RING_ID_RING_ID, srng->ring_id) | FIELD_PREP(HAL_REO1_RING_ID_ENTRY_SIZE, srng->entry_size); - ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_ID_OFFSET, val); + ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_ID_OFFSET(ab), val); /* interrupt setup */ val = FIELD_PREP(HAL_REO1_RING_PRDR_INT_SETUP_INTR_TMR_THOLD, @@ -366,21 +366,21 @@ static void ath11k_hal_srng_dst_hw_init(struct ath11k_base *ab, srng->entry_size)); ath11k_hif_write32(ab, - reg_base + HAL_REO1_RING_PRODUCER_INT_SETUP_OFFSET, + reg_base + HAL_REO1_RING_PRODUCER_INT_SETUP_OFFSET(ab), val); hp_addr = hal->rdp.paddr + ((unsigned long)srng->u.dst_ring.hp_addr - (unsigned long)hal->rdp.vaddr); - ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_HP_ADDR_LSB_OFFSET, + ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_HP_ADDR_LSB_OFFSET(ab), hp_addr & HAL_ADDR_LSB_REG_MASK); - ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_HP_ADDR_MSB_OFFSET, + ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_HP_ADDR_MSB_OFFSET(ab), hp_addr >> HAL_ADDR_MSB_REG_SHIFT); /* Initialize head and tail pointers to indicate ring is empty */ reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R2]; ath11k_hif_write32(ab, reg_base, 0); - ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_TP_OFFSET, 0); + ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_TP_OFFSET(ab), 0); *srng->u.dst_ring.hp_addr = 0; reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R0]; @@ -393,7 +393,7 @@ static void ath11k_hal_srng_dst_hw_init(struct ath11k_base *ab, val |= HAL_REO1_RING_MISC_MSI_SWAP; val |= HAL_REO1_RING_MISC_SRNG_ENABLE; - ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_MISC_OFFSET, val); + ath11k_hif_write32(ab, reg_base + HAL_REO1_RING_MISC_OFFSET(ab), val); } static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab, @@ -408,7 +408,7 @@ static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab, if (srng->flags & HAL_SRNG_FLAGS_MSI_INTR) { ath11k_hif_write32(ab, reg_base + - HAL_TCL1_RING_MSI1_BASE_LSB_OFFSET, + HAL_TCL1_RING_MSI1_BASE_LSB_OFFSET(ab), (u32)srng->msi_addr); val = FIELD_PREP(HAL_TCL1_RING_MSI1_BASE_MSB_ADDR, @@ -416,11 +416,11 @@ static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab, HAL_ADDR_MSB_REG_SHIFT)) | HAL_TCL1_RING_MSI1_BASE_MSB_MSI1_ENABLE; ath11k_hif_write32(ab, reg_base + - HAL_TCL1_RING_MSI1_BASE_MSB_OFFSET, + HAL_TCL1_RING_MSI1_BASE_MSB_OFFSET(ab), val); ath11k_hif_write32(ab, reg_base + - HAL_TCL1_RING_MSI1_DATA_OFFSET, + HAL_TCL1_RING_MSI1_DATA_OFFSET(ab), srng->msi_data); } @@ -431,10 +431,10 @@ static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab, HAL_ADDR_MSB_REG_SHIFT)) | FIELD_PREP(HAL_TCL1_RING_BASE_MSB_RING_SIZE, (srng->entry_size * srng->num_entries)); - ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_BASE_MSB_OFFSET, val); + ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_BASE_MSB_OFFSET(ab), val); val = FIELD_PREP(HAL_REO1_RING_ID_ENTRY_SIZE, srng->entry_size); - ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_ID_OFFSET, val); + ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_ID_OFFSET(ab), val); /* interrupt setup */ /* NOTE: IPQ8074 v2 requires the interrupt timer threshold in the @@ -448,7 +448,7 @@ static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab, srng->entry_size)); ath11k_hif_write32(ab, - reg_base + HAL_TCL1_RING_CONSR_INT_SETUP_IX0_OFFSET, + reg_base + HAL_TCL1_RING_CONSR_INT_SETUP_IX0_OFFSET(ab), val); val = 0; @@ -457,7 +457,7 @@ static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab, srng->u.src_ring.low_threshold); } ath11k_hif_write32(ab, - reg_base + HAL_TCL1_RING_CONSR_INT_SETUP_IX1_OFFSET, + reg_base + HAL_TCL1_RING_CONSR_INT_SETUP_IX1_OFFSET(ab), val); if (srng->ring_id != HAL_SRNG_RING_ID_WBM_IDLE_LINK) { @@ -465,10 +465,10 @@ static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab, ((unsigned long)srng->u.src_ring.tp_addr - (unsigned long)hal->rdp.vaddr); ath11k_hif_write32(ab, - reg_base + HAL_TCL1_RING_TP_ADDR_LSB_OFFSET, + reg_base + HAL_TCL1_RING_TP_ADDR_LSB_OFFSET(ab), tp_addr & HAL_ADDR_LSB_REG_MASK); ath11k_hif_write32(ab, - reg_base + HAL_TCL1_RING_TP_ADDR_MSB_OFFSET, + reg_base + HAL_TCL1_RING_TP_ADDR_MSB_OFFSET(ab), tp_addr >> HAL_ADDR_MSB_REG_SHIFT); } @@ -492,7 +492,7 @@ static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab, val |= HAL_TCL1_RING_MISC_SRNG_ENABLE; - ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_MISC_OFFSET, val); + ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_MISC_OFFSET(ab), val); } static void ath11k_hal_srng_hw_init(struct ath11k_base *ab, @@ -1043,7 +1043,7 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type, } else { srng->u.dst_ring.tp_addr = (u32 *)((unsigned long)ab->mem + reg_base + - (HAL_REO1_RING_TP - HAL_REO1_RING_HP)); + (HAL_REO1_RING_TP(ab) - HAL_REO1_RING_HP(ab))); } } @@ -1072,14 +1072,14 @@ static int ath11k_hal_srng_create_config(struct ath11k_base *ab) return -ENOMEM; s = &hal->srng_config[HAL_REO_DST]; - s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_BASE_LSB; - s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_HP; - s->reg_size[0] = HAL_REO2_RING_BASE_LSB - HAL_REO1_RING_BASE_LSB; - s->reg_size[1] = HAL_REO2_RING_HP - HAL_REO1_RING_HP; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_BASE_LSB(ab); + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_HP(ab); + s->reg_size[0] = HAL_REO2_RING_BASE_LSB(ab) - HAL_REO1_RING_BASE_LSB(ab); + s->reg_size[1] = HAL_REO2_RING_HP(ab) - HAL_REO1_RING_HP(ab); s = &hal->srng_config[HAL_REO_EXCEPTION]; - s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_TCL_RING_BASE_LSB; - s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_TCL_RING_HP; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_TCL_RING_BASE_LSB(ab); + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_TCL_RING_HP(ab); s = &hal->srng_config[HAL_REO_REINJECT]; s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_SW2REO_RING_BASE_LSB; @@ -1090,21 +1090,21 @@ static int ath11k_hal_srng_create_config(struct ath11k_base *ab) s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_CMD_HP; s = &hal->srng_config[HAL_REO_STATUS]; - s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_STATUS_RING_BASE_LSB; - s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_STATUS_HP; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_STATUS_RING_BASE_LSB(ab); + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_STATUS_HP(ab); s = &hal->srng_config[HAL_TCL_DATA]; - s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_BASE_LSB; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_BASE_LSB(ab); s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_HP; - s->reg_size[0] = HAL_TCL2_RING_BASE_LSB - HAL_TCL1_RING_BASE_LSB; + s->reg_size[0] = HAL_TCL2_RING_BASE_LSB(ab) - HAL_TCL1_RING_BASE_LSB(ab); s->reg_size[1] = HAL_TCL2_RING_HP - HAL_TCL1_RING_HP; s = &hal->srng_config[HAL_TCL_CMD]; - s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_RING_BASE_LSB; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_RING_BASE_LSB(ab); s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_RING_HP; s = &hal->srng_config[HAL_TCL_STATUS]; - s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_BASE_LSB; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_BASE_LSB(ab); s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_HP; return 0; diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h index f52fd61d685d..85192d170b6b 100644 --- a/drivers/net/wireless/ath/ath11k/hal.h +++ b/drivers/net/wireless/ath/ath11k/hal.h @@ -46,40 +46,47 @@ struct ath11k_base; /* SW2TCL(x) R0 ring configuration address */ #define HAL_TCL1_RING_CMN_CTRL_REG 0x00000014 #define HAL_TCL1_RING_DSCP_TID_MAP 0x0000002c -#define HAL_TCL1_RING_BASE_LSB ab->hw_params.regs->hal_tcl1_ring_base_lsb -#define HAL_TCL1_RING_BASE_MSB ab->hw_params.regs->hal_tcl1_ring_base_msb -#define HAL_TCL1_RING_ID ab->hw_params.regs->hal_tcl1_ring_id -#define HAL_TCL1_RING_MISC ab->hw_params.regs->hal_tcl1_ring_misc -#define HAL_TCL1_RING_TP_ADDR_LSB ab->hw_params.regs->hal_tcl1_ring_tp_addr_lsb -#define HAL_TCL1_RING_TP_ADDR_MSB ab->hw_params.regs->hal_tcl1_ring_tp_addr_msb -#define HAL_TCL1_RING_CONSUMER_INT_SETUP_IX0 ab->hw_params.regs->hal_tcl1_ring_consumer_int_setup_ix0 -#define HAL_TCL1_RING_CONSUMER_INT_SETUP_IX1 ab->hw_params.regs->hal_tcl1_ring_consumer_int_setup_ix1 -#define HAL_TCL1_RING_MSI1_BASE_LSB ab->hw_params.regs->hal_tcl1_ring_msi1_base_lsb -#define HAL_TCL1_RING_MSI1_BASE_MSB ab->hw_params.regs->hal_tcl1_ring_msi1_base_msb -#define HAL_TCL1_RING_MSI1_DATA ab->hw_params.regs->hal_tcl1_ring_msi1_data -#define HAL_TCL2_RING_BASE_LSB ab->hw_params.regs->hal_tcl2_ring_base_lsb -#define HAL_TCL_RING_BASE_LSB ab->hw_params.regs->hal_tcl_ring_base_lsb - -#define HAL_TCL1_RING_MSI1_BASE_LSB_OFFSET \ - (HAL_TCL1_RING_MSI1_BASE_LSB - HAL_TCL1_RING_BASE_LSB) -#define HAL_TCL1_RING_MSI1_BASE_MSB_OFFSET \ - (HAL_TCL1_RING_MSI1_BASE_MSB - HAL_TCL1_RING_BASE_LSB) -#define HAL_TCL1_RING_MSI1_DATA_OFFSET \ - (HAL_TCL1_RING_MSI1_DATA - HAL_TCL1_RING_BASE_LSB) -#define HAL_TCL1_RING_BASE_MSB_OFFSET \ - (HAL_TCL1_RING_BASE_MSB - HAL_TCL1_RING_BASE_LSB) -#define HAL_TCL1_RING_ID_OFFSET \ - (HAL_TCL1_RING_ID - HAL_TCL1_RING_BASE_LSB) -#define HAL_TCL1_RING_CONSR_INT_SETUP_IX0_OFFSET \ - (HAL_TCL1_RING_CONSUMER_INT_SETUP_IX0 - HAL_TCL1_RING_BASE_LSB) -#define HAL_TCL1_RING_CONSR_INT_SETUP_IX1_OFFSET \ - (HAL_TCL1_RING_CONSUMER_INT_SETUP_IX1 - HAL_TCL1_RING_BASE_LSB) -#define HAL_TCL1_RING_TP_ADDR_LSB_OFFSET \ - (HAL_TCL1_RING_TP_ADDR_LSB - HAL_TCL1_RING_BASE_LSB) -#define HAL_TCL1_RING_TP_ADDR_MSB_OFFSET \ - (HAL_TCL1_RING_TP_ADDR_MSB - HAL_TCL1_RING_BASE_LSB) -#define HAL_TCL1_RING_MISC_OFFSET \ - (HAL_TCL1_RING_MISC - HAL_TCL1_RING_BASE_LSB) +#define HAL_TCL1_RING_BASE_LSB(ab) ab->hw_params.regs->hal_tcl1_ring_base_lsb +#define HAL_TCL1_RING_BASE_MSB(ab) ab->hw_params.regs->hal_tcl1_ring_base_msb +#define HAL_TCL1_RING_ID(ab) ab->hw_params.regs->hal_tcl1_ring_id +#define HAL_TCL1_RING_MISC(ab) ab->hw_params.regs->hal_tcl1_ring_misc +#define HAL_TCL1_RING_TP_ADDR_LSB(ab) \ + ab->hw_params.regs->hal_tcl1_ring_tp_addr_lsb +#define HAL_TCL1_RING_TP_ADDR_MSB(ab) \ + ab->hw_params.regs->hal_tcl1_ring_tp_addr_msb +#define HAL_TCL1_RING_CONSUMER_INT_SETUP_IX0(ab) \ + ab->hw_params.regs->hal_tcl1_ring_consumer_int_setup_ix0 +#define HAL_TCL1_RING_CONSUMER_INT_SETUP_IX1(ab) \ + ab->hw_params.regs->hal_tcl1_ring_consumer_int_setup_ix1 +#define HAL_TCL1_RING_MSI1_BASE_LSB(ab) \ + ab->hw_params.regs->hal_tcl1_ring_msi1_base_lsb +#define HAL_TCL1_RING_MSI1_BASE_MSB(ab) \ + ab->hw_params.regs->hal_tcl1_ring_msi1_base_msb +#define HAL_TCL1_RING_MSI1_DATA(ab) \ + ab->hw_params.regs->hal_tcl1_ring_msi1_data +#define HAL_TCL2_RING_BASE_LSB(ab) ab->hw_params.regs->hal_tcl2_ring_base_lsb +#define HAL_TCL_RING_BASE_LSB(ab) ab->hw_params.regs->hal_tcl_ring_base_lsb + +#define HAL_TCL1_RING_MSI1_BASE_LSB_OFFSET(ab) \ + (HAL_TCL1_RING_MSI1_BASE_LSB(ab) - HAL_TCL1_RING_BASE_LSB(ab)) +#define HAL_TCL1_RING_MSI1_BASE_MSB_OFFSET(ab) \ + (HAL_TCL1_RING_MSI1_BASE_MSB(ab) - HAL_TCL1_RING_BASE_LSB(ab)) +#define HAL_TCL1_RING_MSI1_DATA_OFFSET(ab) \ + (HAL_TCL1_RING_MSI1_DATA(ab) - HAL_TCL1_RING_BASE_LSB(ab)) +#define HAL_TCL1_RING_BASE_MSB_OFFSET(ab) \ + (HAL_TCL1_RING_BASE_MSB(ab) - HAL_TCL1_RING_BASE_LSB(ab)) +#define HAL_TCL1_RING_ID_OFFSET(ab) \ + (HAL_TCL1_RING_ID(ab) - HAL_TCL1_RING_BASE_LSB(ab)) +#define HAL_TCL1_RING_CONSR_INT_SETUP_IX0_OFFSET(ab) \ + (HAL_TCL1_RING_CONSUMER_INT_SETUP_IX0(ab) - HAL_TCL1_RING_BASE_LSB(ab)) +#define HAL_TCL1_RING_CONSR_INT_SETUP_IX1_OFFSET(ab) \ + (HAL_TCL1_RING_CONSUMER_INT_SETUP_IX1(ab) - HAL_TCL1_RING_BASE_LSB(ab)) +#define HAL_TCL1_RING_TP_ADDR_LSB_OFFSET(ab) \ + (HAL_TCL1_RING_TP_ADDR_LSB(ab) - HAL_TCL1_RING_BASE_LSB(ab)) +#define HAL_TCL1_RING_TP_ADDR_MSB_OFFSET(ab) \ + (HAL_TCL1_RING_TP_ADDR_MSB(ab) - HAL_TCL1_RING_BASE_LSB(ab)) +#define HAL_TCL1_RING_MISC_OFFSET(ab) \ + (HAL_TCL1_RING_MISC(ab) - HAL_TCL1_RING_BASE_LSB(ab)) /* SW2TCL(x) R2 ring pointers (head/tail) address */ #define HAL_TCL1_RING_HP 0x00002000 @@ -91,7 +98,8 @@ struct ath11k_base; (HAL_TCL1_RING_TP - HAL_TCL1_RING_HP) /* TCL STATUS ring address */ -#define HAL_TCL_STATUS_RING_BASE_LSB ab->hw_params.regs->hal_tcl_status_ring_base_lsb +#define HAL_TCL_STATUS_RING_BASE_LSB(ab) \ + ab->hw_params.regs->hal_tcl_status_ring_base_lsb #define HAL_TCL_STATUS_RING_HP 0x00002030 /* REO2SW(x) R0 ring configuration address */ @@ -100,51 +108,63 @@ struct ath11k_base; #define HAL_REO1_DEST_RING_CTRL_IX_1 0x00000008 #define HAL_REO1_DEST_RING_CTRL_IX_2 0x0000000c #define HAL_REO1_DEST_RING_CTRL_IX_3 0x00000010 - #define HAL_REO1_RING_BASE_LSB ab->hw_params.regs->hal_reo1_ring_base_lsb -#define HAL_REO1_RING_BASE_MSB ab->hw_params.regs->hal_reo1_ring_base_msb -#define HAL_REO1_RING_ID ab->hw_params.regs->hal_reo1_ring_id -#define HAL_REO1_RING_MISC ab->hw_params.regs->hal_reo1_ring_misc -#define HAL_REO1_RING_HP_ADDR_LSB ab->hw_params.regs->hal_reo1_ring_hp_addr_lsb -#define HAL_REO1_RING_HP_ADDR_MSB ab->hw_params.regs->hal_reo1_ring_hp_addr_msb -#define HAL_REO1_RING_PRODUCER_INT_SETUP ab->hw_params.regs->hal_reo1_ring_producer_int_setup -#define HAL_REO1_RING_MSI1_BASE_LSB ab->hw_params.regs->hal_reo1_ring_msi1_base_lsb -#define HAL_REO1_RING_MSI1_BASE_MSB ab->hw_params.regs->hal_reo1_ring_msi1_base_msb -#define HAL_REO1_RING_MSI1_DATA ab->hw_params.regs->hal_reo1_ring_msi1_data -#define HAL_REO2_RING_BASE_LSB ab->hw_params.regs->hal_reo2_ring_base_lsb -#define HAL_REO1_AGING_THRESH_IX_0 ab->hw_params.regs->hal_reo1_aging_thresh_ix_0 -#define HAL_REO1_AGING_THRESH_IX_1 ab->hw_params.regs->hal_reo1_aging_thresh_ix_1 -#define HAL_REO1_AGING_THRESH_IX_2 ab->hw_params.regs->hal_reo1_aging_thresh_ix_2 -#define HAL_REO1_AGING_THRESH_IX_3 ab->hw_params.regs->hal_reo1_aging_thresh_ix_3 - -#define HAL_REO1_RING_MSI1_BASE_LSB_OFFSET \ - (HAL_REO1_RING_MSI1_BASE_LSB - HAL_REO1_RING_BASE_LSB) -#define HAL_REO1_RING_MSI1_BASE_MSB_OFFSET \ - (HAL_REO1_RING_MSI1_BASE_MSB - HAL_REO1_RING_BASE_LSB) -#define HAL_REO1_RING_MSI1_DATA_OFFSET \ - (HAL_REO1_RING_MSI1_DATA - HAL_REO1_RING_BASE_LSB) -#define HAL_REO1_RING_BASE_MSB_OFFSET \ - (HAL_REO1_RING_BASE_MSB - HAL_REO1_RING_BASE_LSB) -#define HAL_REO1_RING_ID_OFFSET (HAL_REO1_RING_ID - HAL_REO1_RING_BASE_LSB) -#define HAL_REO1_RING_PRODUCER_INT_SETUP_OFFSET \ - (HAL_REO1_RING_PRODUCER_INT_SETUP - HAL_REO1_RING_BASE_LSB) -#define HAL_REO1_RING_HP_ADDR_LSB_OFFSET \ - (HAL_REO1_RING_HP_ADDR_LSB - HAL_REO1_RING_BASE_LSB) -#define HAL_REO1_RING_HP_ADDR_MSB_OFFSET \ - (HAL_REO1_RING_HP_ADDR_MSB - HAL_REO1_RING_BASE_LSB) -#define HAL_REO1_RING_MISC_OFFSET (HAL_REO1_RING_MISC - HAL_REO1_RING_BASE_LSB) +#define HAL_REO1_RING_BASE_LSB(ab) ab->hw_params.regs->hal_reo1_ring_base_lsb +#define HAL_REO1_RING_BASE_MSB(ab) ab->hw_params.regs->hal_reo1_ring_base_msb +#define HAL_REO1_RING_ID(ab) ab->hw_params.regs->hal_reo1_ring_id +#define HAL_REO1_RING_MISC(ab) ab->hw_params.regs->hal_reo1_ring_misc +#define HAL_REO1_RING_HP_ADDR_LSB(ab) \ + ab->hw_params.regs->hal_reo1_ring_hp_addr_lsb +#define HAL_REO1_RING_HP_ADDR_MSB(ab) \ + ab->hw_params.regs->hal_reo1_ring_hp_addr_msb +#define HAL_REO1_RING_PRODUCER_INT_SETUP(ab) \ + ab->hw_params.regs->hal_reo1_ring_producer_int_setup +#define HAL_REO1_RING_MSI1_BASE_LSB(ab) \ + ab->hw_params.regs->hal_reo1_ring_msi1_base_lsb +#define HAL_REO1_RING_MSI1_BASE_MSB(ab) \ + ab->hw_params.regs->hal_reo1_ring_msi1_base_msb +#define HAL_REO1_RING_MSI1_DATA(ab) \ + ab->hw_params.regs->hal_reo1_ring_msi1_data +#define HAL_REO2_RING_BASE_LSB(ab) ab->hw_params.regs->hal_reo2_ring_base_lsb +#define HAL_REO1_AGING_THRESH_IX_0(ab) \ + ab->hw_params.regs->hal_reo1_aging_thresh_ix_0 +#define HAL_REO1_AGING_THRESH_IX_1(ab) \ + ab->hw_params.regs->hal_reo1_aging_thresh_ix_1 +#define HAL_REO1_AGING_THRESH_IX_2(ab) \ + ab->hw_params.regs->hal_reo1_aging_thresh_ix_2 +#define HAL_REO1_AGING_THRESH_IX_3(ab) \ + ab->hw_params.regs->hal_reo1_aging_thresh_ix_3 + +#define HAL_REO1_RING_MSI1_BASE_LSB_OFFSET(ab) \ + (HAL_REO1_RING_MSI1_BASE_LSB(ab) - HAL_REO1_RING_BASE_LSB(ab)) +#define HAL_REO1_RING_MSI1_BASE_MSB_OFFSET(ab) \ + (HAL_REO1_RING_MSI1_BASE_MSB(ab) - HAL_REO1_RING_BASE_LSB(ab)) +#define HAL_REO1_RING_MSI1_DATA_OFFSET(ab) \ + (HAL_REO1_RING_MSI1_DATA(ab) - HAL_REO1_RING_BASE_LSB(ab)) +#define HAL_REO1_RING_BASE_MSB_OFFSET(ab) \ + (HAL_REO1_RING_BASE_MSB(ab) - HAL_REO1_RING_BASE_LSB(ab)) +#define HAL_REO1_RING_ID_OFFSET(ab) (HAL_REO1_RING_ID(ab) - HAL_REO1_RING_BASE_LSB(ab)) +#define HAL_REO1_RING_PRODUCER_INT_SETUP_OFFSET(ab) \ + (HAL_REO1_RING_PRODUCER_INT_SETUP(ab) - HAL_REO1_RING_BASE_LSB(ab)) +#define HAL_REO1_RING_HP_ADDR_LSB_OFFSET(ab) \ + (HAL_REO1_RING_HP_ADDR_LSB(ab) - HAL_REO1_RING_BASE_LSB(ab)) +#define HAL_REO1_RING_HP_ADDR_MSB_OFFSET(ab) \ + (HAL_REO1_RING_HP_ADDR_MSB(ab) - HAL_REO1_RING_BASE_LSB(ab)) +#define HAL_REO1_RING_MISC_OFFSET(ab) \ + (HAL_REO1_RING_MISC(ab) - HAL_REO1_RING_BASE_LSB(ab)) /* REO2SW(x) R2 ring pointers (head/tail) address */ -#define HAL_REO1_RING_HP ab->hw_params.regs->hal_reo1_ring_hp -#define HAL_REO1_RING_TP ab->hw_params.regs->hal_reo1_ring_tp -#define HAL_REO2_RING_HP ab->hw_params.regs->hal_reo2_ring_hp +#define HAL_REO1_RING_HP(ab) ab->hw_params.regs->hal_reo1_ring_hp +#define HAL_REO1_RING_TP(ab) ab->hw_params.regs->hal_reo1_ring_tp +#define HAL_REO2_RING_HP(ab) ab->hw_params.regs->hal_reo2_ring_hp -#define HAL_REO1_RING_TP_OFFSET (HAL_REO1_RING_TP - HAL_REO1_RING_HP) +#define HAL_REO1_RING_TP_OFFSET(ab) (HAL_REO1_RING_TP(ab) - HAL_REO1_RING_HP(ab)) /* REO2TCL R0 ring configuration address */ -#define HAL_REO_TCL_RING_BASE_LSB ab->hw_params.regs->hal_reo_tcl_ring_base_lsb +#define HAL_REO_TCL_RING_BASE_LSB(ab) \ + ab->hw_params.regs->hal_reo_tcl_ring_base_lsb /* REO2TCL R2 ring pointer (head/tail) address */ -#define HAL_REO_TCL_RING_HP ab->hw_params.regs->hal_reo_tcl_ring_hp +#define HAL_REO_TCL_RING_HP(ab) ab->hw_params.regs->hal_reo_tcl_ring_hp /* REO CMD R0 address */ #define HAL_REO_CMD_RING_BASE_LSB 0x00000194 @@ -168,8 +188,9 @@ struct ath11k_base; #define HAL_CE_DST_STATUS_RING_HP 0x00000408 /* REO status address */ -#define HAL_REO_STATUS_RING_BASE_LSB ab->hw_params.regs->hal_reo_status_ring_base_lsb -#define HAL_REO_STATUS_HP ab->hw_params.regs->hal_reo_status_hp +#define HAL_REO_STATUS_RING_BASE_LSB(ab) \ + ab->hw_params.regs->hal_reo_status_ring_base_lsb +#define HAL_REO_STATUS_HP(ab) ab->hw_params.regs->hal_reo_status_hp /* WBM Idle R0 address */ #define HAL_WBM_IDLE_LINK_RING_BASE_LSB 0x00000860 diff --git a/drivers/net/wireless/ath/ath11k/hal_rx.c b/drivers/net/wireless/ath/ath11k/hal_rx.c index b30f1931313d..4bbad2e341ee 100644 --- a/drivers/net/wireless/ath/ath11k/hal_rx.c +++ b/drivers/net/wireless/ath/ath11k/hal_rx.c @@ -813,13 +813,13 @@ void ath11k_hal_reo_hw_setup(struct ath11k_base *ab, u32 ring_hash_map) FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_FLUSH_ENABLE, 1); ath11k_hif_write32(ab, reo_base + HAL_REO1_GEN_ENABLE, val); - ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_0, + ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_0(ab), HAL_DEFAULT_REO_TIMEOUT_USEC); - ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_1, + ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_1(ab), HAL_DEFAULT_REO_TIMEOUT_USEC); - ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_2, + ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_2(ab), HAL_DEFAULT_REO_TIMEOUT_USEC); - ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_3, + ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_3(ab), HAL_DEFAULT_REO_TIMEOUT_USEC); ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_0, -- cgit v1.2.3 From e3396b8bddd2ea822f9390f1ba49c22d769a7534 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Mon, 17 Aug 2020 13:31:47 +0300 Subject: ath11k: ce: support different CE configurations QCA6390 uses only 9 Copy Engines while IPQ8074 may use 12, make it possible to change CE configuration dynamically via hw_params. The defines for host_ce_config_wlan and CE_COUNT are temporary solutions, they will be removed in the following patches to keep things simple. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597576599-8857-4-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/ahb.c | 12 ++--- drivers/net/wireless/ath/ath11k/ce.c | 84 +++++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath11k/ce.h | 11 +++-- drivers/net/wireless/ath/ath11k/core.c | 4 ++ drivers/net/wireless/ath/ath11k/hal.c | 2 +- drivers/net/wireless/ath/ath11k/hw.c | 1 + drivers/net/wireless/ath/ath11k/hw.h | 2 + drivers/net/wireless/ath/ath11k/pci.c | 12 ++--- 8 files changed, 110 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 2e0d90c022bb..4bc3558fc300 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -387,7 +387,7 @@ static void ath11k_ahb_kill_tasklets(struct ath11k_base *ab) for (i = 0; i < CE_COUNT; i++) { struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; - if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) + if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; tasklet_kill(&ce_pipe->intr_tq); @@ -476,7 +476,7 @@ static void ath11k_ahb_sync_ce_irqs(struct ath11k_base *ab) int irq_idx; for (i = 0; i < CE_COUNT; i++) { - if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) + if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; irq_idx = ATH11K_IRQ_CE0_OFFSET + i; @@ -504,7 +504,7 @@ static void ath11k_ahb_ce_irqs_enable(struct ath11k_base *ab) int i; for (i = 0; i < CE_COUNT; i++) { - if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) + if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; ath11k_ahb_ce_irq_enable(ab, i); } @@ -515,7 +515,7 @@ static void ath11k_ahb_ce_irqs_disable(struct ath11k_base *ab) int i; for (i = 0; i < CE_COUNT; i++) { - if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) + if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; ath11k_ahb_ce_irq_disable(ab, i); } @@ -602,7 +602,7 @@ static void ath11k_ahb_free_irq(struct ath11k_base *ab) int i; for (i = 0; i < CE_COUNT; i++) { - if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) + if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; irq_idx = ATH11K_IRQ_CE0_OFFSET + i; free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); @@ -759,7 +759,7 @@ static int ath11k_ahb_config_irq(struct ath11k_base *ab) for (i = 0; i < CE_COUNT; i++) { struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; - if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) + if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; irq_idx = ATH11K_IRQ_CE0_OFFSET + i; diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index 59cb403b8597..a588e5d0e5e0 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c @@ -7,7 +7,9 @@ #include "debug.h" #include "hif.h" -static const struct ce_attr host_ce_config_wlan[] = { +#define host_ce_config_wlan ab->hw_params.host_ce_config + +const struct ce_attr ath11k_host_ce_config_ipq8074[] = { /* CE0: host->target HTC control and raw streams */ { .flags = CE_ATTR_FLAGS, @@ -109,6 +111,84 @@ static const struct ce_attr host_ce_config_wlan[] = { }, }; +const struct ce_attr ath11k_host_ce_config_qca6390[] = { + /* CE0: host->target HTC control and raw streams */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 16, + .src_sz_max = 2048, + .dest_nentries = 0, + }, + + /* CE1: target->host HTT + HTC control */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 512, + .recv_cb = ath11k_htc_rx_completion_handler, + }, + + /* CE2: target->host WMI */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 512, + .recv_cb = ath11k_htc_rx_completion_handler, + }, + + /* CE3: host->target WMI (mac0) */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 32, + .src_sz_max = 2048, + .dest_nentries = 0, + }, + + /* CE4: host->target HTT */ + { + .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, + .src_nentries = 2048, + .src_sz_max = 256, + .dest_nentries = 0, + }, + + /* CE5: target->host pktlog */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 512, + .recv_cb = ath11k_dp_htt_htc_t2h_msg_handler, + }, + + /* CE6: target autonomous hif_memcpy */ + { + .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, + .src_nentries = 0, + .src_sz_max = 0, + .dest_nentries = 0, + }, + + /* CE7: host->target WMI (mac1) */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 32, + .src_sz_max = 2048, + .dest_nentries = 0, + }, + + /* CE8: target autonomous hif_memcpy */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 0, + .dest_nentries = 0, + }, + +}; + static int ath11k_ce_rx_buf_enqueue_pipe(struct ath11k_ce_pipe *pipe, struct sk_buff *skb, dma_addr_t paddr) { @@ -834,7 +914,7 @@ void ath11k_ce_byte_swap(void *mem, u32 len) } } -int ath11k_ce_get_attr_flags(int ce_id) +int ath11k_ce_get_attr_flags(struct ath11k_base *ab, int ce_id) { if (ce_id >= CE_COUNT) return -EINVAL; diff --git a/drivers/net/wireless/ath/ath11k/ce.h b/drivers/net/wireless/ath/ath11k/ce.h index 6e3a37909ade..8feb6e98ea13 100644 --- a/drivers/net/wireless/ath/ath11k/ce.h +++ b/drivers/net/wireless/ath/ath11k/ce.h @@ -6,7 +6,8 @@ #ifndef ATH11K_CE_H #define ATH11K_CE_H -#define CE_COUNT 12 +#define CE_COUNT (ab->hw_params.ce_count) +#define CE_COUNT_MAX 12 /* Byte swap data words */ #define CE_ATTR_BYTE_SWAP_DATA 2 @@ -165,11 +166,14 @@ struct ath11k_ce_pipe { }; struct ath11k_ce { - struct ath11k_ce_pipe ce_pipe[CE_COUNT]; + struct ath11k_ce_pipe ce_pipe[CE_COUNT_MAX]; /* Protects rings of all ce pipes */ spinlock_t ce_lock; }; +extern const struct ce_attr ath11k_host_ce_config_ipq8074[]; +extern const struct ce_attr ath11k_host_ce_config_qca6390[]; + void ath11k_ce_cleanup_pipes(struct ath11k_base *ab); void ath11k_ce_rx_replenish_retry(struct timer_list *t); void ath11k_ce_per_engine_service(struct ath11k_base *ab, u16 ce_id); @@ -179,8 +183,9 @@ void ath11k_ce_rx_post_buf(struct ath11k_base *ab); int ath11k_ce_init_pipes(struct ath11k_base *ab); int ath11k_ce_alloc_pipes(struct ath11k_base *ab); void ath11k_ce_free_pipes(struct ath11k_base *ab); -int ath11k_ce_get_attr_flags(int ce_id); +int ath11k_ce_get_attr_flags(struct ath11k_base *ab, int ce_id); void ath11k_ce_poll_send_completed(struct ath11k_base *ab, u8 pipe_id); int ath11k_ce_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, u8 *ul_pipe, u8 *dl_pipe); +int ath11k_ce_attr_attach(struct ath11k_base *ab); #endif diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 613a8a6721ba..c55c886f6276 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -33,6 +33,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .ring_mask = &ath11k_hw_ring_mask_ipq8074, .internal_sleep_clock = false, .regs = &ipq8074_regs, + .host_ce_config = ath11k_host_ce_config_ipq8074, + .ce_count = 12, }, { .name = "qca6390 hw2.0", @@ -48,6 +50,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .ring_mask = &ath11k_hw_ring_mask_ipq8074, .internal_sleep_clock = true, .regs = &qca6390_regs, + .host_ce_config = ath11k_host_ce_config_qca6390, + .ce_count = 9, }, }; diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index ae4dc6c39e64..cca019cc0234 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -1160,7 +1160,7 @@ void ath11k_hal_dump_srng_stats(struct ath11k_base *ab) for (i = 0; i < CE_COUNT; i++) { ce_pipe = &ab->ce.ce_pipe[i]; - if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) + if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; ath11k_err(ab, "CE_id %d pipe_num %d %ums before\n", diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index 51ddd418bc3b..5811eabf2275 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -9,6 +9,7 @@ #include "hw.h" #include "core.h" +#include "ce.h" /* Map from pdev index to hw mac index */ static u8 ath11k_hw_ipq8074_mac_from_pdev_id(int pdev_idx) diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index eb1d8a2beffd..ef553bafa158 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -137,6 +137,8 @@ struct ath11k_hw_params { bool internal_sleep_clock; const struct ath11k_hw_regs *regs; + const struct ce_attr *host_ce_config; + u32 ce_count; }; extern const struct ath11k_hw_ops ipq8074_ops; diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index d5dcbb928baf..e4551fb493ff 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -394,7 +394,7 @@ static void ath11k_pci_free_irq(struct ath11k_base *ab) int i, irq_idx; for (i = 0; i < CE_COUNT; i++) { - if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) + if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); @@ -422,7 +422,7 @@ static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab) int i; for (i = 0; i < CE_COUNT; i++) { - if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) + if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; ath11k_pci_ce_irq_disable(ab, i); } @@ -434,7 +434,7 @@ static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab) int irq_idx; for (i = 0; i < CE_COUNT; i++) { - if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) + if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; @@ -482,7 +482,7 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab) irq = ath11k_pci_get_msi_irq(ab->dev, msi_data); ce_pipe = &ab->ce.ce_pipe[i]; - if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) + if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; @@ -522,7 +522,7 @@ static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab) int i; for (i = 0; i < CE_COUNT; i++) { - if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) + if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; ath11k_pci_ce_irq_enable(ab, i); } @@ -683,7 +683,7 @@ static void ath11k_pci_kill_tasklets(struct ath11k_base *ab) for (i = 0; i < CE_COUNT; i++) { struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; - if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) + if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; tasklet_kill(&ce_pipe->intr_tq); -- cgit v1.2.3 From 6e5e9f59dc5b49bad3af283c165beb8321e2a89b Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 17 Aug 2020 13:31:47 +0300 Subject: ath11k: ce: remove host_ce_config_wlan macro This macro is evil as it's accesses ab variable in a hidden way. It's better for readibility to access ab->hw_params.host_ce_config directly. This is done in a separate patch to keep the patches simple. No functional changes. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597576599-8857-5-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/ce.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index a588e5d0e5e0..c75007e92830 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c @@ -7,8 +7,6 @@ #include "debug.h" #include "hif.h" -#define host_ce_config_wlan ab->hw_params.host_ce_config - const struct ce_attr ath11k_host_ce_config_ipq8074[] = { /* CE0: host->target HTC control and raw streams */ { @@ -471,19 +469,19 @@ static int ath11k_ce_init_ring(struct ath11k_base *ab, switch (type) { case HAL_CE_SRC: - if (!(CE_ATTR_DIS_INTR & host_ce_config_wlan[ce_id].flags)) + if (!(CE_ATTR_DIS_INTR & ab->hw_params.host_ce_config[ce_id].flags)) params.intr_batch_cntr_thres_entries = 1; break; case HAL_CE_DST: - params.max_buffer_len = host_ce_config_wlan[ce_id].src_sz_max; - if (!(host_ce_config_wlan[ce_id].flags & CE_ATTR_DIS_INTR)) { + params.max_buffer_len = ab->hw_params.host_ce_config[ce_id].src_sz_max; + if (!(ab->hw_params.host_ce_config[ce_id].flags & CE_ATTR_DIS_INTR)) { params.intr_timer_thres_us = 1024; params.flags |= HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN; params.low_threshold = ce_ring->nentries - 3; } break; case HAL_CE_DST_STATUS: - if (!(host_ce_config_wlan[ce_id].flags & CE_ATTR_DIS_INTR)) { + if (!(ab->hw_params.host_ce_config[ce_id].flags & CE_ATTR_DIS_INTR)) { params.intr_batch_cntr_thres_entries = 1; params.intr_timer_thres_us = 0x1000; } @@ -502,7 +500,7 @@ static int ath11k_ce_init_ring(struct ath11k_base *ab, return ret; } - if (!(CE_ATTR_DIS_INTR & host_ce_config_wlan[ce_id].flags)) + if (!(CE_ATTR_DIS_INTR & ab->hw_params.host_ce_config[ce_id].flags)) ath11k_ce_srng_msi_ring_params_setup(ab, ce_id, ¶ms); ce_ring->hal_ring_id = ret; @@ -550,7 +548,7 @@ ath11k_ce_alloc_ring(struct ath11k_base *ab, int nentries, int desc_sz) static int ath11k_ce_alloc_pipe(struct ath11k_base *ab, int ce_id) { struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id]; - const struct ce_attr *attr = &host_ce_config_wlan[ce_id]; + const struct ce_attr *attr = &ab->hw_params.host_ce_config[ce_id]; struct ath11k_ce_ring *ring; int nentries; int desc_sz; @@ -877,7 +875,7 @@ int ath11k_ce_alloc_pipes(struct ath11k_base *ab) spin_lock_init(&ab->ce.ce_lock); for (i = 0; i < CE_COUNT; i++) { - attr = &host_ce_config_wlan[i]; + attr = &ab->hw_params.host_ce_config[i]; pipe = &ab->ce.ce_pipe[i]; pipe->pipe_num = i; pipe->ab = ab; @@ -919,6 +917,6 @@ int ath11k_ce_get_attr_flags(struct ath11k_base *ab, int ce_id) if (ce_id >= CE_COUNT) return -EINVAL; - return host_ce_config_wlan[ce_id].flags; + return ab->hw_params.host_ce_config[ce_id].flags; } EXPORT_SYMBOL(ath11k_ce_get_attr_flags); -- cgit v1.2.3 From d9d4b5f354883375b8e35caa172af6c223f4a0c1 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 17 Aug 2020 13:31:48 +0300 Subject: ath11k: ce: remove CE_COUNT() macro This macro is evil as it's accesses ab variable in a hidden way. It's better for readibility to access ab->hw_params.ce_count directly. This is done in a separate patch to keep the patches simple. No functional changes. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597576599-8857-6-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/ahb.c | 12 ++++++------ drivers/net/wireless/ath/ath11k/ce.c | 12 ++++++------ drivers/net/wireless/ath/ath11k/ce.h | 1 - drivers/net/wireless/ath/ath11k/hal.c | 2 +- drivers/net/wireless/ath/ath11k/htc.c | 2 +- drivers/net/wireless/ath/ath11k/pci.c | 12 ++++++------ 6 files changed, 20 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 4bc3558fc300..8466c62a83d6 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -384,7 +384,7 @@ static void ath11k_ahb_kill_tasklets(struct ath11k_base *ab) { int i; - for (i = 0; i < CE_COUNT; i++) { + for (i = 0; i < ab->hw_params.ce_count; i++) { struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) @@ -475,7 +475,7 @@ static void ath11k_ahb_sync_ce_irqs(struct ath11k_base *ab) int i; int irq_idx; - for (i = 0; i < CE_COUNT; i++) { + for (i = 0; i < ab->hw_params.ce_count; i++) { if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; @@ -503,7 +503,7 @@ static void ath11k_ahb_ce_irqs_enable(struct ath11k_base *ab) { int i; - for (i = 0; i < CE_COUNT; i++) { + for (i = 0; i < ab->hw_params.ce_count; i++) { if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; ath11k_ahb_ce_irq_enable(ab, i); @@ -514,7 +514,7 @@ static void ath11k_ahb_ce_irqs_disable(struct ath11k_base *ab) { int i; - for (i = 0; i < CE_COUNT; i++) { + for (i = 0; i < ab->hw_params.ce_count; i++) { if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; ath11k_ahb_ce_irq_disable(ab, i); @@ -601,7 +601,7 @@ static void ath11k_ahb_free_irq(struct ath11k_base *ab) int irq_idx; int i; - for (i = 0; i < CE_COUNT; i++) { + for (i = 0; i < ab->hw_params.ce_count; i++) { if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; irq_idx = ATH11K_IRQ_CE0_OFFSET + i; @@ -756,7 +756,7 @@ static int ath11k_ahb_config_irq(struct ath11k_base *ab) int ret; /* Configure CE irqs */ - for (i = 0; i < CE_COUNT; i++) { + for (i = 0; i < ab->hw_params.ce_count; i++) { struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index c75007e92830..41c1a6e56596 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c @@ -718,7 +718,7 @@ void ath11k_ce_cleanup_pipes(struct ath11k_base *ab) struct ath11k_ce_pipe *pipe; int pipe_num; - for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { + for (pipe_num = 0; pipe_num < ab->hw_params.ce_count; pipe_num++) { pipe = &ab->ce.ce_pipe[pipe_num]; ath11k_ce_rx_pipe_cleanup(pipe); @@ -736,7 +736,7 @@ void ath11k_ce_rx_post_buf(struct ath11k_base *ab) int i; int ret; - for (i = 0; i < CE_COUNT; i++) { + for (i = 0; i < ab->hw_params.ce_count; i++) { pipe = &ab->ce.ce_pipe[i]; ret = ath11k_ce_rx_post_pipe(pipe); if (ret) { @@ -767,7 +767,7 @@ int ath11k_ce_init_pipes(struct ath11k_base *ab) int i; int ret; - for (i = 0; i < CE_COUNT; i++) { + for (i = 0; i < ab->hw_params.ce_count; i++) { pipe = &ab->ce.ce_pipe[i]; if (pipe->src_ring) { @@ -825,7 +825,7 @@ void ath11k_ce_free_pipes(struct ath11k_base *ab) int desc_sz; int i; - for (i = 0; i < CE_COUNT; i++) { + for (i = 0; i < ab->hw_params.ce_count; i++) { pipe = &ab->ce.ce_pipe[i]; if (pipe->src_ring) { @@ -874,7 +874,7 @@ int ath11k_ce_alloc_pipes(struct ath11k_base *ab) spin_lock_init(&ab->ce.ce_lock); - for (i = 0; i < CE_COUNT; i++) { + for (i = 0; i < ab->hw_params.ce_count; i++) { attr = &ab->hw_params.host_ce_config[i]; pipe = &ab->ce.ce_pipe[i]; pipe->pipe_num = i; @@ -914,7 +914,7 @@ void ath11k_ce_byte_swap(void *mem, u32 len) int ath11k_ce_get_attr_flags(struct ath11k_base *ab, int ce_id) { - if (ce_id >= CE_COUNT) + if (ce_id >= ab->hw_params.ce_count) return -EINVAL; return ab->hw_params.host_ce_config[ce_id].flags; diff --git a/drivers/net/wireless/ath/ath11k/ce.h b/drivers/net/wireless/ath/ath11k/ce.h index 8feb6e98ea13..cf704f18f3a1 100644 --- a/drivers/net/wireless/ath/ath11k/ce.h +++ b/drivers/net/wireless/ath/ath11k/ce.h @@ -6,7 +6,6 @@ #ifndef ATH11K_CE_H #define ATH11K_CE_H -#define CE_COUNT (ab->hw_params.ce_count) #define CE_COUNT_MAX 12 /* Byte swap data words */ diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index cca019cc0234..7dcdcc1a72fb 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -1157,7 +1157,7 @@ void ath11k_hal_dump_srng_stats(struct ath11k_base *ab) int i; ath11k_err(ab, "Last interrupt received for each CE:\n"); - for (i = 0; i < CE_COUNT; i++) { + for (i = 0; i < ab->hw_params.ce_count; i++) { ce_pipe = &ab->ce.ce_pipe[i]; if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) diff --git a/drivers/net/wireless/ath/ath11k/htc.c b/drivers/net/wireless/ath/ath11k/htc.c index bc0026c1e4a6..e9e354fc11fa 100644 --- a/drivers/net/wireless/ath/ath11k/htc.c +++ b/drivers/net/wireless/ath/ath11k/htc.c @@ -478,7 +478,7 @@ int ath11k_htc_wait_target(struct ath11k_htc *htc) if (!time_left) { ath11k_warn(ab, "failed to receive control response completion, polling..\n"); - for (i = 0; i < CE_COUNT; i++) + for (i = 0; i < ab->hw_params.ce_count; i++) ath11k_ce_per_engine_service(htc->ab, i); time_left = diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index e4551fb493ff..37bd385348c3 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -393,7 +393,7 @@ static void ath11k_pci_free_irq(struct ath11k_base *ab) { int i, irq_idx; - for (i = 0; i < CE_COUNT; i++) { + for (i = 0; i < ab->hw_params.ce_count; i++) { if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; @@ -421,7 +421,7 @@ static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab) { int i; - for (i = 0; i < CE_COUNT; i++) { + for (i = 0; i < ab->hw_params.ce_count; i++) { if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; ath11k_pci_ce_irq_disable(ab, i); @@ -433,7 +433,7 @@ static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab) int i; int irq_idx; - for (i = 0; i < CE_COUNT; i++) { + for (i = 0; i < ab->hw_params.ce_count; i++) { if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; @@ -477,7 +477,7 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab) return ret; /* Configure CE irqs */ - for (i = 0; i < CE_COUNT; i++) { + for (i = 0; i < ab->hw_params.ce_count; i++) { msi_data = (i % msi_data_count) + msi_irq_start; irq = ath11k_pci_get_msi_irq(ab->dev, msi_data); ce_pipe = &ab->ce.ce_pipe[i]; @@ -521,7 +521,7 @@ static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab) { int i; - for (i = 0; i < CE_COUNT; i++) { + for (i = 0; i < ab->hw_params.ce_count; i++) { if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; ath11k_pci_ce_irq_enable(ab, i); @@ -680,7 +680,7 @@ static void ath11k_pci_kill_tasklets(struct ath11k_base *ab) { int i; - for (i = 0; i < CE_COUNT; i++) { + for (i = 0; i < ab->hw_params.ce_count; i++) { struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) -- cgit v1.2.3 From 7cea7c5b0e7b3012c0e4e340292f7624b1dad402 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Mon, 17 Aug 2020 13:31:49 +0300 Subject: ath11k: hal: assign msi_addr and msi_data to srng QCA6390 uses MSI interrupt so it needs msi_addr and msi_data to generate interrupt. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597576599-8857-7-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/hal.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index 7dcdcc1a72fb..5cd948f55b95 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -985,6 +985,8 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type, params->intr_batch_cntr_thres_entries; srng->intr_timer_thres_us = params->intr_timer_thres_us; srng->flags = params->flags; + srng->msi_addr = params->msi_addr; + srng->msi_data = params->msi_data; srng->initialized = 1; spin_lock_init(&srng->lock); -- cgit v1.2.3 From 1a05ed37c513f63c8a56698df3f5fb54c682af12 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Mon, 17 Aug 2020 13:31:50 +0300 Subject: ath11k: ce: get msi_addr and msi_data before srng setup Move function to get msi_addr and msi_data before srng setup, otherwise srng is setup with no MSI configuration. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597576599-8857-8-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/ce.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index 41c1a6e56596..b2da1f937478 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c @@ -467,6 +467,9 @@ static int ath11k_ce_init_ring(struct ath11k_base *ab, params.ring_base_vaddr = ce_ring->base_addr_owner_space; params.num_entries = ce_ring->nentries; + if (!(CE_ATTR_DIS_INTR & ab->hw_params.host_ce_config[ce_id].flags)) + ath11k_ce_srng_msi_ring_params_setup(ab, ce_id, ¶ms); + switch (type) { case HAL_CE_SRC: if (!(CE_ATTR_DIS_INTR & ab->hw_params.host_ce_config[ce_id].flags)) @@ -500,9 +503,6 @@ static int ath11k_ce_init_ring(struct ath11k_base *ab, return ret; } - if (!(CE_ATTR_DIS_INTR & ab->hw_params.host_ce_config[ce_id].flags)) - ath11k_ce_srng_msi_ring_params_setup(ab, ce_id, ¶ms); - ce_ring->hal_ring_id = ret; return 0; -- cgit v1.2.3 From e5c860e121c2e415354d7ae0626f04cbef966851 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Mon, 17 Aug 2020 13:31:50 +0300 Subject: ath11k: disable CE interrupt before hif start Disable CE interrupt otherwise interrupt may come before host initialized related context. This also fixes unbalanced interrupt enablement. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597576599-8857-9-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 37bd385348c3..2b5a8d3162d0 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -500,6 +500,7 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab) } ab->irq_num[irq_idx] = irq; + ath11k_pci_ce_irq_disable(ab, i); } return 0; -- cgit v1.2.3 From 5f859bc02c7bc7a4094bfba0b4ed145edd7661f2 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Mon, 17 Aug 2020 13:31:50 +0300 Subject: ath11k: force single pdev only for QCA6390 For QCA6390, only one pdev is created and only one HW is registered to mac80211. This one pdev manages both 2G radio and 5G radio. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597576599-8857-10-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/core.c | 2 + drivers/net/wireless/ath/ath11k/core.h | 1 + drivers/net/wireless/ath/ath11k/hw.h | 2 + drivers/net/wireless/ath/ath11k/mac.c | 33 +++++++++++++ drivers/net/wireless/ath/ath11k/wmi.c | 86 ++++++++++++++++++++++++---------- 5 files changed, 98 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index c55c886f6276..62fac8bbf221 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -35,6 +35,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .regs = &ipq8074_regs, .host_ce_config = ath11k_host_ce_config_ipq8074, .ce_count = 12, + .single_pdev_only = false, }, { .name = "qca6390 hw2.0", @@ -52,6 +53,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .regs = &qca6390_regs, .host_ce_config = ath11k_host_ce_config_qca6390, .ce_count = 9, + .single_pdev_only = true, }, }; diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 6e351e7bded8..48bf2954c97c 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -545,6 +545,7 @@ struct ath11k { }; struct ath11k_band_cap { + u32 phy_id; u32 max_bw_supported; u32 ht_cap_info; u32 he_cap_info[2]; diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index ef553bafa158..3dcd05ceeef7 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -139,6 +139,8 @@ struct ath11k_hw_params { const struct ath11k_hw_regs *regs; const struct ce_attr *host_ce_config; u32 ce_count; + + bool single_pdev_only; }; extern const struct ath11k_hw_ops ipq8074_ops; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 0fd1f714429c..ec68b5eea847 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -521,6 +521,11 @@ struct ath11k *ath11k_mac_get_ar_by_pdev_id(struct ath11k_base *ab, u32 pdev_id) int i; struct ath11k_pdev *pdev; + if (ab->hw_params.single_pdev_only) { + pdev = rcu_dereference(ab->pdevs_active[0]); + return pdev ? pdev->ar : NULL; + } + if (WARN_ON(pdev_id > ab->num_radios)) return NULL; @@ -5821,12 +5826,29 @@ static void ath11k_mac_update_ch_list(struct ath11k *ar, } } +static u32 ath11k_get_phy_id(struct ath11k *ar, u32 band) +{ + struct ath11k_pdev *pdev = ar->pdev; + struct ath11k_pdev_cap *pdev_cap = &pdev->cap; + + if (band == WMI_HOST_WLAN_2G_CAP) + return pdev_cap->band[NL80211_BAND_2GHZ].phy_id; + + if (band == WMI_HOST_WLAN_5G_CAP) + return pdev_cap->band[NL80211_BAND_5GHZ].phy_id; + + ath11k_warn(ar->ab, "unsupported phy cap:%d\n", band); + + return 0; +} + static int ath11k_mac_setup_channels_rates(struct ath11k *ar, u32 supported_bands) { struct ieee80211_supported_band *band; struct ath11k_hal_reg_capabilities_ext *reg_cap; void *channels; + u32 phy_id; BUILD_BUG_ON((ARRAY_SIZE(ath11k_2ghz_channels) + ARRAY_SIZE(ath11k_5ghz_channels) + @@ -5849,6 +5871,11 @@ static int ath11k_mac_setup_channels_rates(struct ath11k *ar, band->n_bitrates = ath11k_g_rates_size; band->bitrates = ath11k_g_rates; ar->hw->wiphy->bands[NL80211_BAND_2GHZ] = band; + + if (ar->ab->hw_params.single_pdev_only) { + phy_id = ath11k_get_phy_id(ar, WMI_HOST_WLAN_2G_CAP); + reg_cap = &ar->ab->hal_reg_cap[phy_id]; + } ath11k_mac_update_ch_list(ar, band, reg_cap->low_2ghz_chan, reg_cap->high_2ghz_chan); @@ -5893,6 +5920,12 @@ static int ath11k_mac_setup_channels_rates(struct ath11k *ar, band->n_bitrates = ath11k_a_rates_size; band->bitrates = ath11k_a_rates; ar->hw->wiphy->bands[NL80211_BAND_5GHZ] = band; + + if (ar->ab->hw_params.single_pdev_only) { + phy_id = ath11k_get_phy_id(ar, WMI_HOST_WLAN_5G_CAP); + reg_cap = &ar->ab->hal_reg_cap[phy_id]; + } + ath11k_mac_update_ch_list(ar, band, reg_cap->low_5ghz_chan, reg_cap->high_5ghz_chan); diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index cd1bdb2a75c9..c43f54a7c54d 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -338,7 +338,7 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(struct ath11k_pdev_wmi *wmi_handle, mac_phy_caps = wmi_mac_phy_caps + phy_idx; pdev->pdev_id = mac_phy_caps->pdev_id; - pdev_cap->supported_bands = mac_phy_caps->supported_bands; + pdev_cap->supported_bands |= mac_phy_caps->supported_bands; pdev_cap->ampdu_density = mac_phy_caps->ampdu_density; /* Take non-zero tx/rx chainmask. If tx/rx chainmask differs from @@ -371,27 +371,33 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(struct ath11k_pdev_wmi *wmi_handle, pdev_cap->rx_chain_mask_shift = find_first_bit((unsigned long *)&pdev_cap->rx_chain_mask, 32); - cap_band = &pdev_cap->band[NL80211_BAND_2GHZ]; - cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_2g; - cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_2g; - cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_2g; - cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_2g_ext; - cap_band->he_mcs = mac_phy_caps->he_supp_mcs_2g; - memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_2g, - sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE); - memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet2g, - sizeof(struct ath11k_ppe_threshold)); - - cap_band = &pdev_cap->band[NL80211_BAND_5GHZ]; - cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_5g; - cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_5g; - cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_5g; - cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_5g_ext; - cap_band->he_mcs = mac_phy_caps->he_supp_mcs_5g; - memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_5g, - sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE); - memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet5g, - sizeof(struct ath11k_ppe_threshold)); + if (mac_phy_caps->supported_bands & WMI_HOST_WLAN_2G_CAP) { + cap_band = &pdev_cap->band[NL80211_BAND_2GHZ]; + cap_band->phy_id = mac_phy_caps->phy_id; + cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_2g; + cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_2g; + cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_2g; + cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_2g_ext; + cap_band->he_mcs = mac_phy_caps->he_supp_mcs_2g; + memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_2g, + sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE); + memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet2g, + sizeof(struct ath11k_ppe_threshold)); + } + + if (mac_phy_caps->supported_bands & WMI_HOST_WLAN_5G_CAP) { + cap_band = &pdev_cap->band[NL80211_BAND_5GHZ]; + cap_band->phy_id = mac_phy_caps->phy_id; + cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_5g; + cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_5g; + cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_5g; + cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_5g_ext; + cap_band->he_mcs = mac_phy_caps->he_supp_mcs_5g; + memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_5g, + sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE); + memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet5g, + sizeof(struct ath11k_ppe_threshold)); + } cap_band = &pdev_cap->band[NL80211_BAND_6GHZ]; cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_5g; @@ -3388,7 +3394,8 @@ int ath11k_wmi_cmd_init(struct ath11k_base *ab) init_param.hw_mode_id = wmi_sc->preferred_hw_mode; init_param.mem_chunks = wmi_sc->mem_chunks; - if (wmi_sc->preferred_hw_mode == WMI_HOST_HW_MODE_SINGLE) + if (wmi_sc->preferred_hw_mode == WMI_HOST_HW_MODE_SINGLE || + ab->hw_params.single_pdev_only) init_param.hw_mode_id = WMI_HOST_HW_MODE_MAX; init_param.num_band_to_mac = ab->num_radios; @@ -3688,6 +3695,8 @@ static int ath11k_wmi_tlv_hw_mode_caps(struct ath11k_base *soc, i++; } + ath11k_dbg(soc, ATH11K_DBG_WMI, "preferred_hw_mode:%d\n", + soc->wmi_ab.preferred_hw_mode); if (soc->wmi_ab.preferred_hw_mode == WMI_HOST_HW_MODE_MAX) return -EINVAL; @@ -3778,6 +3787,7 @@ static int ath11k_wmi_tlv_ext_soc_hal_reg_caps_parse(struct ath11k_base *soc, struct wmi_tlv_svc_rdy_ext_parse *svc_rdy_ext = data; u8 hw_mode_id = svc_rdy_ext->pref_hw_mode_caps.hw_mode_id; u32 phy_id_map; + int pdev_index = 0; int ret; svc_rdy_ext->soc_hal_reg_caps = (struct wmi_soc_hal_reg_capabilities *)ptr; @@ -3793,7 +3803,7 @@ static int ath11k_wmi_tlv_ext_soc_hal_reg_caps_parse(struct ath11k_base *soc, svc_rdy_ext->soc_hal_reg_caps, svc_rdy_ext->mac_phy_caps, hw_mode_id, soc->num_radios, - &soc->pdevs[soc->num_radios]); + &soc->pdevs[pdev_index]); if (ret) { ath11k_warn(soc, "failed to extract mac caps, idx :%d\n", soc->num_radios); @@ -3802,9 +3812,25 @@ static int ath11k_wmi_tlv_ext_soc_hal_reg_caps_parse(struct ath11k_base *soc, soc->num_radios++; + /* For QCA6390, save mac_phy capability in the same pdev */ + if (soc->hw_params.single_pdev_only) + pdev_index = 0; + else + pdev_index = soc->num_radios; + /* TODO: mac_phy_cap prints */ phy_id_map >>= 1; } + + /* For QCA6390, set num_radios to 1 because host manages + * both 2G and 5G radio in one pdev. + * Set pdev_id = 0 and 0 means soc level. + */ + if (soc->hw_params.single_pdev_only) { + soc->num_radios = 1; + soc->pdevs[0].pdev_id = 0; + } + return 0; } @@ -5434,8 +5460,12 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *sk pdev_idx = reg_info->phy_id; - if (pdev_idx >= ab->num_radios) - goto fallback; + if (pdev_idx >= ab->num_radios) { + if (ab->hw_params.single_pdev_only) + goto mem_free; + else + goto fallback; + } /* Avoid multiple overwrites to default regd, during core * stop-start after mac registration. @@ -6728,6 +6758,10 @@ int ath11k_wmi_attach(struct ath11k_base *ab) ab->wmi_ab.ab = ab; ab->wmi_ab.preferred_hw_mode = WMI_HOST_HW_MODE_MAX; + /* It's overwritten when service_ext_ready is handled */ + if (ab->hw_params.single_pdev_only) + ab->wmi_ab.preferred_hw_mode = WMI_HOST_HW_MODE_SINGLE; + /* TODO: Init remaining wmi soc resources required */ init_completion(&ab->wmi_ab.service_ready); init_completion(&ab->wmi_ab.unified_ready); -- cgit v1.2.3 From 2d4bcbed5b7d53e19fc158885e7340b464b64507 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Mon, 17 Aug 2020 13:31:51 +0300 Subject: ath11k: initialize wmi config based on hw_params QCA6390 has very different wmi config parameters compared to IPQ8074, so use different function to initialize wmi init config parameters. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597576599-8857-11-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/hw.c | 98 +++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/hw.h | 4 ++ drivers/net/wireless/ath/ath11k/wmi.c | 4 +- 3 files changed, 105 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index 5811eabf2275..338b784b0e84 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -31,12 +31,110 @@ static u8 ath11k_hw_ipq6018_mac_from_pdev_id(int pdev_idx) return pdev_idx; } +static void ath11k_init_wmi_config_qca6390(struct ath11k_base *ab, + struct target_resource_config *config) +{ + config->num_vdevs = 4; + config->num_peers = 16; + config->num_tids = 32; + + config->num_offload_peers = 3; + config->num_offload_reorder_buffs = 3; + config->num_peer_keys = TARGET_NUM_PEER_KEYS; + config->ast_skid_limit = TARGET_AST_SKID_LIMIT; + config->tx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1; + config->rx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1; + config->rx_timeout_pri[0] = TARGET_RX_TIMEOUT_LO_PRI; + config->rx_timeout_pri[1] = TARGET_RX_TIMEOUT_LO_PRI; + config->rx_timeout_pri[2] = TARGET_RX_TIMEOUT_LO_PRI; + config->rx_timeout_pri[3] = TARGET_RX_TIMEOUT_HI_PRI; + config->rx_decap_mode = TARGET_DECAP_MODE_NATIVE_WIFI; + config->scan_max_pending_req = TARGET_SCAN_MAX_PENDING_REQS; + config->bmiss_offload_max_vdev = TARGET_BMISS_OFFLOAD_MAX_VDEV; + config->roam_offload_max_vdev = TARGET_ROAM_OFFLOAD_MAX_VDEV; + config->roam_offload_max_ap_profiles = TARGET_ROAM_OFFLOAD_MAX_AP_PROFILES; + config->num_mcast_groups = 0; + config->num_mcast_table_elems = 0; + config->mcast2ucast_mode = 0; + config->tx_dbg_log_size = TARGET_TX_DBG_LOG_SIZE; + config->num_wds_entries = 0; + config->dma_burst_size = 0; + config->rx_skip_defrag_timeout_dup_detection_check = 0; + config->vow_config = TARGET_VOW_CONFIG; + config->gtk_offload_max_vdev = 2; + config->num_msdu_desc = 0x400; + config->beacon_tx_offload_max_vdev = 2; + config->rx_batchmode = TARGET_RX_BATCHMODE; + + config->peer_map_unmap_v2_support = 0; + config->use_pdev_id = 1; + config->max_frag_entries = 0xa; + config->num_tdls_vdevs = 0x1; + config->num_tdls_conn_table_entries = 8; + config->beacon_tx_offload_max_vdev = 0x2; + config->num_multicast_filter_entries = 0x20; + config->num_wow_filters = 0x16; + config->num_keep_alive_pattern = 0x1; + config->num_keep_alive_pattern = 0; +} + +static void ath11k_init_wmi_config_ipq8074(struct ath11k_base *ab, + struct target_resource_config *config) +{ + config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS; + + if (ab->num_radios == 2) { + config->num_peers = TARGET_NUM_PEERS(DBS); + config->num_tids = TARGET_NUM_TIDS(DBS); + } else if (ab->num_radios == 3) { + config->num_peers = TARGET_NUM_PEERS(DBS_SBS); + config->num_tids = TARGET_NUM_TIDS(DBS_SBS); + } else { + /* Control should not reach here */ + config->num_peers = TARGET_NUM_PEERS(SINGLE); + config->num_tids = TARGET_NUM_TIDS(SINGLE); + } + config->num_offload_peers = TARGET_NUM_OFFLD_PEERS; + config->num_offload_reorder_buffs = TARGET_NUM_OFFLD_REORDER_BUFFS; + config->num_peer_keys = TARGET_NUM_PEER_KEYS; + config->ast_skid_limit = TARGET_AST_SKID_LIMIT; + config->tx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1; + config->rx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1; + config->rx_timeout_pri[0] = TARGET_RX_TIMEOUT_LO_PRI; + config->rx_timeout_pri[1] = TARGET_RX_TIMEOUT_LO_PRI; + config->rx_timeout_pri[2] = TARGET_RX_TIMEOUT_LO_PRI; + config->rx_timeout_pri[3] = TARGET_RX_TIMEOUT_HI_PRI; + config->rx_decap_mode = TARGET_DECAP_MODE_NATIVE_WIFI; + config->scan_max_pending_req = TARGET_SCAN_MAX_PENDING_REQS; + config->bmiss_offload_max_vdev = TARGET_BMISS_OFFLOAD_MAX_VDEV; + config->roam_offload_max_vdev = TARGET_ROAM_OFFLOAD_MAX_VDEV; + config->roam_offload_max_ap_profiles = TARGET_ROAM_OFFLOAD_MAX_AP_PROFILES; + config->num_mcast_groups = TARGET_NUM_MCAST_GROUPS; + config->num_mcast_table_elems = TARGET_NUM_MCAST_TABLE_ELEMS; + config->mcast2ucast_mode = TARGET_MCAST2UCAST_MODE; + config->tx_dbg_log_size = TARGET_TX_DBG_LOG_SIZE; + config->num_wds_entries = TARGET_NUM_WDS_ENTRIES; + config->dma_burst_size = TARGET_DMA_BURST_SIZE; + config->rx_skip_defrag_timeout_dup_detection_check = + TARGET_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK; + config->vow_config = TARGET_VOW_CONFIG; + config->gtk_offload_max_vdev = TARGET_GTK_OFFLOAD_MAX_VDEV; + config->num_msdu_desc = TARGET_NUM_MSDU_DESC; + config->beacon_tx_offload_max_vdev = ab->num_radios * TARGET_MAX_BCN_OFFLD; + config->rx_batchmode = TARGET_RX_BATCHMODE; + config->peer_map_unmap_v2_support = 1; + config->twt_ap_pdev_count = 2; + config->twt_ap_sta_count = 1000; +} + const struct ath11k_hw_ops ipq8074_ops = { .get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id, + .wmi_init_config = ath11k_init_wmi_config_qca6390, }; const struct ath11k_hw_ops ipq6018_ops = { .get_hw_mac_from_pdev_id = ath11k_hw_ipq6018_mac_from_pdev_id, + .wmi_init_config = ath11k_init_wmi_config_ipq8074, }; const struct ath11k_hw_ops qca6390_ops = { diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 3dcd05ceeef7..4651aed2eaf0 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -6,6 +6,8 @@ #ifndef ATH11K_HW_H #define ATH11K_HW_H +#include "wmi.h" + /* Target configuration defines */ /* Num VDEVS per radio */ @@ -116,6 +118,8 @@ struct ath11k_hw_ring_mask { struct ath11k_hw_ops { u8 (*get_hw_mac_from_pdev_id)(int pdev_id); + void (*wmi_init_config)(struct ath11k_base *ab, + struct target_resource_config *config); }; struct ath11k_hw_params { diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index c43f54a7c54d..21f9070a1300 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -3181,7 +3181,7 @@ static int ath11k_init_cmd_send(struct ath11k_pdev_wmi *wmi, (param->num_band_to_mac * sizeof(*band_to_mac)); len = sizeof(*cmd) + TLV_HDR_SIZE + sizeof(*cfg) + hw_mode_len + - (sizeof(*host_mem_chunks) * WMI_MAX_MEM_REQS); + (param->num_mem_chunks ? (sizeof(*host_mem_chunks) * WMI_MAX_MEM_REQS) : 0); skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) @@ -3387,6 +3387,8 @@ int ath11k_wmi_cmd_init(struct ath11k_base *ab) config.twt_ap_pdev_count = ab->num_radios; config.twt_ap_sta_count = 1000; + ab->hw_params.hw_ops->wmi_init_config(ab, &config); + memcpy(&wmi_sc->wlan_resource_config, &config, sizeof(config)); init_param.res_cfg = &wmi_sc->wlan_resource_config; -- cgit v1.2.3 From ed0192f7942e4be9f520022278036d0d08b6a856 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Mon, 17 Aug 2020 13:31:51 +0300 Subject: ath11k: wmi: put hardware to DBS mode For QCA6390, host puts hardware to Dual Band Simultaneous (DBS) mode by default so both 2G and 5G bands can be used. Otherwise only the 5G band can be used. QCA6390 doesn't provide band_to_mac configuration and firmware will do the band_to_mac map. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597576599-8857-12-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/core.c | 2 ++ drivers/net/wireless/ath/ath11k/hw.h | 6 ++++++ drivers/net/wireless/ath/ath11k/wmi.c | 10 +++++----- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 62fac8bbf221..b94630822d1e 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -36,6 +36,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .host_ce_config = ath11k_host_ce_config_ipq8074, .ce_count = 12, .single_pdev_only = false, + .needs_band_to_mac = true, }, { .name = "qca6390 hw2.0", @@ -54,6 +55,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .host_ce_config = ath11k_host_ce_config_qca6390, .ce_count = 9, .single_pdev_only = true, + .needs_band_to_mac = false, }, }; diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 4651aed2eaf0..8db9534b176b 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -145,6 +145,12 @@ struct ath11k_hw_params { u32 ce_count; bool single_pdev_only; + + /* For example on QCA6390 struct + * wmi_init_cmd_param::band_to_mac_config needs to be false as the + * firmware creates the mapping. + */ + bool needs_band_to_mac; }; extern const struct ath11k_hw_ops ipq8074_ops; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 21f9070a1300..4e100407fea6 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -3396,13 +3396,13 @@ int ath11k_wmi_cmd_init(struct ath11k_base *ab) init_param.hw_mode_id = wmi_sc->preferred_hw_mode; init_param.mem_chunks = wmi_sc->mem_chunks; - if (wmi_sc->preferred_hw_mode == WMI_HOST_HW_MODE_SINGLE || - ab->hw_params.single_pdev_only) + if (wmi_sc->preferred_hw_mode == WMI_HOST_HW_MODE_SINGLE) init_param.hw_mode_id = WMI_HOST_HW_MODE_MAX; - init_param.num_band_to_mac = ab->num_radios; - - ath11k_fill_band_to_mac_param(ab, init_param.band_to_mac); + if (ab->hw_params.needs_band_to_mac) { + init_param.num_band_to_mac = ab->num_radios; + ath11k_fill_band_to_mac_param(ab, init_param.band_to_mac); + } return ath11k_init_cmd_send(&wmi_sc->wmi[0], &init_param); } -- cgit v1.2.3 From 13ecd81fbad66126700b82f29f8259d338f9bc2a Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Mon, 17 Aug 2020 13:31:52 +0300 Subject: ath11k: dp: redefine peer_map and peer_unmap For QCA6390, it uses peer_map and peer_unmap V1. IPQ8074 uses V2. Redefine previous definition to peer_map2 and peer_unmap2. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597576599-8857-13-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/dp.h | 6 ++++-- drivers/net/wireless/ath/ath11k/dp_rx.c | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h index 7587862d2e32..07876fd521f7 100644 --- a/drivers/net/wireless/ath/ath11k/dp.h +++ b/drivers/net/wireless/ath/ath11k/dp.h @@ -936,11 +936,13 @@ struct htt_rx_ring_tlv_filter { enum htt_t2h_msg_type { HTT_T2H_MSG_TYPE_VERSION_CONF, + HTT_T2H_MSG_TYPE_PEER_MAP = 0x3, + HTT_T2H_MSG_TYPE_PEER_UNMAP = 0x4, HTT_T2H_MSG_TYPE_RX_ADDBA = 0x5, HTT_T2H_MSG_TYPE_PKTLOG = 0x8, HTT_T2H_MSG_TYPE_SEC_IND = 0xb, - HTT_T2H_MSG_TYPE_PEER_MAP = 0x1e, - HTT_T2H_MSG_TYPE_PEER_UNMAP = 0x1f, + HTT_T2H_MSG_TYPE_PEER_MAP2 = 0x1e, + HTT_T2H_MSG_TYPE_PEER_UNMAP2 = 0x1f, HTT_T2H_MSG_TYPE_PPDU_STATS_IND = 0x1d, HTT_T2H_MSG_TYPE_EXT_STATS_CONF = 0x1c, HTT_T2H_MSG_TYPE_BKPRESSURE_EVENT_IND = 0x24, diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 66002de04aec..6009c26ce525 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -1569,6 +1569,7 @@ void ath11k_dp_htt_htc_t2h_msg_handler(struct ath11k_base *ab, complete(&dp->htt_tgt_version_received); break; case HTT_T2H_MSG_TYPE_PEER_MAP: + case HTT_T2H_MSG_TYPE_PEER_MAP2: vdev_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_VDEV_ID, resp->peer_map_ev.info); peer_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_PEER_ID, @@ -1582,6 +1583,7 @@ void ath11k_dp_htt_htc_t2h_msg_handler(struct ath11k_base *ab, ath11k_peer_map_event(ab, vdev_id, peer_id, mac_addr, ast_hash); break; case HTT_T2H_MSG_TYPE_PEER_UNMAP: + case HTT_T2H_MSG_TYPE_PEER_UNMAP2: peer_id = FIELD_GET(HTT_T2H_PEER_UNMAP_INFO_PEER_ID, resp->peer_unmap_ev.info); ath11k_peer_unmap_event(ab, peer_id); -- cgit v1.2.3 From d4ecb90b3857db23c83b2578f1fa0341c5e00b82 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Mon, 17 Aug 2020 13:31:52 +0300 Subject: ath11k: enable DP interrupt setup for QCA6390 QCA6390 uses MSI interrupt, so need to configure msi_add and msi_data to dp srngs. As there are so many DP srngs, so need to group them. Each group shares one MSI interrupt. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597555891-26112-2-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/core.c | 2 +- drivers/net/wireless/ath/ath11k/dp.c | 108 ++++++++++++++++++++ drivers/net/wireless/ath/ath11k/hw.c | 37 +++++++ drivers/net/wireless/ath/ath11k/hw.h | 1 + drivers/net/wireless/ath/ath11k/pci.c | 175 +++++++++++++++++++++++++++++++++ 5 files changed, 322 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index b94630822d1e..45d16f7ad461 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -49,7 +49,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .max_radios = 3, .bdf_addr = 0x4B0C0000, .hw_ops = &qca6390_ops, - .ring_mask = &ath11k_hw_ring_mask_ipq8074, + .ring_mask = &ath11k_hw_ring_mask_qca6390, .internal_sleep_clock = true, .regs = &qca6390_regs, .host_ce_config = ath11k_host_ce_config_qca6390, diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index a3c4d36f850d..ac92f345a013 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -107,6 +107,113 @@ void ath11k_dp_srng_cleanup(struct ath11k_base *ab, struct dp_srng *ring) ring->vaddr_unaligned = NULL; } +static int ath11k_dp_srng_find_ring_in_mask(int ring_num, const u8 *grp_mask) +{ + int ext_group_num; + u8 mask = 1 << ring_num; + + for (ext_group_num = 0; ext_group_num < ATH11K_EXT_IRQ_GRP_NUM_MAX; + ext_group_num++) { + if (mask & grp_mask[ext_group_num]) + return ext_group_num; + } + + return -ENOENT; +} + +static int ath11k_dp_srng_calculate_msi_group(struct ath11k_base *ab, + enum hal_ring_type type, int ring_num) +{ + const u8 *grp_mask; + + switch (type) { + case HAL_WBM2SW_RELEASE: + if (ring_num < 3) { + grp_mask = &ab->hw_params.ring_mask->tx[0]; + } else if (ring_num == 3) { + grp_mask = &ab->hw_params.ring_mask->rx_wbm_rel[0]; + ring_num = 0; + } else { + return -ENOENT; + } + break; + case HAL_REO_EXCEPTION: + grp_mask = &ab->hw_params.ring_mask->rx_err[0]; + break; + case HAL_REO_DST: + grp_mask = &ab->hw_params.ring_mask->rx[0]; + break; + case HAL_REO_STATUS: + grp_mask = &ab->hw_params.ring_mask->reo_status[0]; + break; + case HAL_RXDMA_MONITOR_STATUS: + case HAL_RXDMA_MONITOR_DST: + grp_mask = &ab->hw_params.ring_mask->rx_mon_status[0]; + break; + case HAL_RXDMA_DST: + grp_mask = &ab->hw_params.ring_mask->rxdma2host[0]; + break; + case HAL_RXDMA_BUF: + grp_mask = &ab->hw_params.ring_mask->host2rxdma[0]; + break; + case HAL_RXDMA_MONITOR_BUF: + case HAL_TCL_DATA: + case HAL_TCL_CMD: + case HAL_REO_CMD: + case HAL_SW2WBM_RELEASE: + case HAL_WBM_IDLE_LINK: + case HAL_TCL_STATUS: + case HAL_REO_REINJECT: + case HAL_CE_SRC: + case HAL_CE_DST: + case HAL_CE_DST_STATUS: + default: + return -ENOENT; + } + + return ath11k_dp_srng_find_ring_in_mask(ring_num, grp_mask); +} + +static void ath11k_dp_srng_msi_setup(struct ath11k_base *ab, + struct hal_srng_params *ring_params, + enum hal_ring_type type, int ring_num) +{ + int msi_group_number, msi_data_count; + u32 msi_data_start, msi_irq_start, addr_lo, addr_hi; + int ret; + + ret = ath11k_get_user_msi_vector(ab, "DP", + &msi_data_count, &msi_data_start, + &msi_irq_start); + if (ret) + return; + + msi_group_number = ath11k_dp_srng_calculate_msi_group(ab, type, + ring_num); + if (msi_group_number < 0) { + ath11k_dbg(ab, ATH11K_DBG_PCI, + "ring not part of an ext_group; ring_type: %d,ring_num %d", + type, ring_num); + ring_params->msi_addr = 0; + ring_params->msi_data = 0; + return; + } + + if (msi_group_number > msi_data_count) { + ath11k_dbg(ab, ATH11K_DBG_PCI, + "multiple msi_groups share one msi, msi_group_num %d", + msi_group_number); + } + + ath11k_get_msi_address(ab, &addr_lo, &addr_hi); + + ring_params->msi_addr = addr_lo; + ring_params->msi_addr |= (dma_addr_t)(((uint64_t)addr_hi) << 32); + ring_params->msi_data = (msi_group_number % msi_data_count) + + msi_data_start; + ring_params->flags |= HAL_SRNG_FLAGS_MSI_INTR; +} + int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, enum hal_ring_type type, int ring_num, int mac_id, int num_entries) @@ -136,6 +243,7 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, params.ring_base_vaddr = ring->vaddr; params.ring_base_paddr = ring->paddr; params.num_entries = num_entries; + ath11k_dp_srng_msi_setup(ab, ¶ms, type, ring_num + mac_id); switch (type) { case HAL_REO_DST: diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index 338b784b0e84..9737b9f5e1b5 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -208,6 +208,43 @@ const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq8074 = { }, }; +const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qca6390 = { + .tx = { + ATH11K_TX_RING_MASK_0, + ATH11K_TX_RING_MASK_1, + ATH11K_TX_RING_MASK_2, + }, + .rx_mon_status = { + 0, 0, 0, 0, + ATH11K_RX_MON_STATUS_RING_MASK_0, + ATH11K_RX_MON_STATUS_RING_MASK_1, + ATH11K_RX_MON_STATUS_RING_MASK_2, + }, + .rx = { + 0, 0, 0, 0, 0, 0, 0, + ATH11K_RX_RING_MASK_0, + ATH11K_RX_RING_MASK_1, + ATH11K_RX_RING_MASK_2, + ATH11K_RX_RING_MASK_3, + }, + .rx_err = { + ATH11K_RX_ERR_RING_MASK_0, + }, + .rx_wbm_rel = { + ATH11K_RX_WBM_REL_RING_MASK_0, + }, + .reo_status = { + ATH11K_REO_STATUS_RING_MASK_0, + }, + .rxdma2host = { + ATH11K_RXDMA2HOST_RING_MASK_0, + ATH11K_RXDMA2HOST_RING_MASK_1, + ATH11K_RXDMA2HOST_RING_MASK_2, + }, + .host2rxdma = { + }, +}; + const struct ath11k_hw_regs ipq8074_regs = { /* SW2TCL(x) R0 ring configuration address */ .hal_tcl1_ring_base_lsb = 0x00000510, diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 8db9534b176b..1c9176273883 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -158,6 +158,7 @@ extern const struct ath11k_hw_ops ipq6018_ops; extern const struct ath11k_hw_ops qca6390_ops; extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq8074; +extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qca6390; static inline int ath11k_hw_get_mac_from_pdev_id(struct ath11k_hw_params *hw, diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 2b5a8d3162d0..6a1e74f0d1ac 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -389,6 +389,20 @@ static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_nam base_vector); } +static void ath11k_pci_free_ext_irq(struct ath11k_base *ab) +{ + int i, j; + + for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { + struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; + + for (j = 0; j < irq_grp->num_irq; j++) + free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); + + netif_napi_del(&irq_grp->napi); + } +} + static void ath11k_pci_free_irq(struct ath11k_base *ab) { int i, irq_idx; @@ -399,6 +413,8 @@ static void ath11k_pci_free_irq(struct ath11k_base *ab) irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); } + + ath11k_pci_free_ext_irq(ab); } static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) @@ -461,6 +477,159 @@ static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) return IRQ_HANDLED; } +static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp) +{ + int i; + + for (i = 0; i < irq_grp->num_irq; i++) + disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); +} + +static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc) +{ + int i; + + for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { + struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i]; + + ath11k_pci_ext_grp_disable(irq_grp); + + napi_synchronize(&irq_grp->napi); + napi_disable(&irq_grp->napi); + } +} + +static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp) +{ + int i; + + for (i = 0; i < irq_grp->num_irq; i++) + enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); +} + +static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab) +{ + int i; + + for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { + struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; + + napi_enable(&irq_grp->napi); + ath11k_pci_ext_grp_enable(irq_grp); + } +} + +static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab) +{ + int i, j, irq_idx; + + for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { + struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; + + for (j = 0; j < irq_grp->num_irq; j++) { + irq_idx = irq_grp->irqs[j]; + synchronize_irq(ab->irq_num[irq_idx]); + } + } +} + +static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab) +{ + __ath11k_pci_ext_irq_disable(ab); + ath11k_pci_sync_ext_irqs(ab); +} + +static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) +{ + struct ath11k_ext_irq_grp *irq_grp = container_of(napi, + struct ath11k_ext_irq_grp, + napi); + struct ath11k_base *ab = irq_grp->ab; + int work_done; + + work_done = ath11k_dp_service_srng(ab, irq_grp, budget); + if (work_done < budget) { + napi_complete_done(napi, work_done); + ath11k_pci_ext_grp_enable(irq_grp); + } + + if (work_done > budget) + work_done = budget; + + return work_done; +} + +static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg) +{ + struct ath11k_ext_irq_grp *irq_grp = arg; + + ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq); + + ath11k_pci_ext_grp_disable(irq_grp); + + napi_schedule(&irq_grp->napi); + + return IRQ_HANDLED; +} + +static int ath11k_pci_ext_irq_config(struct ath11k_base *ab) +{ + int i, j, ret, num_vectors = 0; + u32 user_base_data = 0, base_vector = 0; + + ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP", + &num_vectors, &user_base_data, + &base_vector); + + for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { + struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; + u32 num_irq = 0; + + irq_grp->ab = ab; + irq_grp->grp_id = i; + init_dummy_netdev(&irq_grp->napi_ndev); + netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, + ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT); + + if (ab->hw_params.ring_mask->tx[i] || + ab->hw_params.ring_mask->rx[i] || + ab->hw_params.ring_mask->rx_err[i] || + ab->hw_params.ring_mask->rx_wbm_rel[i] || + ab->hw_params.ring_mask->reo_status[i] || + ab->hw_params.ring_mask->rxdma2host[i] || + ab->hw_params.ring_mask->host2rxdma[i] || + ab->hw_params.ring_mask->rx_mon_status[i]) { + num_irq = 1; + } + + irq_grp->num_irq = num_irq; + irq_grp->irqs[0] = base_vector + i; + + for (j = 0; j < irq_grp->num_irq; j++) { + int irq_idx = irq_grp->irqs[j]; + int vector = (i % num_vectors) + base_vector; + int irq = ath11k_pci_get_msi_irq(ab->dev, vector); + + ab->irq_num[irq_idx] = irq; + + ath11k_dbg(ab, ATH11K_DBG_PCI, + "irq:%d group:%d\n", irq, i); + ret = request_irq(irq, ath11k_pci_ext_interrupt_handler, + IRQF_SHARED, + "DP_EXT_IRQ", irq_grp); + if (ret) { + ath11k_err(ab, "failed request irq %d: %d\n", + vector, ret); + return ret; + } + + disable_irq_nosync(ab->irq_num[irq_idx]); + } + } + + return 0; +} + static int ath11k_pci_config_irq(struct ath11k_base *ab) { struct ath11k_ce_pipe *ce_pipe; @@ -503,6 +672,10 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab) ath11k_pci_ce_irq_disable(ab, i); } + ret = ath11k_pci_ext_irq_config(ab); + if (ret) + return ret; + return 0; } @@ -757,6 +930,8 @@ static const struct ath11k_hif_ops ath11k_pci_hif_ops = { .write32 = ath11k_pci_write32, .power_down = ath11k_pci_power_down, .power_up = ath11k_pci_power_up, + .irq_enable = ath11k_pci_ext_irq_enable, + .irq_disable = ath11k_pci_ext_irq_disable, .get_msi_address = ath11k_pci_get_msi_address, .get_user_msi_vector = ath11k_get_user_msi_assignment, .map_service_to_pipe = ath11k_pci_map_service_to_pipe, -- cgit v1.2.3 From 7f6fc1ebf5b19850e6035de16032f7d81dee65d8 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Mon, 17 Aug 2020 13:31:52 +0300 Subject: ath11k: don't initialize rxdma1 related ring For QCA6390, it has 2 lmacs and thus 2 rxdmas. However, each rxdma has rxdma0 only, and doesn't have rxdma1. So for QCA6390, don't initialize rxdma1 related rings such as rx_mon_buf_ring, rx_mon_dst_ring and rx_mon_desc_ring. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597555891-26112-3-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/core.c | 2 ++ drivers/net/wireless/ath/ath11k/dp_rx.c | 34 +++++++++++++++++++++++++++++++-- drivers/net/wireless/ath/ath11k/hw.h | 2 ++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 45d16f7ad461..8e9bf0e64a68 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -37,6 +37,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .ce_count = 12, .single_pdev_only = false, .needs_band_to_mac = true, + .rxdma1_enable = true, }, { .name = "qca6390 hw2.0", @@ -56,6 +57,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .ce_count = 9, .single_pdev_only = true, .needs_band_to_mac = false, + .rxdma1_enable = false, }, }; diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 6009c26ce525..64aa0077a45d 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -375,6 +375,12 @@ static int ath11k_dp_rxdma_buf_ring_free(struct ath11k *ar, idr_destroy(&rx_ring->bufs_idr); spin_unlock_bh(&rx_ring->idr_lock); + /* if rxdma1_enable is false, mon_status_refill_ring + * isn't setup, so don't clean. + */ + if (!ar->ab->hw_params.rxdma1_enable) + return 0; + rx_ring = &dp->rx_mon_status_refill_ring; spin_lock_bh(&rx_ring->idr_lock); @@ -390,6 +396,7 @@ static int ath11k_dp_rxdma_buf_ring_free(struct ath11k *ar, idr_destroy(&rx_ring->bufs_idr); spin_unlock_bh(&rx_ring->idr_lock); + return 0; } @@ -431,8 +438,10 @@ static int ath11k_dp_rxdma_pdev_buf_setup(struct ath11k *ar) ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_BUF); - rx_ring = &dp->rxdma_mon_buf_ring; - ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_BUF); + if (ar->ab->hw_params.rxdma1_enable) { + rx_ring = &dp->rxdma_mon_buf_ring; + ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_BUF); + } rx_ring = &dp->rx_mon_status_refill_ring; ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_STATUS); @@ -516,6 +525,14 @@ static int ath11k_dp_rx_pdev_srng_alloc(struct ath11k *ar) "failed to setup rx_mon_status_refill_ring\n"); return ret; } + + /* if rxdma1_enable is false, then it doesn't need + * to setup rxdam_mon_buf_ring, rxdma_mon_dst_ring + * and rxdma_mon_desc_ring. + */ + if (!ar->ab->hw_params.rxdma1_enable) + return 0; + ret = ath11k_dp_srng_setup(ar->ab, &dp->rxdma_mon_buf_ring.refill_buf_ring, HAL_RXDMA_MONITOR_BUF, 0, dp->mac_id, @@ -4129,6 +4146,9 @@ int ath11k_dp_rx_pdev_alloc(struct ath11k_base *ab, int mac_id) return ret; } + if (!ab->hw_params.rxdma1_enable) + goto config_refill_ring; + ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id; ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id, HAL_RXDMA_MONITOR_BUF); @@ -4153,6 +4173,8 @@ int ath11k_dp_rx_pdev_alloc(struct ath11k_base *ab, int mac_id) ret); return ret; } + +config_refill_ring: ring_id = dp->rx_mon_status_refill_ring.refill_buf_ring.ring_id; ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id, HAL_RXDMA_MONITOR_STATUS); @@ -4162,6 +4184,7 @@ int ath11k_dp_rx_pdev_alloc(struct ath11k_base *ab, int mac_id) ret); return ret; } + return 0; } @@ -4834,6 +4857,12 @@ int ath11k_dp_rx_pdev_mon_attach(struct ath11k *ar) return ret; } + /* if rxdma1_enable is false, no need to setup + * rxdma_mon_desc_ring. + */ + if (!ar->ab->hw_params.rxdma1_enable) + return 0; + dp_srng = &dp->rxdma_mon_desc_ring; n_link_desc = dp_srng->size / ath11k_hal_srng_get_entrysize(ar->ab, HAL_RXDMA_MONITOR_DESC); @@ -4850,6 +4879,7 @@ int ath11k_dp_rx_pdev_mon_attach(struct ath11k *ar) pmon->mon_last_linkdesc_paddr = 0; pmon->mon_last_buf_cookie = DP_RX_DESC_COOKIE_MAX + 1; spin_lock_init(&pmon->mon_lock); + return 0; } diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 1c9176273883..2e88194da329 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -151,6 +151,8 @@ struct ath11k_hw_params { * firmware creates the mapping. */ bool needs_band_to_mac; + + bool rxdma1_enable; }; extern const struct ath11k_hw_ops ipq8074_ops; -- cgit v1.2.3 From 4152e4206cc5a9dcfd575fc8342e04faa2d9ec53 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Mon, 17 Aug 2020 13:31:53 +0300 Subject: ath11k: setup QCA6390 rings for both rxdmas For QCA6390, only one pdev is created and this pdev manages both lmacs, thus both rxdmas. So host needs to initialize all rxdma related rings for one pdev. Another difference is for QCA6390, host fills rxbuf to firmware and firmware further fills the rxbuf to rxbuf ring for each rxdma. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597555891-26112-4-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/core.c | 4 + drivers/net/wireless/ath/ath11k/core.h | 6 ++ drivers/net/wireless/ath/ath11k/debug.c | 41 ++++---- drivers/net/wireless/ath/ath11k/dp.c | 7 +- drivers/net/wireless/ath/ath11k/dp.h | 7 +- drivers/net/wireless/ath/ath11k/dp_rx.c | 164 ++++++++++++++++++++++---------- drivers/net/wireless/ath/ath11k/dp_tx.c | 55 +++++++---- drivers/net/wireless/ath/ath11k/hw.c | 31 ++++++ drivers/net/wireless/ath/ath11k/hw.h | 34 +++++-- drivers/net/wireless/ath/ath11k/mac.c | 15 ++- 10 files changed, 268 insertions(+), 96 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 8e9bf0e64a68..e583b1492eca 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -38,6 +38,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .single_pdev_only = false, .needs_band_to_mac = true, .rxdma1_enable = true, + .num_rxmda_per_pdev = 1, + .rx_mac_buf_ring = false, }, { .name = "qca6390 hw2.0", @@ -58,6 +60,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .single_pdev_only = true, .needs_band_to_mac = false, .rxdma1_enable = false, + .num_rxmda_per_pdev = 2, + .rx_mac_buf_ring = true, }, }; diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 48bf2954c97c..f623f357aa33 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -901,6 +901,12 @@ static inline struct ath11k_vif *ath11k_vif_to_arvif(struct ieee80211_vif *vif) return (struct ath11k_vif *)vif->drv_priv; } +static inline struct ath11k *ath11k_ab_to_ar(struct ath11k_base *ab, + int mac_id) +{ + return ab->pdevs[ath11k_hw_mac_id_to_pdev_id(&ab->hw_params, mac_id)].ar; +} + static inline void ath11k_core_create_firmware_path(struct ath11k_base *ab, const char *filename, void *buf, size_t buf_len) diff --git a/drivers/net/wireless/ath/ath11k/debug.c b/drivers/net/wireless/ath/ath11k/debug.c index 60b961e59189..0a3cfa716390 100644 --- a/drivers/net/wireless/ath/ath11k/debug.c +++ b/drivers/net/wireless/ath/ath11k/debug.c @@ -698,8 +698,10 @@ static ssize_t ath11k_write_extd_rx_stats(struct file *file, size_t count, loff_t *ppos) { struct ath11k *ar = file->private_data; + struct ath11k_base *ab = ar->ab; struct htt_rx_ring_tlv_filter tlv_filter = {0}; u32 enable, rx_filter = 0, ring_id; + int i; int ret; if (kstrtouint_from_user(ubuf, count, 0, &enable)) @@ -742,14 +744,16 @@ static ssize_t ath11k_write_extd_rx_stats(struct file *file, ar->debug.rx_filter = tlv_filter.rx_filter; - ring_id = ar->dp.rx_mon_status_refill_ring.refill_buf_ring.ring_id; - ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id, - HAL_RXDMA_MONITOR_STATUS, - DP_RX_BUFFER_SIZE, &tlv_filter); + for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; + ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id, + HAL_RXDMA_MONITOR_STATUS, + DP_RX_BUFFER_SIZE, &tlv_filter); - if (ret) { - ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n"); - goto exit; + if (ret) { + ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n"); + goto exit; + } } ar->debug.extd_rx_stats = enable; @@ -1000,10 +1004,11 @@ static ssize_t ath11k_write_pktlog_filter(struct file *file, size_t count, loff_t *ppos) { struct ath11k *ar = file->private_data; + struct ath11k_base *ab = ar->ab; struct htt_rx_ring_tlv_filter tlv_filter = {0}; u32 rx_filter = 0, ring_id, filter, mode; u8 buf[128] = {0}; - int ret; + int i, ret; ssize_t rc; mutex_lock(&ar->conf_mutex); @@ -1084,16 +1089,20 @@ static ssize_t ath11k_write_pktlog_filter(struct file *file, HTT_RX_FP_DATA_FILTER_FLASG3; } - ring_id = ar->dp.rx_mon_status_refill_ring.refill_buf_ring.ring_id; - ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id, - HAL_RXDMA_MONITOR_STATUS, - DP_RX_BUFFER_SIZE, &tlv_filter); - if (ret) { - ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n"); - goto out; + for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; + ret = ath11k_dp_tx_htt_rx_filter_setup(ab, ring_id, + ar->dp.mac_id + i, + HAL_RXDMA_MONITOR_STATUS, + DP_RX_BUFFER_SIZE, &tlv_filter); + + if (ret) { + ath11k_warn(ab, "failed to set rx filter for moniter status ring\n"); + goto out; + } } - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "pktlog filter %d mode %s\n", + ath11k_dbg(ab, ATH11K_DBG_WMI, "pktlog filter %d mode %s\n", filter, ((mode == ATH11K_PKTLOG_MODE_FULL) ? "full" : "lite")); ar->debug.pktlog_filter = filter; diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index ac92f345a013..93f30525d7f6 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -831,6 +831,7 @@ void ath11k_dp_pdev_pre_alloc(struct ath11k_base *ab) struct ath11k *ar; struct ath11k_pdev_dp *dp; int i; + int j; for (i = 0; i < ab->num_radios; i++) { ar = ab->pdevs[i].ar; @@ -840,8 +841,10 @@ void ath11k_dp_pdev_pre_alloc(struct ath11k_base *ab) spin_lock_init(&dp->rx_refill_buf_ring.idr_lock); atomic_set(&dp->num_tx_pending, 0); init_waitqueue_head(&dp->tx_empty_waitq); - idr_init(&dp->rx_mon_status_refill_ring.bufs_idr); - spin_lock_init(&dp->rx_mon_status_refill_ring.idr_lock); + for (j = 0; j < ab->hw_params.num_rxmda_per_pdev; j++) { + idr_init(&dp->rx_mon_status_refill_ring[j].bufs_idr); + spin_lock_init(&dp->rx_mon_status_refill_ring[j].idr_lock); + } idr_init(&dp->rxdma_mon_buf_ring.bufs_idr); spin_lock_init(&dp->rxdma_mon_buf_ring.idr_lock); } diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h index 07876fd521f7..558f03fbec99 100644 --- a/drivers/net/wireless/ath/ath11k/dp.h +++ b/drivers/net/wireless/ath/ath11k/dp.h @@ -8,6 +8,8 @@ #include "hal_rx.h" +#define MAX_RXDMA_PER_PDEV 2 + struct ath11k_base; struct ath11k_peer; struct ath11k_dp; @@ -142,12 +144,13 @@ struct ath11k_pdev_dp { atomic_t num_tx_pending; wait_queue_head_t tx_empty_waitq; struct dp_rxdma_ring rx_refill_buf_ring; - struct dp_srng rxdma_err_dst_ring; + struct dp_srng rx_mac_buf_ring[MAX_RXDMA_PER_PDEV]; + struct dp_srng rxdma_err_dst_ring[MAX_RXDMA_PER_PDEV]; struct dp_srng rxdma_mon_dst_ring; struct dp_srng rxdma_mon_desc_ring; struct dp_rxdma_ring rxdma_mon_buf_ring; - struct dp_rxdma_ring rx_mon_status_refill_ring; + struct dp_rxdma_ring rx_mon_status_refill_ring[MAX_RXDMA_PER_PDEV]; struct ieee80211_rx_status rx_status; struct ath11k_mon_data mon_data; }; diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 64aa0077a45d..4d745ea63f3e 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -381,7 +381,7 @@ static int ath11k_dp_rxdma_buf_ring_free(struct ath11k *ar, if (!ar->ab->hw_params.rxdma1_enable) return 0; - rx_ring = &dp->rx_mon_status_refill_ring; + rx_ring = &dp->rx_mon_status_refill_ring[0]; spin_lock_bh(&rx_ring->idr_lock); idr_for_each_entry(&rx_ring->bufs_idr, skb, buf_id) { @@ -403,15 +403,20 @@ static int ath11k_dp_rxdma_buf_ring_free(struct ath11k *ar, static int ath11k_dp_rxdma_pdev_buf_free(struct ath11k *ar) { struct ath11k_pdev_dp *dp = &ar->dp; + struct ath11k_base *ab = ar->ab; struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; + int i; ath11k_dp_rxdma_buf_ring_free(ar, rx_ring); rx_ring = &dp->rxdma_mon_buf_ring; ath11k_dp_rxdma_buf_ring_free(ar, rx_ring); - rx_ring = &dp->rx_mon_status_refill_ring; - ath11k_dp_rxdma_buf_ring_free(ar, rx_ring); + for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + rx_ring = &dp->rx_mon_status_refill_ring[i]; + ath11k_dp_rxdma_buf_ring_free(ar, rx_ring); + } + return 0; } @@ -434,7 +439,9 @@ static int ath11k_dp_rxdma_ring_buf_setup(struct ath11k *ar, static int ath11k_dp_rxdma_pdev_buf_setup(struct ath11k *ar) { struct ath11k_pdev_dp *dp = &ar->dp; + struct ath11k_base *ab = ar->ab; struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; + int i; ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_BUF); @@ -443,8 +450,10 @@ static int ath11k_dp_rxdma_pdev_buf_setup(struct ath11k *ar) ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_BUF); } - rx_ring = &dp->rx_mon_status_refill_ring; - ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_STATUS); + for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + rx_ring = &dp->rx_mon_status_refill_ring[i]; + ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_STATUS); + } return 0; } @@ -452,11 +461,21 @@ static int ath11k_dp_rxdma_pdev_buf_setup(struct ath11k *ar) static void ath11k_dp_rx_pdev_srng_free(struct ath11k *ar) { struct ath11k_pdev_dp *dp = &ar->dp; + struct ath11k_base *ab = ar->ab; + int i; + + ath11k_dp_srng_cleanup(ab, &dp->rx_refill_buf_ring.refill_buf_ring); + + for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + if (ab->hw_params.rx_mac_buf_ring) + ath11k_dp_srng_cleanup(ab, &dp->rx_mac_buf_ring[i]); - ath11k_dp_srng_cleanup(ar->ab, &dp->rx_refill_buf_ring.refill_buf_ring); - ath11k_dp_srng_cleanup(ar->ab, &dp->rxdma_err_dst_ring); - ath11k_dp_srng_cleanup(ar->ab, &dp->rx_mon_status_refill_ring.refill_buf_ring); - ath11k_dp_srng_cleanup(ar->ab, &dp->rxdma_mon_buf_ring.refill_buf_ring); + ath11k_dp_srng_cleanup(ab, &dp->rxdma_err_dst_ring[i]); + ath11k_dp_srng_cleanup(ab, + &dp->rx_mon_status_refill_ring[i].refill_buf_ring); + } + + ath11k_dp_srng_cleanup(ab, &dp->rxdma_mon_buf_ring.refill_buf_ring); } void ath11k_dp_pdev_reo_cleanup(struct ath11k_base *ab) @@ -495,7 +514,9 @@ err_reo_cleanup: static int ath11k_dp_rx_pdev_srng_alloc(struct ath11k *ar) { struct ath11k_pdev_dp *dp = &ar->dp; + struct ath11k_base *ab = ar->ab; struct dp_srng *srng = NULL; + int i; int ret; ret = ath11k_dp_srng_setup(ar->ab, @@ -507,23 +528,41 @@ static int ath11k_dp_rx_pdev_srng_alloc(struct ath11k *ar) return ret; } - ret = ath11k_dp_srng_setup(ar->ab, &dp->rxdma_err_dst_ring, - HAL_RXDMA_DST, 0, dp->mac_id, - DP_RXDMA_ERR_DST_RING_SIZE); - if (ret) { - ath11k_warn(ar->ab, "failed to setup rxdma_err_dst_ring\n"); - return ret; + if (ar->ab->hw_params.rx_mac_buf_ring) { + for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + ret = ath11k_dp_srng_setup(ar->ab, + &dp->rx_mac_buf_ring[i], + HAL_RXDMA_BUF, 1, + dp->mac_id + i, 1024); + if (ret) { + ath11k_warn(ar->ab, "failed to setup rx_mac_buf_ring %d\n", + i); + return ret; + } + } } - srng = &dp->rx_mon_status_refill_ring.refill_buf_ring; - ret = ath11k_dp_srng_setup(ar->ab, - srng, - HAL_RXDMA_MONITOR_STATUS, 0, dp->mac_id, - DP_RXDMA_MON_STATUS_RING_SIZE); - if (ret) { - ath11k_warn(ar->ab, - "failed to setup rx_mon_status_refill_ring\n"); - return ret; + for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + ret = ath11k_dp_srng_setup(ar->ab, &dp->rxdma_err_dst_ring[i], + HAL_RXDMA_DST, 0, dp->mac_id + i, + DP_RXDMA_ERR_DST_RING_SIZE); + if (ret) { + ath11k_warn(ar->ab, "failed to setup rxdma_err_dst_ring %d\n", i); + return ret; + } + } + + for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + srng = &dp->rx_mon_status_refill_ring[i].refill_buf_ring; + ret = ath11k_dp_srng_setup(ar->ab, + srng, + HAL_RXDMA_MONITOR_STATUS, 0, dp->mac_id + i, + DP_RXDMA_MON_STATUS_RING_SIZE); + if (ret) { + ath11k_warn(ar->ab, + "failed to setup rx_mon_status_refill_ring %d\n", i); + return ret; + } } /* if rxdma1_enable is false, then it doesn't need @@ -2738,20 +2777,25 @@ fail_desc_get: static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, int *budget, struct sk_buff_head *skb_list) { - struct ath11k *ar = ab->pdevs[mac_id].ar; - struct ath11k_pdev_dp *dp = &ar->dp; - struct dp_rxdma_ring *rx_ring = &dp->rx_mon_status_refill_ring; + struct ath11k *ar; + struct ath11k_pdev_dp *dp; + struct dp_rxdma_ring *rx_ring; struct hal_srng *srng; void *rx_mon_status_desc; struct sk_buff *skb; struct ath11k_skb_rxcb *rxcb; struct hal_tlv_hdr *tlv; u32 cookie; - int buf_id; + int buf_id, srng_id; dma_addr_t paddr; u8 rbm; int num_buffs_reaped = 0; + ar = ab->pdevs[ath11k_hw_mac_id_to_pdev_id(&ab->hw_params, mac_id)].ar; + dp = &ar->dp; + srng_id = ath11k_hw_mac_id_to_srng_id(&ab->hw_params, mac_id); + rx_ring = &dp->rx_mon_status_refill_ring[srng_id]; + srng = &ab->hal.srng_list[rx_ring->refill_buf_ring.ring_id]; spin_lock_bh(&srng->lock); @@ -2832,7 +2876,7 @@ move_next: int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id, struct napi_struct *napi, int budget) { - struct ath11k *ar = ab->pdevs[mac_id].ar; + struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); enum hal_rx_mon_status hal_status; struct sk_buff *skb; struct sk_buff_head skb_list; @@ -3942,9 +3986,9 @@ done: int ath11k_dp_process_rxdma_err(struct ath11k_base *ab, int mac_id, int budget) { - struct ath11k *ar = ab->pdevs[mac_id].ar; - struct dp_srng *err_ring = &ar->dp.rxdma_err_dst_ring; - struct dp_rxdma_ring *rx_ring = &ar->dp.rx_refill_buf_ring; + struct ath11k *ar; + struct dp_srng *err_ring; + struct dp_rxdma_ring *rx_ring; struct dp_link_desc_bank *link_desc_banks = ab->dp.link_desc_banks; struct hal_srng *srng; u32 msdu_cookies[HAL_NUM_RX_MSDUS_PER_LINK_DESC]; @@ -3963,6 +4007,11 @@ int ath11k_dp_process_rxdma_err(struct ath11k_base *ab, int mac_id, int budget) int i; int buf_id; + ar = ab->pdevs[ath11k_hw_mac_id_to_pdev_id(&ab->hw_params, mac_id)].ar; + err_ring = &ar->dp.rxdma_err_dst_ring[ath11k_hw_mac_id_to_srng_id(&ab->hw_params, + mac_id)]; + rx_ring = &ar->dp.rx_refill_buf_ring; + srng = &ab->hal.srng_list[err_ring->ring_id]; spin_lock_bh(&srng->lock); @@ -4116,6 +4165,7 @@ int ath11k_dp_rx_pdev_alloc(struct ath11k_base *ab, int mac_id) struct ath11k *ar = ab->pdevs[mac_id].ar; struct ath11k_pdev_dp *dp = &ar->dp; u32 ring_id; + int i; int ret; ret = ath11k_dp_rx_pdev_srng_alloc(ar); @@ -4138,12 +4188,28 @@ int ath11k_dp_rx_pdev_alloc(struct ath11k_base *ab, int mac_id) return ret; } - ring_id = dp->rxdma_err_dst_ring.ring_id; - ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id, HAL_RXDMA_DST); - if (ret) { - ath11k_warn(ab, "failed to configure rxdma_err_dest_ring %d\n", - ret); - return ret; + if (ab->hw_params.rx_mac_buf_ring) { + for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + ring_id = dp->rx_mac_buf_ring[i].ring_id; + ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, + mac_id + i, HAL_RXDMA_BUF); + if (ret) { + ath11k_warn(ab, "failed to configure rx_mac_buf_ring%d %d\n", + i, ret); + return ret; + } + } + } + + for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + ring_id = dp->rxdma_err_dst_ring[i].ring_id; + ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, + mac_id + i, HAL_RXDMA_DST); + if (ret) { + ath11k_warn(ab, "failed to configure rxdma_err_dest_ring%d %d\n", + i, ret); + return ret; + } } if (!ab->hw_params.rxdma1_enable) @@ -4175,14 +4241,16 @@ int ath11k_dp_rx_pdev_alloc(struct ath11k_base *ab, int mac_id) } config_refill_ring: - ring_id = dp->rx_mon_status_refill_ring.refill_buf_ring.ring_id; - ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id, - HAL_RXDMA_MONITOR_STATUS); - if (ret) { - ath11k_warn(ab, - "failed to configure mon_status_refill_ring %d\n", - ret); - return ret; + for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + ring_id = dp->rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; + ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id + i, + HAL_RXDMA_MONITOR_STATUS); + if (ret) { + ath11k_warn(ab, + "failed to configure mon_status_refill_ring%d %d\n", + i, ret); + return ret; + } } return 0; @@ -4802,7 +4870,7 @@ static void ath11k_dp_rx_mon_status_process_tlv(struct ath11k *ar, static int ath11k_dp_mon_process_rx(struct ath11k_base *ab, int mac_id, struct napi_struct *napi, int budget) { - struct ath11k *ar = ab->pdevs[mac_id].ar; + struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); struct ath11k_pdev_dp *dp = &ar->dp; struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data; int num_buffs_reaped = 0; @@ -4818,7 +4886,7 @@ static int ath11k_dp_mon_process_rx(struct ath11k_base *ab, int mac_id, int ath11k_dp_rx_process_mon_rings(struct ath11k_base *ab, int mac_id, struct napi_struct *napi, int budget) { - struct ath11k *ar = ab->pdevs[mac_id].ar; + struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); int ret = 0; if (test_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags)) diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index b83b5176a5df..953c435ef3b3 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -633,14 +633,28 @@ ath11k_dp_tx_get_ring_id_type(struct ath11k_base *ab, switch (ring_type) { case HAL_RXDMA_BUF: lmac_ring_id_offset = mac_id * HAL_SRNG_RINGS_PER_LMAC; - if (!(ring_id == (HAL_SRNG_RING_ID_WMAC1_SW2RXDMA0_BUF + - lmac_ring_id_offset) || - ring_id == (HAL_SRNG_RING_ID_WMAC1_SW2RXDMA1_BUF + - lmac_ring_id_offset))) { - ret = -EINVAL; + + /* for QCA6390, host fills rx buffer to fw and fw fills to + * rxbuf ring for each rxdma + */ + if (!ab->hw_params.rx_mac_buf_ring) { + if (!(ring_id == (HAL_SRNG_RING_ID_WMAC1_SW2RXDMA0_BUF + + lmac_ring_id_offset) || + ring_id == (HAL_SRNG_RING_ID_WMAC1_SW2RXDMA1_BUF + + lmac_ring_id_offset))) { + ret = -EINVAL; + } + *htt_ring_id = HTT_RXDMA_HOST_BUF_RING; + *htt_ring_type = HTT_SW_TO_HW_RING; + } else { + if (ring_id == HAL_SRNG_RING_ID_WMAC1_SW2RXDMA0_BUF) { + *htt_ring_id = HTT_HOST1_TO_FW_RXBUF_RING; + *htt_ring_type = HTT_SW_TO_SW_RING; + } else { + *htt_ring_id = HTT_RXDMA_HOST_BUF_RING; + *htt_ring_type = HTT_SW_TO_HW_RING; + } } - *htt_ring_id = HTT_RXDMA_HOST_BUF_RING; - *htt_ring_type = HTT_SW_TO_HW_RING; break; case HAL_RXDMA_DST: *htt_ring_id = HTT_RXDMA_NON_MONITOR_DEST_RING; @@ -968,8 +982,9 @@ ath11k_dp_tx_htt_h2t_ext_stats_req(struct ath11k *ar, u8 type, int ath11k_dp_tx_htt_monitor_mode_ring_config(struct ath11k *ar, bool reset) { struct ath11k_pdev_dp *dp = &ar->dp; + struct ath11k_base *ab = ar->ab; struct htt_rx_ring_tlv_filter tlv_filter = {0}; - int ret = 0, ring_id = 0; + int ret = 0, ring_id = 0, i; ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id; @@ -998,16 +1013,20 @@ int ath11k_dp_tx_htt_monitor_mode_ring_config(struct ath11k *ar, bool reset) if (ret) return ret; - ring_id = dp->rx_mon_status_refill_ring.refill_buf_ring.ring_id; - if (!reset) - tlv_filter.rx_filter = - HTT_RX_MON_FILTER_TLV_FLAGS_MON_STATUS_RING; - else - tlv_filter = ath11k_mac_mon_status_filter_default; + for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + ring_id = dp->rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; + if (!reset) + tlv_filter.rx_filter = + HTT_RX_MON_FILTER_TLV_FLAGS_MON_STATUS_RING; + else + tlv_filter = ath11k_mac_mon_status_filter_default; + + ret = ath11k_dp_tx_htt_rx_filter_setup(ab, ring_id, + dp->mac_id + i, + HAL_RXDMA_MONITOR_STATUS, + DP_RXDMA_REFILL_RING_SIZE, + &tlv_filter); + } - ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, dp->mac_id, - HAL_RXDMA_MONITOR_STATUS, - DP_RXDMA_REFILL_RING_SIZE, - &tlv_filter); return ret; } diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index 9737b9f5e1b5..e0788994ea22 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -127,18 +127,49 @@ static void ath11k_init_wmi_config_ipq8074(struct ath11k_base *ab, config->twt_ap_sta_count = 1000; } +static int ath11k_hw_mac_id_to_pdev_id_ipq8074(struct ath11k_hw_params *hw, + int mac_id) +{ + return mac_id; +} + +static int ath11k_hw_mac_id_to_srng_id_ipq8074(struct ath11k_hw_params *hw, + int mac_id) +{ + return 0; +} + +static int ath11k_hw_mac_id_to_pdev_id_qca6390(struct ath11k_hw_params *hw, + int mac_id) +{ + return 0; +} + +static int ath11k_hw_mac_id_to_srng_id_qca6390(struct ath11k_hw_params *hw, + int mac_id) +{ + return mac_id; +} + const struct ath11k_hw_ops ipq8074_ops = { .get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id, .wmi_init_config = ath11k_init_wmi_config_qca6390, + .mac_id_to_pdev_id = ath11k_hw_mac_id_to_pdev_id_ipq8074, + .mac_id_to_srng_id = ath11k_hw_mac_id_to_srng_id_ipq8074, }; const struct ath11k_hw_ops ipq6018_ops = { .get_hw_mac_from_pdev_id = ath11k_hw_ipq6018_mac_from_pdev_id, .wmi_init_config = ath11k_init_wmi_config_ipq8074, + .mac_id_to_pdev_id = ath11k_hw_mac_id_to_pdev_id_ipq8074, + .mac_id_to_srng_id = ath11k_hw_mac_id_to_srng_id_ipq8074, }; const struct ath11k_hw_ops qca6390_ops = { .get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id, + .wmi_init_config = ath11k_init_wmi_config_qca6390, + .mac_id_to_pdev_id = ath11k_hw_mac_id_to_pdev_id_qca6390, + .mac_id_to_srng_id = ath11k_hw_mac_id_to_srng_id_qca6390, }; #define ATH11K_TX_RING_MASK_0 0x1 diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 2e88194da329..1a8f63e789a0 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -116,12 +116,6 @@ struct ath11k_hw_ring_mask { u8 host2rxdma[ATH11K_EXT_IRQ_GRP_NUM_MAX]; }; -struct ath11k_hw_ops { - u8 (*get_hw_mac_from_pdev_id)(int pdev_id); - void (*wmi_init_config)(struct ath11k_base *ab, - struct target_resource_config *config); -}; - struct ath11k_hw_params { const char *name; u16 hw_rev; @@ -153,6 +147,16 @@ struct ath11k_hw_params { bool needs_band_to_mac; bool rxdma1_enable; + int num_rxmda_per_pdev; + bool rx_mac_buf_ring; +}; + +struct ath11k_hw_ops { + u8 (*get_hw_mac_from_pdev_id)(int pdev_id); + void (*wmi_init_config)(struct ath11k_base *ab, + struct target_resource_config *config); + int (*mac_id_to_pdev_id)(struct ath11k_hw_params *hw, int mac_id); + int (*mac_id_to_srng_id)(struct ath11k_hw_params *hw, int mac_id); }; extern const struct ath11k_hw_ops ipq8074_ops; @@ -172,6 +176,24 @@ int ath11k_hw_get_mac_from_pdev_id(struct ath11k_hw_params *hw, return 0; } +static inline int ath11k_hw_mac_id_to_pdev_id(struct ath11k_hw_params *hw, + int mac_id) +{ + if (hw->hw_ops->mac_id_to_pdev_id) + return hw->hw_ops->mac_id_to_pdev_id(hw, mac_id); + + return 0; +} + +static inline int ath11k_hw_mac_id_to_srng_id(struct ath11k_hw_params *hw, + int mac_id) +{ + if (hw->hw_ops->mac_id_to_srng_id) + return hw->hw_ops->mac_id_to_srng_id(hw, mac_id); + + return 0; +} + struct ath11k_fw_ie { __le32 id; __le32 len; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index ec68b5eea847..5aae1ec27e9f 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -4054,6 +4054,8 @@ void ath11k_mac_drain_tx(struct ath11k *ar) static int ath11k_mac_config_mon_status_default(struct ath11k *ar, bool enable) { struct htt_rx_ring_tlv_filter tlv_filter = {0}; + struct ath11k_base *ab = ar->ab; + int i, ret = 0; u32 ring_id; if (enable) { @@ -4061,11 +4063,16 @@ static int ath11k_mac_config_mon_status_default(struct ath11k *ar, bool enable) tlv_filter.rx_filter = ath11k_debug_rx_filter(ar); } - ring_id = ar->dp.rx_mon_status_refill_ring.refill_buf_ring.ring_id; + for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; + ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, + ar->dp.mac_id + i, + HAL_RXDMA_MONITOR_STATUS, + DP_RX_BUFFER_SIZE, + &tlv_filter); + } - return ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id, - HAL_RXDMA_MONITOR_STATUS, - DP_RX_BUFFER_SIZE, &tlv_filter); + return ret; } static int ath11k_mac_op_start(struct ieee80211_hw *hw) -- cgit v1.2.3 From 84eee3c845d377cbe1cae722e8f83344107d709f Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Mon, 17 Aug 2020 13:31:53 +0300 Subject: ath11k: refine the phy_id check in ath11k_reg_chan_list_event For QCA6390, it processes the reg chan list event only for phy0, and it goes to fallback if the phy_id is not valid. For a valid phy_id but not 0, just discard the event. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597555891-26112-5-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/wmi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 4e100407fea6..a66576f78af2 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -5463,7 +5463,12 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *sk pdev_idx = reg_info->phy_id; if (pdev_idx >= ab->num_radios) { - if (ab->hw_params.single_pdev_only) + /* Process the event for phy0 only if single_pdev_only + * is true. If pdev_idx is valid but not 0, discard the + * event. Otherwise, it goes to fallback. + */ + if (ab->hw_params.single_pdev_only && + pdev_idx < ab->hw_params.num_rxmda_per_pdev) goto mem_free; else goto fallback; -- cgit v1.2.3 From e7495035286aae68e5cc67f842c3e8bcc4483352 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Mon, 17 Aug 2020 13:31:53 +0300 Subject: ath11k: delay vdev_start for QCA6390 For QCA6390 firmware, bss peer must be created before vdev_start, so delay vdev_start until bss peer is created. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597555891-26112-6-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/core.c | 2 ++ drivers/net/wireless/ath/ath11k/core.h | 1 + drivers/net/wireless/ath/ath11k/hw.h | 1 + drivers/net/wireless/ath/ath11k/mac.c | 51 ++++++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index e583b1492eca..c469904057f9 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -40,6 +40,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .rxdma1_enable = true, .num_rxmda_per_pdev = 1, .rx_mac_buf_ring = false, + .vdev_start_delay = false, }, { .name = "qca6390 hw2.0", @@ -62,6 +63,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .rxdma1_enable = false, .num_rxmda_per_pdev = 2, .rx_mac_buf_ring = true, + .vdev_start_delay = true, }, }; diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index f623f357aa33..d21191c51e10 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -217,6 +217,7 @@ struct ath11k_vif { int txpower; bool rsnie_present; bool wpaie_present; + struct ieee80211_chanctx_conf chanctx; }; struct ath11k_vif_iter { diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 1a8f63e789a0..cac6cd3c4c57 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -149,6 +149,7 @@ struct ath11k_hw_params { bool rxdma1_enable; int num_rxmda_per_pdev; bool rx_mac_buf_ring; + bool vdev_start_delay; }; struct ath11k_hw_ops { diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 5aae1ec27e9f..9759a5db39fc 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -244,6 +244,9 @@ static const u32 ath11k_smps_map[] = { [WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE, }; +static int ath11k_start_vdev_delay(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + u8 ath11k_mac_bw_to_mac80211_bw(u8 bw) { u8 ret = 0; @@ -2960,6 +2963,14 @@ static int ath11k_mac_station_add(struct ath11k *ar, goto free_tx_stats; } + if (ab->hw_params.vdev_start_delay) { + ret = ath11k_start_vdev_delay(ar->hw, vif); + if (ret) { + ath11k_warn(ab, "failed to delay vdev start: %d\n", ret); + goto free_tx_stats; + } + } + return 0; free_tx_stats: @@ -5116,6 +5127,39 @@ unlock: mutex_unlock(&ar->conf_mutex); } +static int ath11k_start_vdev_delay(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath11k *ar = hw->priv; + struct ath11k_base *ab = ar->ab; + struct ath11k_vif *arvif = (void *)vif->drv_priv; + int ret; + + if (WARN_ON(arvif->is_started)) + return -EBUSY; + + ret = ath11k_mac_vdev_start(arvif, &arvif->chanctx.def); + if (ret) { + ath11k_warn(ab, "failed to start vdev %i addr %pM on freq %d: %d\n", + arvif->vdev_id, vif->addr, + arvif->chanctx.def.chan->center_freq, ret); + return ret; + } + + if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { + ret = ath11k_monitor_vdev_up(ar, arvif->vdev_id); + if (ret) { + ath11k_warn(ab, "failed put monitor up: %d\n", ret); + return ret; + } + } + + arvif->is_started = true; + + /* TODO: Setup ps and cts/rts protection */ + return 0; +} + static int ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -5132,6 +5176,13 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, "mac chanctx assign ptr %pK vdev_id %i\n", ctx, arvif->vdev_id); + /* for QCA6390 bss peer must be created before vdev_start */ + if (ab->hw_params.vdev_start_delay) { + memcpy(&arvif->chanctx, ctx, sizeof(*ctx)); + mutex_unlock(&ar->conf_mutex); + return 0; + } + if (WARN_ON(arvif->is_started)) { mutex_unlock(&ar->conf_mutex); return -EBUSY; -- cgit v1.2.3 From a6275302c3704a126c1b309888520fb05c94a563 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Mon, 17 Aug 2020 13:31:54 +0300 Subject: ath11k: assign correct search flag and type for QCA6390 QCA6390 doesn't enable V2 map and ummap event, so the addr search flags and type is different from IPQ8074. Assign correct search flags and type for QCA6390. Without this change, ping sometimes fails. With this change, now ping is always successful. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597555891-26112-7-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/core.c | 2 ++ drivers/net/wireless/ath/ath11k/dp.c | 15 +++++++++++---- drivers/net/wireless/ath/ath11k/dp_rx.c | 10 ++++++++++ drivers/net/wireless/ath/ath11k/hw.h | 1 + 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index c469904057f9..a279450438bb 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -41,6 +41,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .num_rxmda_per_pdev = 1, .rx_mac_buf_ring = false, .vdev_start_delay = false, + .htt_peer_map_v2 = true, }, { .name = "qca6390 hw2.0", @@ -64,6 +65,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .num_rxmda_per_pdev = 2, .rx_mac_buf_ring = true, .vdev_start_delay = true, + .htt_peer_map_v2 = false, }, }; diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index 93f30525d7f6..fb82c4f75ced 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -909,13 +909,20 @@ int ath11k_dp_htt_connect(struct ath11k_dp *dp) static void ath11k_dp_update_vdev_search(struct ath11k_vif *arvif) { - /* For STA mode, enable address search index, - * tcl uses ast_hash value in the descriptor. + /* When v2_map_support is true:for STA mode, enable address + * search index, tcl uses ast_hash value in the descriptor. + * When v2_map_support is false: for STA mode, dont' enable + * address search index. */ switch (arvif->vdev_type) { case WMI_VDEV_TYPE_STA: - arvif->hal_addr_search_flags = HAL_TX_ADDRX_EN; - arvif->search_type = HAL_TX_ADDR_SEARCH_INDEX; + if (arvif->ar->ab->hw_params.htt_peer_map_v2) { + arvif->hal_addr_search_flags = HAL_TX_ADDRX_EN; + arvif->search_type = HAL_TX_ADDR_SEARCH_INDEX; + } else { + arvif->hal_addr_search_flags = HAL_TX_ADDRY_EN; + arvif->search_type = HAL_TX_ADDR_SEARCH_DEFAULT; + } break; case WMI_VDEV_TYPE_AP: case WMI_VDEV_TYPE_IBSS: diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 4d745ea63f3e..33c7c232773f 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -1625,6 +1625,16 @@ void ath11k_dp_htt_htc_t2h_msg_handler(struct ath11k_base *ab, complete(&dp->htt_tgt_version_received); break; case HTT_T2H_MSG_TYPE_PEER_MAP: + vdev_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_VDEV_ID, + resp->peer_map_ev.info); + peer_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_PEER_ID, + resp->peer_map_ev.info); + peer_mac_h16 = FIELD_GET(HTT_T2H_PEER_MAP_INFO1_MAC_ADDR_H16, + resp->peer_map_ev.info1); + ath11k_dp_get_mac_addr(resp->peer_map_ev.mac_addr_l32, + peer_mac_h16, mac_addr); + ath11k_peer_map_event(ab, vdev_id, peer_id, mac_addr, 0); + break; case HTT_T2H_MSG_TYPE_PEER_MAP2: vdev_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_VDEV_ID, resp->peer_map_ev.info); diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index cac6cd3c4c57..500060b36fb4 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -150,6 +150,7 @@ struct ath11k_hw_params { int num_rxmda_per_pdev; bool rx_mac_buf_ring; bool vdev_start_delay; + bool htt_peer_map_v2; }; struct ath11k_hw_ops { -- cgit v1.2.3 From 454a97217283df762650d4b4e61b64a9d8dfeddf Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Mon, 17 Aug 2020 13:31:54 +0300 Subject: ath11k: process both lmac rings for QCA6390 For QCA6390, the num_radios is 1 but it needs to process 2 lmac rings. So use NUM_RXDMA_PER_PDEV to do another loop. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597555891-26112-8-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/dp.c | 59 +++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index fb82c4f75ced..b0ea5958833a 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -731,7 +731,7 @@ int ath11k_dp_service_srng(struct ath11k_base *ab, struct napi_struct *napi = &irq_grp->napi; int grp_id = irq_grp->grp_id; int work_done = 0; - int i = 0; + int i = 0, j; int tot_work_done = 0; while (ab->hw_params.ring_mask->tx[grp_id] >> i) { @@ -770,17 +770,23 @@ int ath11k_dp_service_srng(struct ath11k_base *ab, } if (ab->hw_params.ring_mask->rx_mon_status[grp_id]) { - for (i = 0; i < ab->num_radios; i++) { - if (ab->hw_params.ring_mask->rx_mon_status[grp_id] & BIT(i)) { - work_done = - ath11k_dp_rx_process_mon_rings(ab, - i, napi, - budget); - budget -= work_done; - tot_work_done += work_done; + for (i = 0; i < ab->num_radios; i++) { + for (j = 0; j < ab->hw_params.num_rxmda_per_pdev; j++) { + int id = i * ab->hw_params.num_rxmda_per_pdev + j; + + if (ab->hw_params.ring_mask->rx_mon_status[grp_id] & + BIT(id)) { + work_done = + ath11k_dp_rx_process_mon_rings(ab, + id, + napi, budget); + budget -= work_done; + tot_work_done += work_done; + + if (budget <= 0) + goto done; + } } - if (budget <= 0) - goto done; } } @@ -788,22 +794,27 @@ int ath11k_dp_service_srng(struct ath11k_base *ab, ath11k_dp_process_reo_status(ab); for (i = 0; i < ab->num_radios; i++) { - if (ab->hw_params.ring_mask->rxdma2host[grp_id] & BIT(i)) { - work_done = ath11k_dp_process_rxdma_err(ab, i, budget); - budget -= work_done; - tot_work_done += work_done; - } + for (j = 0; j < ab->hw_params.num_rxmda_per_pdev; j++) { + int id = i * ab->hw_params.num_rxmda_per_pdev + j; - if (budget <= 0) - goto done; + if (ab->hw_params.ring_mask->rxdma2host[grp_id] & BIT(id)) { + work_done = ath11k_dp_process_rxdma_err(ab, id, budget); + budget -= work_done; + tot_work_done += work_done; + } - if (ab->hw_params.ring_mask->host2rxdma[grp_id] & BIT(i)) { - struct ath11k_pdev_dp *dp = &ab->pdevs[i].ar->dp; - struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; + if (budget <= 0) + goto done; + + if (ab->hw_params.ring_mask->host2rxdma[grp_id] & BIT(id)) { + struct ath11k *ar = ath11k_ab_to_ar(ab, id); + struct ath11k_pdev_dp *dp = &ar->dp; + struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; - ath11k_dp_rxbufs_replenish(ab, i, rx_ring, 0, - HAL_RX_BUF_RBM_SW3_BM, - GFP_ATOMIC); + ath11k_dp_rxbufs_replenish(ab, id, rx_ring, 0, + HAL_RX_BUF_RBM_SW3_BM, + GFP_ATOMIC); + } } } /* TODO: Implement handler for other interrupts */ -- cgit v1.2.3 From 065f5f683ea6abbc83cbf03b8789b452ab29d14f Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Mon, 17 Aug 2020 13:31:55 +0300 Subject: ath11k: use TCL_DATA_RING_0 for QCA6390 For QCA6390, wbm2sw1 is used for other purpose rather than tx completion ring. So use TCL_DATA_RING 0 only for QCA6390. Add MISC_CAPS_TCL_0_ONLY to control it. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597555891-26112-9-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/core.c | 2 ++ drivers/net/wireless/ath/ath11k/dp_tx.c | 10 ++++++++-- drivers/net/wireless/ath/ath11k/hw.h | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index a279450438bb..4e397664d1b9 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -42,6 +42,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .rx_mac_buf_ring = false, .vdev_start_delay = false, .htt_peer_map_v2 = true, + .tcl_0_only = false, }, { .name = "qca6390 hw2.0", @@ -66,6 +67,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .rx_mac_buf_ring = true, .vdev_start_delay = true, .htt_peer_map_v2 = false, + .tcl_0_only = true, }, }; diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index 953c435ef3b3..a9632b774304 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -110,7 +110,12 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, tcl_ring_sel: tcl_ring_retry = false; - ti.ring_id = ring_selector % DP_TCL_NUM_RING_MAX; + /* For some chip, it can only use tcl0 to tx */ + if (ar->ab->hw_params.tcl_0_only) + ti.ring_id = 0; + else + ti.ring_id = ring_selector % DP_TCL_NUM_RING_MAX; + ring_map |= BIT(ti.ring_id); tx_ring = &dp->tx_ring[ti.ring_id]; @@ -221,7 +226,8 @@ tcl_ring_sel: * checking this ring earlier for each pkt tx. * Restart ring selection if some rings are not checked yet. */ - if (ring_map != (BIT(DP_TCL_NUM_RING_MAX) - 1)) { + if (ring_map != (BIT(DP_TCL_NUM_RING_MAX) - 1) && + !ar->ab->hw_params.tcl_0_only) { tcl_ring_retry = true; ring_selector++; } diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 500060b36fb4..d15fa7fd6d5d 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -151,6 +151,7 @@ struct ath11k_hw_params { bool rx_mac_buf_ring; bool vdev_start_delay; bool htt_peer_map_v2; + bool tcl_0_only; }; struct ath11k_hw_ops { -- cgit v1.2.3 From f3c603d412b3434dec15821f13fa4a1d0dd1cc84 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Mon, 17 Aug 2020 13:31:55 +0300 Subject: ath11k: reset MHI during power down and power up For QCA6390, normal power up and power down can't bring MHI to a workable state. This happens especially in warm reboot and rmmod and insmod. Host needs to write a few registers to bring MHI to normal state. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-2 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597555891-26112-10-git-send-email-kvalo@codeaurora.org --- drivers/net/wireless/ath/ath11k/mhi.c | 46 +++++++++++++++++++- drivers/net/wireless/ath/ath11k/mhi.h | 11 +++++ drivers/net/wireless/ath/ath11k/pci.c | 79 ++++++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath11k/pci.h | 17 ++++++++ 4 files changed, 150 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index 62d39ef6741f..d7e60dc5b300 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -107,6 +107,51 @@ static struct mhi_controller_config ath11k_mhi_config = { .event_cfg = ath11k_mhi_events, }; +void ath11k_mhi_set_mhictrl_reset(struct ath11k_base *ab) +{ + u32 val; + + val = ath11k_pci_read32(ab, MHISTATUS); + + ath11k_dbg(ab, ATH11K_DBG_PCI, "MHISTATUS 0x%x\n", val); + + /* Observed on QCA6390 that after SOC_GLOBAL_RESET, MHISTATUS + * has SYSERR bit set and thus need to set MHICTRL_RESET + * to clear SYSERR. + */ + ath11k_pci_write32(ab, MHICTRL, MHICTRL_RESET_MASK); + + mdelay(10); +} + +static void ath11k_mhi_reset_txvecdb(struct ath11k_base *ab) +{ + ath11k_pci_write32(ab, PCIE_TXVECDB, 0); +} + +static void ath11k_mhi_reset_txvecstatus(struct ath11k_base *ab) +{ + ath11k_pci_write32(ab, PCIE_TXVECSTATUS, 0); +} + +static void ath11k_mhi_reset_rxvecdb(struct ath11k_base *ab) +{ + ath11k_pci_write32(ab, PCIE_RXVECDB, 0); +} + +static void ath11k_mhi_reset_rxvecstatus(struct ath11k_base *ab) +{ + ath11k_pci_write32(ab, PCIE_RXVECSTATUS, 0); +} + +void ath11k_mhi_clear_vector(struct ath11k_base *ab) +{ + ath11k_mhi_reset_txvecdb(ab); + ath11k_mhi_reset_txvecstatus(ab); + ath11k_mhi_reset_rxvecdb(ab); + ath11k_mhi_reset_rxvecstatus(ab); +} + static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci) { struct ath11k_base *ab = ab_pci->ab; @@ -416,7 +461,6 @@ out: void ath11k_mhi_stop(struct ath11k_pci *ab_pci) { - ath11k_mhi_set_state(ab_pci, ATH11K_MHI_RESUME); ath11k_mhi_set_state(ab_pci, ATH11K_MHI_POWER_OFF); ath11k_mhi_set_state(ab_pci, ATH11K_MHI_DEINIT); } diff --git a/drivers/net/wireless/ath/ath11k/mhi.h b/drivers/net/wireless/ath/ath11k/mhi.h index 3c91881b4fbd..a7fd5e201d18 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.h +++ b/drivers/net/wireless/ath/ath11k/mhi.h @@ -7,6 +7,15 @@ #include "pci.h" +#define PCIE_TXVECDB 0x360 +#define PCIE_TXVECSTATUS 0x368 +#define PCIE_RXVECDB 0x394 +#define PCIE_RXVECSTATUS 0x39C + +#define MHISTATUS 0x48 +#define MHICTRL 0x38 +#define MHICTRL_RESET_MASK 0x2 + enum ath11k_mhi_state { ATH11K_MHI_INIT, ATH11K_MHI_DEINIT, @@ -24,5 +33,7 @@ int ath11k_mhi_start(struct ath11k_pci *ar_pci); void ath11k_mhi_stop(struct ath11k_pci *ar_pci); int ath11k_mhi_register(struct ath11k_pci *ar_pci); void ath11k_mhi_unregister(struct ath11k_pci *ar_pci); +void ath11k_mhi_set_mhictrl_reset(struct ath11k_base *ab); +void ath11k_mhi_clear_vector(struct ath11k_base *ab); #endif diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 6a1e74f0d1ac..ca7012d46c3f 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -301,7 +301,7 @@ static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offse } } -static void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value) +void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value) { struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); @@ -315,7 +315,7 @@ static void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value) } } -static u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset) +u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset) { struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); u32 val; @@ -332,6 +332,77 @@ static u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset) return val; } +static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) +{ + u32 val, delay; + + val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); + + val |= PCIE_SOC_GLOBAL_RESET_V; + + ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); + + /* TODO: exact time to sleep is uncertain */ + delay = 10; + mdelay(delay); + + /* Need to toggle V bit back otherwise stuck in reset status */ + val &= ~PCIE_SOC_GLOBAL_RESET_V; + + ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); + + mdelay(delay); + + val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); + if (val == 0xffffffff) + ath11k_warn(ab, "link down error during global reset\n"); +} + +static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab) +{ + u32 val; + + /* read cookie */ + val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR); + ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val); + + val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); + ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); + + /* TODO: exact time to sleep is uncertain */ + mdelay(10); + + /* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from + * continuing warm path and entering dead loop. + */ + ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0); + mdelay(10); + + val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); + ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); + + /* A read clear register. clear the register to prevent + * Q6 from entering wrong code path. + */ + val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG); + ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val); +} + +static void ath11k_pci_force_wake(struct ath11k_base *ab) +{ + ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1); + mdelay(5); +} + +static void ath11k_pci_sw_reset(struct ath11k_base *ab) +{ + ath11k_pci_soc_global_reset(ab); + ath11k_mhi_clear_vector(ab); + ath11k_pci_soc_global_reset(ab); + ath11k_mhi_set_mhictrl_reset(ab); + ath11k_pci_clear_dbg_registers(ab); +} + int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) { struct pci_dev *pci_dev = to_pci_dev(dev); @@ -834,6 +905,8 @@ static int ath11k_pci_power_up(struct ath11k_base *ab) struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); int ret; + ath11k_pci_sw_reset(ab_pci->ab); + ret = ath11k_mhi_start(ab_pci); if (ret) { ath11k_err(ab, "failed to start mhi: %d\n", ret); @@ -848,6 +921,8 @@ static void ath11k_pci_power_down(struct ath11k_base *ab) struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ath11k_mhi_stop(ab_pci); + ath11k_pci_force_wake(ab_pci->ab); + ath11k_pci_sw_reset(ab_pci->ab); } static void ath11k_pci_kill_tasklets(struct ath11k_base *ab) diff --git a/drivers/net/wireless/ath/ath11k/pci.h b/drivers/net/wireless/ath/ath11k/pci.h index 0a262c7307fd..f2f280eb8b55 100644 --- a/drivers/net/wireless/ath/ath11k/pci.h +++ b/drivers/net/wireless/ath/ath11k/pci.h @@ -9,6 +9,21 @@ #include "core.h" +#define PCIE_SOC_GLOBAL_RESET 0x3008 +#define PCIE_SOC_GLOBAL_RESET_V 1 + +#define WLAON_WARM_SW_ENTRY 0x1f80504 +#define WLAON_SOC_RESET_CAUSE_REG 0x01f8060c + +#define PCIE_Q6_COOKIE_ADDR 0x01f80500 +#define PCIE_Q6_COOKIE_DATA 0xc0000000 + +/* register to wake the UMAC from power collapse */ +#define PCIE_SCRATCH_0_SOC_PCIE_REG 0x4040 + +/* register used for handshake mechanism to validate UMAC is awake */ +#define PCIE_SOC_WAKE_PCIE_LOCAL_REG 0x3004 + struct ath11k_msi_user { char *name; int num_vectors; @@ -44,5 +59,7 @@ int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ar_pci, char *user_nam int *num_vectors, u32 *user_base_data, u32 *base_vector); int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector); +void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value); +u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset); #endif -- cgit v1.2.3 From caf275463d37e1359d1767d774052cbca60a4854 Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Fri, 26 Jun 2020 23:23:01 +0530 Subject: ath10k: Register shutdown handler As a part of device shutdown the smmu driver will be stopped and henceforth any IOVA address translation will not be done. The wlan driver, being one of the smmu driver consumer, should stop all the dma related activity as a part of shutdown, and thereby ensuring that no dma activity is done once the smmu driver shuts down. During the device shutdown, the smmu calls shutdown for all its consumers in order to indicate them to stop all their dma activities. Register the shutdown handler to stop the wlan driver and avoid any dma operations. Tested-on: WCN3990 hw1.0 SNOC WLAN.HL.3.1-01040-QCAHLSWMTPLZ-1 Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1593193981-30161-1-git-send-email-pillair@codeaurora.org --- drivers/net/wireless/ath/ath10k/snoc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 354d49b1cd45..645ed5f63ef8 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -1772,9 +1772,18 @@ static int ath10k_snoc_remove(struct platform_device *pdev) return 0; } +static void ath10k_snoc_shutdown(struct platform_device *pdev) +{ + struct ath10k *ar = platform_get_drvdata(pdev); + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc shutdown\n"); + ath10k_snoc_remove(pdev); +} + static struct platform_driver ath10k_snoc_driver = { .probe = ath10k_snoc_probe, .remove = ath10k_snoc_remove, + .shutdown = ath10k_snoc_shutdown, .driver = { .name = "ath10k_snoc", .of_match_table = ath10k_snoc_dt_match, -- cgit v1.2.3 From 99f41b8e43b8b4b31262adb8ac3e69088fff1289 Mon Sep 17 00:00:00 2001 From: Sathishkumar Muruganandam Date: Fri, 14 Aug 2020 13:46:11 +0530 Subject: ath10k: fix VHT NSS calculation when STBC is enabled When STBC is enabled, NSTS_SU value need to be accounted for VHT NSS calculation for SU case. Without this fix, 1SS + STBC enabled case was reported wrongly as 2SS in radiotap header on monitor mode capture. Tested-on: QCA9984 10.4-3.10-00047 Signed-off-by: Sathishkumar Muruganandam Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1597392971-3897-1-git-send-email-murugana@codeaurora.org --- drivers/net/wireless/ath/ath10k/htt_rx.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 136cbf001c5b..5c1af2021883 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -949,6 +949,7 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar, u8 preamble = 0; u8 group_id; u32 info1, info2, info3; + u32 stbc, nsts_su; info1 = __le32_to_cpu(rxd->ppdu_start.info1); info2 = __le32_to_cpu(rxd->ppdu_start.info2); @@ -993,11 +994,16 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar, */ bw = info2 & 3; sgi = info3 & 1; + stbc = (info2 >> 3) & 1; group_id = (info2 >> 4) & 0x3F; if (GROUP_ID_IS_SU_MIMO(group_id)) { mcs = (info3 >> 4) & 0x0F; - nss = ((info2 >> 10) & 0x07) + 1; + nsts_su = ((info2 >> 10) & 0x07); + if (stbc) + nss = (nsts_su >> 2) + 1; + else + nss = (nsts_su + 1); } else { /* Hardware doesn't decode VHT-SIG-B into Rx descriptor * so it's impossible to decode MCS. Also since -- cgit v1.2.3 From 28f1632118818d9dccabf4c0fccfe49686742317 Mon Sep 17 00:00:00 2001 From: Wang Yufen Date: Mon, 20 Jul 2020 17:36:44 +0800 Subject: ath11k: Fix possible memleak in ath11k_qmi_init_service When qmi_add_lookup fail, we should destroy the workqueue Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices") Reported-by: Hulk Robot Signed-off-by: Wang Yufen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1595237804-66297-1-git-send-email-wangyufen@huawei.com --- drivers/net/wireless/ath/ath11k/qmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index b81897131f0a..91134510364c 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -2648,6 +2648,7 @@ int ath11k_qmi_init_service(struct ath11k_base *ab) ab->qmi.service_ins_id); if (ret < 0) { ath11k_warn(ab, "failed to add qmi lookup\n"); + destroy_workqueue(ab->qmi.event_wq); return ret; } -- cgit v1.2.3 From 0b294aebb6a00b61eddbc30aa9ba34a0a1caeb7d Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 27 Jul 2020 14:44:15 -0500 Subject: ath11k: Use fallthrough pseudo-keyword Replace the existing /* fall through */ comments and its variants with the new pseudo-keyword macro fallthrough[1]. Also, remove unnecessary fall-through markings when it is the case. [1] https://www.kernel.org/doc/html/v5.7/process/deprecated.html?highlight=fallthrough#implicit-switch-case-fall-through Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200727194415.GA1275@embeddedor --- drivers/net/wireless/ath/ath11k/core.c | 2 +- drivers/net/wireless/ath/ath11k/dp.c | 2 +- drivers/net/wireless/ath/ath11k/dp_rx.c | 3 +-- drivers/net/wireless/ath/ath11k/mac.c | 22 +++++++++++----------- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 4e397664d1b9..437b1123a34f 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -729,7 +729,7 @@ static void ath11k_core_restart(struct work_struct *work) break; case ATH11K_STATE_RESTARTED: ar->state = ATH11K_STATE_WEDGED; - /* fall through */ + fallthrough; case ATH11K_STATE_WEDGED: ath11k_warn(ab, "device is wedged, will not restart radio %d\n", i); diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index b0ea5958833a..2617ec221775 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -268,7 +268,7 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, break; } /* follow through when ring_num >= 3 */ - /* fall through */ + fallthrough; case HAL_REO_EXCEPTION: case HAL_REO_REINJECT: case HAL_REO_CMD: diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 33c7c232773f..f3ca73d2173c 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -3782,8 +3782,7 @@ static bool ath11k_dp_rx_h_reo_err(struct ath11k *ar, struct sk_buff *msdu, * instead, it is good to drop such packets in mac80211 * after incrementing the replay counters. */ - - /* fall through */ + fallthrough; default: /* TODO: Review other errors and process them to mac80211 * as appropriate. diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 9759a5db39fc..220f8c9367b6 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1146,13 +1146,13 @@ ath11k_peer_assoc_h_vht_limit(u16 tx_mcs_set, idx_limit = -1; switch (idx_limit) { - case 0: /* fall through */ - case 1: /* fall through */ - case 2: /* fall through */ - case 3: /* fall through */ - case 4: /* fall through */ - case 5: /* fall through */ - case 6: /* fall through */ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: case 7: mcs = IEEE80211_VHT_MCS_SUPPORT_0_7; break; @@ -1164,7 +1164,7 @@ ath11k_peer_assoc_h_vht_limit(u16 tx_mcs_set, break; default: WARN_ON(1); - /* fall through */ + fallthrough; case -1: mcs = IEEE80211_VHT_MCS_NOT_SUPPORTED; break; @@ -1347,7 +1347,7 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; arg->peer_he_mcs_count++; - /* fall through */ + fallthrough; default: v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); @@ -2122,7 +2122,7 @@ void __ath11k_mac_scan_finish(struct ath11k *ar) } else if (ar->scan.roc_notify) { ieee80211_remain_on_channel_expired(ar->hw); } - /* fall through */ + fallthrough; case ATH11K_SCAN_STARTING: ar->scan.state = ATH11K_SCAN_IDLE; ar->scan_channel = NULL; @@ -4383,7 +4383,7 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, break; case NL80211_IFTYPE_MESH_POINT: arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S; - /* fall through */ + fallthrough; case NL80211_IFTYPE_AP: arvif->vdev_type = WMI_VDEV_TYPE_AP; break; -- cgit v1.2.3