From 6707ba0105a2d350710bc0a537a98f49eb4b895d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 29 Mar 2018 00:06:10 +0200 Subject: ath10k: avoid possible string overflow The way that 'strncat' is used here raised a warning in gcc-8: drivers/net/wireless/ath/ath10k/wmi.c: In function 'ath10k_wmi_tpc_stats_final_disp_tables': drivers/net/wireless/ath/ath10k/wmi.c:4649:4: error: 'strncat' output truncated before terminating nul copying as many bytes from a string as its length [-Werror=stringop-truncation] Effectively, this is simply a strcat() but the use of strncat() suggests some form of overflow check. Regardless of whether this might actually overflow, using strlcat() instead of strncat() avoids the warning and makes the code more robust. Fixes: bc64d05220f3 ("ath10k: debugfs support to get final TPC stats for 10.4 variants") Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index c5e1ca5945db..80a80830b363 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4357,7 +4357,7 @@ static void ath10k_tpc_config_disp_tables(struct ath10k *ar, rate_code[i], type); snprintf(buff, sizeof(buff), "%8d ", tpc[j]); - strncat(tpc_value, buff, strlen(buff)); + strlcat(tpc_value, buff, sizeof(tpc_value)); } tpc_stats->tpc_table[type].pream_idx[i] = pream_idx; tpc_stats->tpc_table[type].rate_code[i] = rate_code[i]; @@ -4694,7 +4694,7 @@ ath10k_wmi_tpc_stats_final_disp_tables(struct ath10k *ar, rate_code[i], type, pream_idx); snprintf(buff, sizeof(buff), "%8d ", tpc[j]); - strncat(tpc_value, buff, strlen(buff)); + strlcat(tpc_value, buff, sizeof(tpc_value)); } tpc_stats->tpc_table_final[type].pream_idx[i] = pream_idx; tpc_stats->tpc_table_final[type].rate_code[i] = rate_code[i]; -- cgit v1.2.3 From db5a4d5e1073be452645d7021eeaf807d70325a2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 28 Mar 2018 18:40:27 +0100 Subject: wil6210: fix potential null dereference of ndev before null check The pointer ndev is being dereferenced before it is being null checked, hence there is a potential null pointer deference. Fix this by only dereferencing ndev after it has been null checked Detected by CoverityScan, CID#1467010 ("Dereference before null check") Fixes: e00243fab84b ("wil6210: infrastructure for multiple virtual interfaces") Signed-off-by: Colin Ian King Reviewed-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index a4b413e8d55a..82aec6b06d09 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -391,7 +391,7 @@ static void wil_fw_error_worker(struct work_struct *work) struct wil6210_priv *wil = container_of(work, struct wil6210_priv, fw_error_worker); struct net_device *ndev = wil->main_ndev; - struct wireless_dev *wdev = ndev->ieee80211_ptr; + struct wireless_dev *wdev; wil_dbg_misc(wil, "fw error worker\n"); @@ -399,6 +399,7 @@ static void wil_fw_error_worker(struct work_struct *work) wil_info(wil, "No recovery - interface is down\n"); return; } + wdev = ndev->ieee80211_ptr; /* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO * passed since last recovery attempt -- cgit v1.2.3 From ec2c64e202576295bdef8edd18c67428a378cc16 Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Tue, 27 Mar 2018 22:31:44 +0200 Subject: ath10k: sdio: fix memory leak for probe allocations These allocations are not freed upon release. When on it; go for managed resources instead. Signed-off-by: Marcus Folkesson [kvalo: fix two checkpatch warnings] Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/sdio.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 03a69e5b1116..2d04c54a4153 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -1957,25 +1957,25 @@ static int ath10k_sdio_probe(struct sdio_func *func, ar_sdio = ath10k_sdio_priv(ar); ar_sdio->irq_data.irq_proc_reg = - kzalloc(sizeof(struct ath10k_sdio_irq_proc_regs), - GFP_KERNEL); + devm_kzalloc(ar->dev, sizeof(struct ath10k_sdio_irq_proc_regs), + GFP_KERNEL); if (!ar_sdio->irq_data.irq_proc_reg) { ret = -ENOMEM; goto err_core_destroy; } ar_sdio->irq_data.irq_en_reg = - kzalloc(sizeof(struct ath10k_sdio_irq_enable_regs), - GFP_KERNEL); + devm_kzalloc(ar->dev, sizeof(struct ath10k_sdio_irq_enable_regs), + GFP_KERNEL); if (!ar_sdio->irq_data.irq_en_reg) { ret = -ENOMEM; - goto err_free_proc_reg; + goto err_core_destroy; } - ar_sdio->bmi_buf = kzalloc(BMI_MAX_CMDBUF_SIZE, GFP_KERNEL); + ar_sdio->bmi_buf = devm_kzalloc(ar->dev, BMI_MAX_CMDBUF_SIZE, GFP_KERNEL); if (!ar_sdio->bmi_buf) { ret = -ENOMEM; - goto err_free_en_reg; + goto err_core_destroy; } ar_sdio->func = func; @@ -1995,7 +1995,7 @@ static int ath10k_sdio_probe(struct sdio_func *func, ar_sdio->workqueue = create_singlethread_workqueue("ath10k_sdio_wq"); if (!ar_sdio->workqueue) { ret = -ENOMEM; - goto err_free_bmi_buf; + goto err_core_destroy; } for (i = 0; i < ATH10K_SDIO_BUS_REQUEST_MAX_NUM; i++) @@ -2011,7 +2011,7 @@ static int ath10k_sdio_probe(struct sdio_func *func, ret = -ENODEV; ath10k_err(ar, "unsupported device id %u (0x%x)\n", dev_id_base, id->device); - goto err_free_bmi_buf; + goto err_core_destroy; } ar->id.vendor = id->vendor; @@ -2040,12 +2040,6 @@ static int ath10k_sdio_probe(struct sdio_func *func, err_free_wq: destroy_workqueue(ar_sdio->workqueue); -err_free_bmi_buf: - kfree(ar_sdio->bmi_buf); -err_free_en_reg: - kfree(ar_sdio->irq_data.irq_en_reg); -err_free_proc_reg: - kfree(ar_sdio->irq_data.irq_proc_reg); err_core_destroy: ath10k_core_destroy(ar); -- cgit v1.2.3 From 6ce36faeac353813b0bfd3b9bc867f3e0d6a35b2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 29 Mar 2018 17:59:49 +0100 Subject: ath10k: fix spelling mistake: "tiggers" -> "triggers" Trivial fix to spelling mistake in message text Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 80a80830b363..eb1c8a1a1c88 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -7768,7 +7768,7 @@ ath10k_wmi_fw_pdev_tx_stats_fill(const struct ath10k_fw_stats_pdev *pdev, len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", "HW rate", pdev->data_rc); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "Sched self tiggers", pdev->self_triggers); + "Sched self triggers", pdev->self_triggers); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", "Dropped due to SW retries", pdev->sw_retry_failure); -- cgit v1.2.3 From 9c27489a34548913baaaf3b2776e05d4a9389e3e Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 30 Mar 2018 13:34:01 -0500 Subject: ath9k: dfs: remove accidental use of stack VLA In preparation to enabling -Wvla, remove accidental use of stack VLA. This avoids an accidental stack VLA (since the compiler thinks the value of FFT_NUM_SAMPLES can change, even when marked "const"). This just replaces it with a #define. Also, fixed as part of the directive to remove all VLAs from the kernel: https://lkml.org/lkml/2018/3/7/621 Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/dfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c index 6fee9a464cce..c8844f55574c 100644 --- a/drivers/net/wireless/ath/ath9k/dfs.c +++ b/drivers/net/wireless/ath/ath9k/dfs.c @@ -41,7 +41,7 @@ static const int BIN_DELTA_MAX = 10; /* we need at least 3 deltas / 4 samples for a reliable chirp detection */ #define NUM_DIFFS 3 -static const int FFT_NUM_SAMPLES = (NUM_DIFFS + 1); +#define FFT_NUM_SAMPLES (NUM_DIFFS + 1) /* Threshold for difference of delta peaks */ static const int MAX_DIFF = 2; @@ -114,7 +114,7 @@ static bool ath9k_check_chirping(struct ath_softc *sc, u8 *data, ath_dbg(common, DFS, "HT40: datalen=%d, num_fft_packets=%d\n", datalen, num_fft_packets); - if (num_fft_packets < (FFT_NUM_SAMPLES)) { + if (num_fft_packets < FFT_NUM_SAMPLES) { ath_dbg(common, DFS, "not enough packets for chirp\n"); return false; } @@ -136,7 +136,7 @@ static bool ath9k_check_chirping(struct ath_softc *sc, u8 *data, return false; ath_dbg(common, DFS, "HT20: datalen=%d, num_fft_packets=%d\n", datalen, num_fft_packets); - if (num_fft_packets < (FFT_NUM_SAMPLES)) { + if (num_fft_packets < FFT_NUM_SAMPLES) { ath_dbg(common, DFS, "not enough packets for chirp\n"); return false; } -- cgit v1.2.3 From 7cae35199bee1cd661926f2d68ac46d07682fc54 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 3 Apr 2018 18:51:52 +0200 Subject: wcn36xx: check for DMA mapping errors in wcn36xx_dxe_tx_frame() Bail out if the mapping fails. Even though this hasn't occured during tests, this unlikely case should still be handled. Signed-off-by: Daniel Mack Acked-by: Ramon Fried Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/dxe.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index 2c3b899a88fa..405d350f8708 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -705,6 +705,11 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, ctl->skb->data, ctl->skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(wcn->dev, desc->src_addr_l)) { + dev_err(wcn->dev, "unable to DMA map src_addr_l\n"); + ret = -ENOMEM; + goto unlock; + } desc->dst_addr_l = ch->dxe_wq; desc->fr_len = ctl->skb->len; -- cgit v1.2.3 From 271f1e65ff38f18aa440fec17c759e70a6adfa4e Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 3 Apr 2018 18:51:53 +0200 Subject: wcn36xx: don't keep reference to skb if transmission failed When wcn36xx_dxe_tx_frame() fails to transmit the TX frame, the driver will call into ieee80211_free_txskb() for the skb in flight, so it'll no longer be valid. Hence, we shouldn't keep a reference to it in ctl->skb. Also, if the skb has IEEE80211_TX_CTL_REQ_TX_STATUS set, a pointer to it will currently remain in wcn->tx_ack_skb, which will potentially lead to a crash if accessed later. Fix this by checking the return value of wcn36xx_dxe_tx_frame(), and nullify wcn->tx_ack_skb again in case of errors. Move the assignment of ctl->skb in wcn36xx_dxe_tx_frame() so it only happens when the transmission is successful. Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/dxe.c | 6 +++--- drivers/net/wireless/ath/wcn36xx/txrx.c | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index 405d350f8708..2cedb5a4f9e3 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -693,7 +693,6 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, /* Set source address of the SKB we send */ ctl = ctl->next; - ctl->skb = skb; desc = ctl->desc; if (ctl->bd_cpu_addr) { wcn36xx_err("bd_cpu_addr cannot be NULL for skb DXE\n"); @@ -702,8 +701,8 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, } desc->src_addr_l = dma_map_single(wcn->dev, - ctl->skb->data, - ctl->skb->len, + skb->data, + skb->len, DMA_TO_DEVICE); if (dma_mapping_error(wcn->dev, desc->src_addr_l)) { dev_err(wcn->dev, "unable to DMA map src_addr_l\n"); @@ -711,6 +710,7 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, goto unlock; } + ctl->skb = skb; desc->dst_addr_l = ch->dxe_wq; desc->fr_len = ctl->skb->len; diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index b1768ed6b0be..a6902371e89c 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -273,6 +273,7 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, bool bcast = is_broadcast_ether_addr(hdr->addr1) || is_multicast_ether_addr(hdr->addr1); struct wcn36xx_tx_bd bd; + int ret; memset(&bd, 0, sizeof(bd)); @@ -317,5 +318,17 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, buff_to_be((u32 *)&bd, sizeof(bd)/sizeof(u32)); bd.tx_bd_sign = 0xbdbdbdbd; - return wcn36xx_dxe_tx_frame(wcn, vif_priv, &bd, skb, is_low); + ret = wcn36xx_dxe_tx_frame(wcn, vif_priv, &bd, skb, is_low); + if (ret && bd.tx_comp) { + /* If the skb has not been transmitted, + * don't keep a reference to it. + */ + spin_lock_irqsave(&wcn->dxe_lock, flags); + wcn->tx_ack_skb = NULL; + spin_unlock_irqrestore(&wcn->dxe_lock, flags); + + ieee80211_wake_queues(wcn->hw); + } + + return ret; } -- cgit v1.2.3 From 2edfcf2b303cdd63fe0176c6771b47af2d655f8e Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 3 Apr 2018 18:51:54 +0200 Subject: wcn36xx: don't delete invalid bss indices The firmware code cannot cope with requests to remove BSS indices that have not previously been added. This primarily happens when the device is suspended and then resumed. ieee80211_reconfig() then calls into wcn36xx_bss_info_changed() with an empty bssid and BSS_CHANGED_BSSID set, which subsequently leads to a firmware crash: [ 43.647928] qcom-wcnss-pil a204000.wcnss: fatal error received: halMsg.c:4964:halMsg_DelBss: Invalid BSSIndex 0 [ 43.647959] remoteproc remoteproc0: crash detected in a204000.wcnss: type fatal error To fix this, set bss_index to WCN36XX_HAL_BSS_INVALID_IDX for all bss that have not been configured in the firmware, and don't call into the firmware with invalid indices. Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/main.c | 1 + drivers/net/wireless/ath/wcn36xx/smd.c | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 69d6be59d97f..32bbd6e2fd09 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -953,6 +953,7 @@ static int wcn36xx_add_interface(struct ieee80211_hw *hw, mutex_lock(&wcn->conf_mutex); + vif_priv->bss_index = WCN36XX_HAL_BSS_INVALID_IDX; list_add(&vif_priv->list, &wcn->vif_list); wcn36xx_smd_add_sta_self(wcn, vif); diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 8932af5e4d8d..5be07e40a86d 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -1446,6 +1446,10 @@ int wcn36xx_smd_delete_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif) int ret = 0; mutex_lock(&wcn->hal_mutex); + + if (vif_priv->bss_index == WCN36XX_HAL_BSS_INVALID_IDX) + goto out; + INIT_HAL_MSG(msg_body, WCN36XX_HAL_DELETE_BSS_REQ); msg_body.bss_index = vif_priv->bss_index; @@ -1464,6 +1468,8 @@ int wcn36xx_smd_delete_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif) wcn36xx_err("hal_delete_bss response failed err=%d\n", ret); goto out; } + + vif_priv->bss_index = WCN36XX_HAL_BSS_INVALID_IDX; out: mutex_unlock(&wcn->hal_mutex); return ret; -- cgit v1.2.3 From 1391cce7daf65dce586aba78df13b0cc4e737416 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Thu, 5 Apr 2018 13:51:49 +0200 Subject: wcn36xx: Add missing fall through comment in smd.c This prevents GCC warning. Reported-by: Dan Carpenter Signed-off-by: Loic Poulain Acked-by: Bjorn Andersson Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/smd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 5be07e40a86d..9827a1e1124b 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -2143,6 +2143,7 @@ static int wcn36xx_smd_hw_scan_ind(struct wcn36xx *wcn, void *buf, size_t len) switch (rsp->type) { case WCN36XX_HAL_SCAN_IND_FAILED: scan_info.aborted = true; + /* fall through */ case WCN36XX_HAL_SCAN_IND_COMPLETED: mutex_lock(&wcn->scan_lock); wcn->scan_req = NULL; -- cgit v1.2.3 From 6062546d9b7fecd93b9ad5ed6a34d4741cf3c51a Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 6 Apr 2018 12:11:28 +0200 Subject: wcn36xx: Remove useless skb spinlock Each DXE control block is associated to a specific channel. The channel lock is always taken before accessing a control block. There is no need to have an extra (useless) spinlock for the control block skb. Signed-off-by: Loic Poulain Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/dxe.c | 8 +------- drivers/net/wireless/ath/wcn36xx/dxe.h | 1 - 2 files changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index 2cedb5a4f9e3..a1541a8f5212 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -78,7 +78,6 @@ static int wcn36xx_dxe_allocate_ctl_block(struct wcn36xx_dxe_ch *ch) if (!cur_ctl) goto out_fail; - spin_lock_init(&cur_ctl->skb_lock); cur_ctl->ctl_blk_order = i; if (i == 0) { ch->head_blk_ctl = cur_ctl; @@ -377,12 +376,11 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch) /* Keep frame until TX status comes */ ieee80211_free_txskb(wcn->hw, ctl->skb); } - spin_lock(&ctl->skb_lock); + if (wcn->queues_stopped) { wcn->queues_stopped = false; ieee80211_wake_queues(wcn->hw); } - spin_unlock(&ctl->skb_lock); ctl->skb = NULL; } @@ -654,8 +652,6 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, spin_lock_irqsave(&ch->lock, flags); ctl = ch->head_blk_ctl; - spin_lock(&ctl->next->skb_lock); - /* * If skb is not null that means that we reached the tail of the ring * hence ring is full. Stop queues to let mac80211 back off until ring @@ -664,11 +660,9 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, if (NULL != ctl->next->skb) { ieee80211_stop_queues(wcn->hw); wcn->queues_stopped = true; - spin_unlock(&ctl->next->skb_lock); spin_unlock_irqrestore(&ch->lock, flags); return -EBUSY; } - spin_unlock(&ctl->next->skb_lock); ctl->skb = NULL; desc = ctl->desc; diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.h b/drivers/net/wireless/ath/wcn36xx/dxe.h index ce580960d109..31b81b7547a3 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.h +++ b/drivers/net/wireless/ath/wcn36xx/dxe.h @@ -422,7 +422,6 @@ struct wcn36xx_dxe_ctl { unsigned int desc_phy_addr; int ctl_blk_order; struct sk_buff *skb; - spinlock_t skb_lock; void *bd_cpu_addr; dma_addr_t bd_phy_addr; }; -- cgit v1.2.3 From 5151a673da43fbaeb62fcbd20814a3cdd4dd3afd Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 10 Apr 2018 17:52:45 +0300 Subject: wcn36xx: allocate skbs with GFP_KERNEL during init GFP_ATOMIC should only be used when the allocation is done from atomic context. Introduce a new flag to wcn36xx_dxe_fill_skb() and use GFP_KERNEL when pre-allocating buffers during init. This doesn't fix an issue that was observed in the wild, but it reduces the chance of failed allocations under memory pressure. Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/dxe.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index a1541a8f5212..a6702ada13d3 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -274,12 +274,14 @@ static int wcn36xx_dxe_enable_ch_int(struct wcn36xx *wcn, u16 wcn_ch) return 0; } -static int wcn36xx_dxe_fill_skb(struct device *dev, struct wcn36xx_dxe_ctl *ctl) +static int wcn36xx_dxe_fill_skb(struct device *dev, + struct wcn36xx_dxe_ctl *ctl, + gfp_t gfp) { struct wcn36xx_dxe_desc *dxe = ctl->desc; struct sk_buff *skb; - skb = alloc_skb(WCN36XX_PKT_SIZE, GFP_ATOMIC); + skb = alloc_skb(WCN36XX_PKT_SIZE, gfp); if (skb == NULL) return -ENOMEM; @@ -306,7 +308,7 @@ static int wcn36xx_dxe_ch_alloc_skb(struct wcn36xx *wcn, cur_ctl = wcn_ch->head_blk_ctl; for (i = 0; i < wcn_ch->desc_num; i++) { - wcn36xx_dxe_fill_skb(wcn->dev, cur_ctl); + wcn36xx_dxe_fill_skb(wcn->dev, cur_ctl, GFP_KERNEL); cur_ctl = cur_ctl->next; } @@ -531,7 +533,7 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn, while (!(dxe->ctrl & WCN36xx_DXE_CTRL_VLD)) { skb = ctl->skb; dma_addr = dxe->dst_addr_l; - ret = wcn36xx_dxe_fill_skb(wcn->dev, ctl); + ret = wcn36xx_dxe_fill_skb(wcn->dev, ctl, GFP_ATOMIC); if (0 == ret) { /* new skb allocation ok. Use the new one and queue * the old one to network system. -- cgit v1.2.3 From e4a2eb8995365858f0dad6985b119313f0a4624f Mon Sep 17 00:00:00 2001 From: Bjoern Johansson Date: Wed, 11 Apr 2018 11:41:56 -0700 Subject: mac80211_hwsim: indicate support for powersave. Without this, higher layers in the kernel will return an error code when trying to set the power state because the driver doesn't indicate power state support. This in turn causes VTS (Android Vendor Test Suite) failures because the WiFi HAL can't enable power saving mode. Signed-off-by: Bjoern Johansson Signed-off-by: Lingfeng Yang Signed-off-by: Roman Kiryanov [johannes: remove remaining code, it was useless even as a skeleton since it didn't even have the right function arguments] Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 96d26cfae90b..7bfbc5916e9a 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2650,6 +2650,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, ieee80211_hw_set(hw, AMPDU_AGGREGATION); ieee80211_hw_set(hw, MFP_CAPABLE); ieee80211_hw_set(hw, SIGNAL_DBM); + ieee80211_hw_set(hw, SUPPORTS_PS); ieee80211_hw_set(hw, TDLS_WIDER_BW); if (rctbl) ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); -- cgit v1.2.3 From 235b9c42766129b2534d1dd4021e04d39128901a Mon Sep 17 00:00:00 2001 From: Venkateswara Naralasetty Date: Tue, 10 Apr 2018 18:01:05 +0300 Subject: ath10k: Add tx ack signal support for management frames This patch add support to get RSSI from acknowledgment frames for transmitted management frames. hardware_used: QCA4019, QCA9984. firmware version: 10.4-3.5.3-00052. Signed-off-by: Venkateswara Naralasetty Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 2 ++ drivers/net/wireless/ath/ath10k/htt.h | 10 +++++++++- drivers/net/wireless/ath/ath10k/htt_rx.c | 10 ++++++++++ drivers/net/wireless/ath/ath10k/txrx.c | 8 ++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 7 +++++++ 5 files changed, 36 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index c17d805d68cc..e4ac8f2831fd 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -52,6 +52,8 @@ /* Antenna noise floor */ #define ATH10K_DEFAULT_NOISE_FLOOR -95 +#define ATH10K_INVALID_RSSI 128 + #define ATH10K_MAX_NUM_MGMT_PENDING 128 /* number of failed packets (20 packets with 16 sw reties each) */ diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 8cc2a8b278e4..e5dbb0bdd787 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -533,12 +534,18 @@ struct htt_ver_resp { u8 rsvd0; } __packed; +#define HTT_MGMT_TX_CMPL_FLAG_ACK_RSSI BIT(0) + +#define HTT_MGMT_TX_CMPL_INFO_ACK_RSSI_MASK GENMASK(7, 0) + struct htt_mgmt_tx_completion { u8 rsvd0; u8 rsvd1; - u8 rsvd2; + u8 flags; __le32 desc_id; __le32 status; + __le32 ppdu_id; + __le32 info; } __packed; #define HTT_RX_INDICATION_INFO0_EXT_TID_MASK (0x1F) @@ -1648,6 +1655,7 @@ struct htt_resp { struct htt_tx_done { u16 msdu_id; u16 status; + u8 ack_rssi; }; enum htt_tx_compl_state { diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 5e02e26158f6..0315bdad7f85 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -25,6 +25,7 @@ #include "mac.h" #include +#include /* when under memory pressure rx ring refill may fail and needs a retry */ #define HTT_RX_RING_REFILL_RETRY_MS 50 @@ -2719,12 +2720,21 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) case HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION: { struct htt_tx_done tx_done = {}; int status = __le32_to_cpu(resp->mgmt_tx_completion.status); + int info = __le32_to_cpu(resp->mgmt_tx_completion.info); tx_done.msdu_id = __le32_to_cpu(resp->mgmt_tx_completion.desc_id); switch (status) { case HTT_MGMT_TX_STATUS_OK: tx_done.status = HTT_TX_COMPL_STATE_ACK; + if (test_bit(WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, + ar->wmi.svc_map) && + (resp->mgmt_tx_completion.flags & + HTT_MGMT_TX_CMPL_FLAG_ACK_RSSI)) { + tx_done.ack_rssi = + FIELD_GET(HTT_MGMT_TX_CMPL_INFO_ACK_RSSI_MASK, + info); + } break; case HTT_MGMT_TX_STATUS_RETRY: tx_done.status = HTT_TX_COMPL_STATE_NOACK; diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 70e23bbf7171..cda164f6e9f6 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2016 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -119,6 +120,13 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt, info->flags &= ~IEEE80211_TX_STAT_ACK; } + if (tx_done->status == HTT_TX_COMPL_STATE_ACK && + tx_done->ack_rssi != ATH10K_INVALID_RSSI) { + info->status.ack_signal = ATH10K_DEFAULT_NOISE_FLOOR + + tx_done->ack_rssi; + info->status.is_valid_ack_signal = true; + } + ieee80211_tx_status(htt->ar->hw, msdu); /* we do not own the msdu anymore */ diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 6fbc84c29521..3cc129d812a4 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -201,6 +201,7 @@ enum wmi_service { WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, WMI_SERVICE_HOST_DFS_CHECK_SUPPORT, WMI_SERVICE_TPC_STATS_FINAL, + WMI_SERVICE_RESET_CHIP, /* keep last */ WMI_SERVICE_MAX, @@ -238,6 +239,8 @@ enum wmi_10x_service { WMI_10X_SERVICE_MESH, WMI_10X_SERVICE_EXT_RES_CFG_SUPPORT, WMI_10X_SERVICE_PEER_STATS, + WMI_10X_SERVICE_RESET_CHIP, + WMI_10X_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, }; enum wmi_main_service { @@ -548,6 +551,10 @@ static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out, WMI_SERVICE_EXT_RES_CFG_SUPPORT, len); SVCMAP(WMI_10X_SERVICE_PEER_STATS, WMI_SERVICE_PEER_STATS, len); + SVCMAP(WMI_10X_SERVICE_RESET_CHIP, + WMI_SERVICE_RESET_CHIP, len); + SVCMAP(WMI_10X_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, + WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, len); } static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out, -- cgit v1.2.3 From a0aedd6e0b5755a4c1cf288744a0fbef667f9f8f Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:11 +0300 Subject: ath10k: build ce layer in ath10k core module CE layer is shared between pci and snoc target and results in duplicate object inclusion if both modules are compiled together statically and undefined KBUILD_MODNAME if compiled as module. Fix this by building ce layer in ath10k core module by adding ce object inclusion with ATH10K_CE boolean CONFIG. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/Kconfig | 4 ++++ drivers/net/wireless/ath/ath10k/Makefile | 4 ++-- drivers/net/wireless/ath/ath10k/ce.c | 22 ++++++++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index deb5ae21a559..d266f2792dae 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -4,12 +4,16 @@ config ATH10K select ATH_COMMON select CRC32 select WANT_DEV_COREDUMP + select ATH10K_CE ---help--- This module adds support for wireless adapters based on Atheros IEEE 802.11ac family of chipsets. If you choose to build a module, it'll be called ath10k. +config ATH10K_CE + bool + config ATH10K_PCI tristate "Atheros ath10k PCI support" depends on ATH10K && PCI diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 6739ac26fd29..536f3dfb9364 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -22,10 +22,10 @@ ath10k_core-$(CONFIG_THERMAL) += thermal.o ath10k_core-$(CONFIG_MAC80211_DEBUGFS) += debugfs_sta.o ath10k_core-$(CONFIG_PM) += wow.o ath10k_core-$(CONFIG_DEV_COREDUMP) += coredump.o +ath10k_core-$(CONFIG_ATH10K_CE) += ce.o obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o -ath10k_pci-y += pci.o \ - ce.o +ath10k_pci-y += pci.o ath10k_pci-$(CONFIG_ATH10K_AHB) += ahb.o diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index b9def7bace2f..e7e7b342e5b8 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -464,6 +464,7 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, return ce_state->ops->ce_send_nolock(ce_state, per_transfer_context, buffer, nbytes, transfer_id, flags); } +EXPORT_SYMBOL(ath10k_ce_send_nolock); void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe) { @@ -491,6 +492,7 @@ void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe) src_ring->per_transfer_context[src_ring->write_index] = NULL; } +EXPORT_SYMBOL(__ath10k_ce_send_revert); int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, void *per_transfer_context, @@ -510,6 +512,7 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, return ret; } +EXPORT_SYMBOL(ath10k_ce_send); int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe) { @@ -525,6 +528,7 @@ int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe) return delta; } +EXPORT_SYMBOL(ath10k_ce_num_free_src_entries); int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe) { @@ -539,6 +543,7 @@ int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe) return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1); } +EXPORT_SYMBOL(__ath10k_ce_rx_num_free_bufs); static int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, dma_addr_t paddr) @@ -622,6 +627,7 @@ void ath10k_ce_rx_update_write_idx(struct ath10k_ce_pipe *pipe, u32 nentries) ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index); dest_ring->write_index = write_index; } +EXPORT_SYMBOL(ath10k_ce_rx_update_write_idx); int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, dma_addr_t paddr) @@ -636,6 +642,7 @@ int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, return ret; } +EXPORT_SYMBOL(ath10k_ce_rx_post_buf); /* * Guts of ath10k_ce_completed_recv_next. @@ -748,6 +755,7 @@ int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state, per_transfer_ctx, nbytesp); } +EXPORT_SYMBOL(ath10k_ce_completed_recv_next_nolock); int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state, void **per_transfer_contextp, @@ -766,6 +774,7 @@ int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state, return ret; } +EXPORT_SYMBOL(ath10k_ce_completed_recv_next); static int _ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, void **per_transfer_contextp, @@ -882,6 +891,7 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, per_transfer_contextp, bufferp); } +EXPORT_SYMBOL(ath10k_ce_revoke_recv_next); /* * Guts of ath10k_ce_completed_send_next. @@ -936,6 +946,7 @@ int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, return 0; } +EXPORT_SYMBOL(ath10k_ce_completed_send_next_nolock); static void ath10k_ce_extract_desc_data(struct ath10k *ar, struct ath10k_ce_ring *src_ring, @@ -1025,6 +1036,7 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state, return ret; } +EXPORT_SYMBOL(ath10k_ce_cancel_send_next); int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state, void **per_transfer_contextp) @@ -1040,6 +1052,7 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state, return ret; } +EXPORT_SYMBOL(ath10k_ce_completed_send_next); /* * Guts of interrupt handler for per-engine interrupts on a particular CE. @@ -1078,6 +1091,7 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) spin_unlock_bh(&ce->ce_lock); } +EXPORT_SYMBOL(ath10k_ce_per_engine_service); /* * Handler for per-engine interrupts on ALL active CEs. @@ -1102,6 +1116,7 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar) ath10k_ce_per_engine_service(ar, ce_id); } } +EXPORT_SYMBOL(ath10k_ce_per_engine_service_any); /* * Adjust interrupts for the copy complete handler. @@ -1139,6 +1154,7 @@ int ath10k_ce_disable_interrupts(struct ath10k *ar) return 0; } +EXPORT_SYMBOL(ath10k_ce_disable_interrupts); void ath10k_ce_enable_interrupts(struct ath10k *ar) { @@ -1154,6 +1170,7 @@ void ath10k_ce_enable_interrupts(struct ath10k *ar) ath10k_ce_per_engine_handler_adjust(ce_state); } } +EXPORT_SYMBOL(ath10k_ce_enable_interrupts); static int ath10k_ce_init_src_ring(struct ath10k *ar, unsigned int ce_id, @@ -1454,6 +1471,7 @@ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, return 0; } +EXPORT_SYMBOL(ath10k_ce_init_pipe); static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id) { @@ -1479,6 +1497,7 @@ void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id) ath10k_ce_deinit_src_ring(ar, ce_id); ath10k_ce_deinit_dest_ring(ar, ce_id); } +EXPORT_SYMBOL(ath10k_ce_deinit_pipe); static void _ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) { @@ -1545,6 +1564,7 @@ void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) ce_state->ops->ce_free_pipe(ar, ce_id); } +EXPORT_SYMBOL(ath10k_ce_free_pipe); void ath10k_ce_dump_registers(struct ath10k *ar, struct ath10k_fw_crash_data *crash_data) @@ -1584,6 +1604,7 @@ void ath10k_ce_dump_registers(struct ath10k *ar, spin_unlock_bh(&ce->ce_lock); } +EXPORT_SYMBOL(ath10k_ce_dump_registers); static const struct ath10k_ce_ops ce_ops = { .ce_alloc_src_ring = ath10k_ce_alloc_src_ring, @@ -1680,3 +1701,4 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, return 0; } +EXPORT_SYMBOL(ath10k_ce_alloc_pipe); -- cgit v1.2.3 From 17f5559e0da51a8780cd93206689f05feca46615 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:14 +0300 Subject: ath10k: platform driver for WCN3990 SNOC WLAN module WCN3990 is integrated 802.11ac chipset with SNOC bus interface. Add snoc layer driver registration and associated ops. WCN3990 support is not yet complete as cold-boot handshake is done using qmi(Qualcomm-MSM-Interface) and qmi client support will be added once qmi framework is available. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/Kconfig | 8 ++ drivers/net/wireless/ath/ath10k/Makefile | 3 + drivers/net/wireless/ath/ath10k/snoc.c | 153 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/snoc.h | 76 +++++++++++++++ 4 files changed, 240 insertions(+) create mode 100644 drivers/net/wireless/ath/ath10k/snoc.c create mode 100644 drivers/net/wireless/ath/ath10k/snoc.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index d266f2792dae..84f071ac0d84 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -40,6 +40,14 @@ config ATH10K_USB This module adds experimental support for USB bus. Currently work in progress and will not fully work. +config ATH10K_SNOC + tristate "Qualcomm ath10k SNOC support (EXPERIMENTAL)" + depends on ATH10K && ARCH_QCOM + ---help--- + This module adds support for integrated WCN3990 chip connected + to system NOC(SNOC). Currently work in progress and will not + fully work. + config ATH10K_DEBUG bool "Atheros ath10k debugging" depends on ATH10K diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 536f3dfb9364..44d60a61b242 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -35,5 +35,8 @@ ath10k_sdio-y += sdio.o obj-$(CONFIG_ATH10K_USB) += ath10k_usb.o ath10k_usb-y += usb.o +obj-$(CONFIG_ATH10K_SNOC) += ath10k_snoc.o +ath10k_snoc-y += snoc.o + # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c new file mode 100644 index 000000000000..30354a653b62 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include "debug.h" +#include "hif.h" +#include "htc.h" +#include "ce.h" +#include "snoc.h" +#include +#include +#include + +static const struct ath10k_snoc_drv_priv drv_priv = { + .hw_rev = ATH10K_HW_WCN3990, + .dma_mask = DMA_BIT_MASK(37), +}; + +void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + + iowrite32(value, ar_snoc->mem + offset); +} + +u32 ath10k_snoc_read32(struct ath10k *ar, u32 offset) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + u32 val; + + val = ioread32(ar_snoc->mem + offset); + + return val; +} + +static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { + .read32 = ath10k_snoc_read32, + .write32 = ath10k_snoc_write32, +}; + +static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { + .read32 = ath10k_snoc_read32, + .write32 = ath10k_snoc_write32, +}; + +static const struct of_device_id ath10k_snoc_dt_match[] = { + { .compatible = "qcom,wcn3990-wifi", + .data = &drv_priv, + }, + { } +}; +MODULE_DEVICE_TABLE(of, ath10k_snoc_dt_match); + +static int ath10k_snoc_probe(struct platform_device *pdev) +{ + const struct ath10k_snoc_drv_priv *drv_data; + const struct of_device_id *of_id; + struct ath10k_snoc *ar_snoc; + struct device *dev; + struct ath10k *ar; + int ret; + + of_id = of_match_device(ath10k_snoc_dt_match, &pdev->dev); + if (!of_id) { + dev_err(&pdev->dev, "failed to find matching device tree id\n"); + return -EINVAL; + } + + drv_data = of_id->data; + dev = &pdev->dev; + + ret = dma_set_mask_and_coherent(dev, drv_data->dma_mask); + if (ret) { + dev_err(dev, "failed to set dma mask: %d", ret); + return ret; + } + + ar = ath10k_core_create(sizeof(*ar_snoc), dev, ATH10K_BUS_SNOC, + drv_data->hw_rev, &ath10k_snoc_hif_ops); + if (!ar) { + dev_err(dev, "failed to allocate core\n"); + return -ENOMEM; + } + + ar_snoc = ath10k_snoc_priv(ar); + ar_snoc->dev = pdev; + platform_set_drvdata(pdev, ar); + ar_snoc->ar = ar; + ar_snoc->ce.bus_ops = &ath10k_snoc_bus_ops; + ar->ce_priv = &ar_snoc->ce; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n"); + ath10k_warn(ar, "Warning: SNOC support is still work-in-progress, it will not work properly!"); + + return ret; +} + +static int ath10k_snoc_remove(struct platform_device *pdev) +{ + struct ath10k *ar = platform_get_drvdata(pdev); + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc remove\n"); + ath10k_core_destroy(ar); + + return 0; +} + +static struct platform_driver ath10k_snoc_driver = { + .probe = ath10k_snoc_probe, + .remove = ath10k_snoc_remove, + .driver = { + .name = "ath10k_snoc", + .owner = THIS_MODULE, + .of_match_table = ath10k_snoc_dt_match, + }, +}; + +static int __init ath10k_snoc_init(void) +{ + int ret; + + ret = platform_driver_register(&ath10k_snoc_driver); + if (ret) + pr_err("failed to register ath10k snoc driver: %d\n", + ret); + + return ret; +} +module_init(ath10k_snoc_init); + +static void __exit ath10k_snoc_exit(void) +{ + platform_driver_unregister(&ath10k_snoc_driver); +} +module_exit(ath10k_snoc_exit); + +MODULE_AUTHOR("Qualcomm"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("Driver support for Atheros WCN3990 SNOC devices"); diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h new file mode 100644 index 000000000000..cf65b01e0085 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SNOC_H_ +#define _SNOC_H_ + +#include "hw.h" +#include "ce.h" +#include "pci.h" + +struct ath10k_snoc_drv_priv { + enum ath10k_hw_rev hw_rev; + u64 dma_mask; +}; + +struct snoc_state { + u32 pipe_cfg_addr; + u32 svc_to_pipe_map; +}; + +struct ath10k_snoc_pipe { + struct ath10k_ce_pipe *ce_hdl; + u8 pipe_num; + struct ath10k *hif_ce_state; + size_t buf_sz; + /* protect ce info */ + spinlock_t pipe_lock; + struct ath10k_snoc *ar_snoc; +}; + +struct ath10k_snoc_target_info { + u32 target_version; + u32 target_type; + u32 target_revision; + u32 soc_version; +}; + +struct ath10k_snoc_ce_irq { + u32 irq_line; +}; + +struct ath10k_snoc { + struct platform_device *dev; + struct ath10k *ar; + void __iomem *mem; + dma_addr_t mem_pa; + struct ath10k_snoc_target_info target_info; + size_t mem_len; + struct ath10k_snoc_pipe pipe_info[CE_COUNT_MAX]; + struct ath10k_snoc_ce_irq ce_irqs[CE_COUNT_MAX]; + struct ath10k_ce ce; + struct timer_list rx_post_retry; +}; + +static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar) +{ + return (struct ath10k_snoc *)ar->drv_priv; +} + +void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value); +u32 ath10k_snoc_read32(struct ath10k *ar, u32 offset); + +#endif /* _SNOC_H_ */ -- cgit v1.2.3 From c963a683e70151dc458e9a85ed4b366b09f65e57 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:15 +0300 Subject: ath10k: add resource init and deinit for WCN3990 Add methods for resource(memory, irq, HOST CE config) initialization and de-initialization for WCN3990 target. WCN3990 target uses 12 copy engine and following CE config. [CE0] :host->target control and raw streams [CE1] :target->host HTT [CE2] :target->host WMI [CE3] :host->target WMI [CE4] :host->target HTT [CE5] :reserved [CE6] :Target autonomous HIF_memcpy [CE7] :reserved [CE8] :reserved [CE9] :target->host HTT [CE10] :target->host HTT [CE11] :target -> host PKTLOG Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/snoc.c | 271 +++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 30354a653b62..575355ce675f 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -24,12 +24,135 @@ #include #include #include +#define WCN3990_CE_ATTR_FLAGS 0 + +static char *const ce_name[] = { + "WLAN_CE_0", + "WLAN_CE_1", + "WLAN_CE_2", + "WLAN_CE_3", + "WLAN_CE_4", + "WLAN_CE_5", + "WLAN_CE_6", + "WLAN_CE_7", + "WLAN_CE_8", + "WLAN_CE_9", + "WLAN_CE_10", + "WLAN_CE_11", +}; static const struct ath10k_snoc_drv_priv drv_priv = { .hw_rev = ATH10K_HW_WCN3990, .dma_mask = DMA_BIT_MASK(37), }; +static struct ce_attr host_ce_config_wlan[] = { + /* CE0: host->target HTC control streams */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 16, + .src_sz_max = 2048, + .dest_nentries = 0, + .send_cb = NULL, + }, + + /* CE1: target->host HTT + HTC control */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 512, + .recv_cb = NULL, + }, + + /* CE2: target->host WMI */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 64, + .recv_cb = NULL, + }, + + /* CE3: host->target WMI */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 32, + .src_sz_max = 2048, + .dest_nentries = 0, + .send_cb = NULL, + }, + + /* CE4: host->target HTT */ + { + .flags = WCN3990_CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, + .src_nentries = 256, + .src_sz_max = 256, + .dest_nentries = 0, + .send_cb = NULL, + }, + + /* CE5: target->host HTT (ipa_uc->target ) */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 512, + .dest_nentries = 512, + .recv_cb = NULL, + }, + + /* CE6: target autonomous hif_memcpy */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 0, + .dest_nentries = 0, + }, + + /* CE7: ce_diag, the Diagnostic Window */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 2, + .src_sz_max = 2048, + .dest_nentries = 2, + }, + + /* CE8: Target to uMC */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 128, + }, + + /* CE9 target->host HTT */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 512, + .recv_cb = NULL, + }, + + /* CE10: target->host HTT */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 512, + .recv_cb = NULL, + }, + + /* CE11: target -> host PKTLOG */ + { + .flags = WCN3990_CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 512, + .recv_cb = NULL, + }, +}; + void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); @@ -57,6 +180,119 @@ static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { .write32 = ath10k_snoc_write32, }; +static irqreturn_t ath10k_snoc_per_engine_handler(int irq, void *arg) +{ + return IRQ_HANDLED; +} + +static int ath10k_snoc_request_irq(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + int irqflags = IRQF_TRIGGER_RISING; + int ret, id; + + for (id = 0; id < CE_COUNT_MAX; id++) { + ret = request_irq(ar_snoc->ce_irqs[id].irq_line, + ath10k_snoc_per_engine_handler, + irqflags, ce_name[id], ar); + if (ret) { + ath10k_err(ar, + "failed to register IRQ handler for CE %d: %d", + id, ret); + goto err_irq; + } + } + + return 0; + +err_irq: + for (id -= 1; id >= 0; id--) + free_irq(ar_snoc->ce_irqs[id].irq_line, ar); + + return ret; +} + +static void ath10k_snoc_free_irq(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + int id; + + for (id = 0; id < CE_COUNT_MAX; id++) + free_irq(ar_snoc->ce_irqs[id].irq_line, ar); +} + +static int ath10k_snoc_resource_init(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct platform_device *pdev; + struct resource *res; + int i, ret = 0; + + pdev = ar_snoc->dev; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "membase"); + if (!res) { + ath10k_err(ar, "Memory base not found in DT\n"); + return -EINVAL; + } + + ar_snoc->mem_pa = res->start; + ar_snoc->mem = devm_ioremap(&pdev->dev, ar_snoc->mem_pa, + resource_size(res)); + if (!ar_snoc->mem) { + ath10k_err(ar, "Memory base ioremap failed with physical address %pa\n", + &ar_snoc->mem_pa); + return -EINVAL; + } + + for (i = 0; i < CE_COUNT; i++) { + res = platform_get_resource(ar_snoc->dev, IORESOURCE_IRQ, i); + if (!res) { + ath10k_err(ar, "failed to get IRQ%d\n", i); + ret = -ENODEV; + goto out; + } + ar_snoc->ce_irqs[i].irq_line = res->start; + } + +out: + return ret; +} + +static int ath10k_snoc_setup_resource(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct ath10k_snoc_pipe *pipe; + int i, ret; + + spin_lock_init(&ce->ce_lock); + for (i = 0; i < CE_COUNT; i++) { + pipe = &ar_snoc->pipe_info[i]; + pipe->ce_hdl = &ce->ce_states[i]; + pipe->pipe_num = i; + pipe->hif_ce_state = ar; + + ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]); + if (ret) { + ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n", + i, ret); + return ret; + } + + pipe->buf_sz = host_ce_config_wlan[i].src_sz_max; + } + + return 0; +} + +static void ath10k_snoc_release_resource(struct ath10k *ar) +{ + int i; + + for (i = 0; i < CE_COUNT; i++) + ath10k_ce_free_pipe(ar, i); +} + static const struct of_device_id ath10k_snoc_dt_match[] = { { .compatible = "qcom,wcn3990-wifi", .data = &drv_priv, @@ -103,9 +339,41 @@ static int ath10k_snoc_probe(struct platform_device *pdev) ar_snoc->ce.bus_ops = &ath10k_snoc_bus_ops; ar->ce_priv = &ar_snoc->ce; + ath10k_snoc_resource_init(ar); + if (ret) { + ath10k_warn(ar, "failed to initialize resource: %d\n", ret); + goto err_core_destroy; + } + + ath10k_snoc_setup_resource(ar); + if (ret) { + ath10k_warn(ar, "failed to setup resource: %d\n", ret); + goto err_core_destroy; + } + ret = ath10k_snoc_request_irq(ar); + if (ret) { + ath10k_warn(ar, "failed to request irqs: %d\n", ret); + goto err_release_resource; + } + ret = ath10k_core_register(ar, drv_data->hw_rev); + if (ret) { + ath10k_err(ar, "failed to register driver core: %d\n", ret); + goto err_free_irq; + } ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n"); ath10k_warn(ar, "Warning: SNOC support is still work-in-progress, it will not work properly!"); + return 0; + +err_free_irq: + ath10k_snoc_free_irq(ar); + +err_release_resource: + ath10k_snoc_release_resource(ar); + +err_core_destroy: + ath10k_core_destroy(ar); + return ret; } @@ -114,6 +382,9 @@ static int ath10k_snoc_remove(struct platform_device *pdev) struct ath10k *ar = platform_get_drvdata(pdev); ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc remove\n"); + ath10k_core_unregister(ar); + ath10k_snoc_free_irq(ar); + ath10k_snoc_release_resource(ar); ath10k_core_destroy(ar); return 0; -- cgit v1.2.3 From a6e149a9ff03e00b0a4293c0cc70b37db48fdf80 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:17 +0300 Subject: ath10k: add hif start/stop methods for wcn3990 snoc layer Add hif start/stop callback for allocating/freeing buffers on tx/rx pipe and enabling/disabling the tx/rx pipe interrupts. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/snoc.c | 189 ++++++++++++++++++++++++++++++++- 1 file changed, 187 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 575355ce675f..dcd8bb7b71b4 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -25,6 +25,7 @@ #include #include #define WCN3990_CE_ATTR_FLAGS 0 +#define ATH10K_SNOC_RX_POST_RETRY_MS 50 static char *const ce_name[] = { "WLAN_CE_0", @@ -170,9 +171,193 @@ u32 ath10k_snoc_read32(struct ath10k *ar, u32 offset) return val; } +static int __ath10k_snoc_rx_post_buf(struct ath10k_snoc_pipe *pipe) +{ + struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl; + struct ath10k *ar = pipe->hif_ce_state; + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct sk_buff *skb; + dma_addr_t paddr; + int ret; + + skb = dev_alloc_skb(pipe->buf_sz); + if (!skb) + return -ENOMEM; + + WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb"); + + paddr = dma_map_single(ar->dev, skb->data, + skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(ar->dev, paddr))) { + ath10k_warn(ar, "failed to dma map snoc rx buf\n"); + dev_kfree_skb_any(skb); + return -EIO; + } + + ATH10K_SKB_RXCB(skb)->paddr = paddr; + + spin_lock_bh(&ce->ce_lock); + ret = ce_pipe->ops->ce_rx_post_buf(ce_pipe, skb, paddr); + spin_unlock_bh(&ce->ce_lock); + if (ret) { + dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + return ret; + } + + return 0; +} + +static void ath10k_snoc_rx_post_pipe(struct ath10k_snoc_pipe *pipe) +{ + struct ath10k *ar = pipe->hif_ce_state; + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl; + int ret, num; + + if (pipe->buf_sz == 0) + return; + + if (!ce_pipe->dest_ring) + return; + + spin_lock_bh(&ce->ce_lock); + num = __ath10k_ce_rx_num_free_bufs(ce_pipe); + spin_unlock_bh(&ce->ce_lock); + while (num--) { + ret = __ath10k_snoc_rx_post_buf(pipe); + if (ret) { + if (ret == -ENOSPC) + break; + ath10k_warn(ar, "failed to post rx buf: %d\n", ret); + mod_timer(&ar_snoc->rx_post_retry, jiffies + + ATH10K_SNOC_RX_POST_RETRY_MS); + break; + } + } +} + +static void ath10k_snoc_rx_post(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + int i; + + for (i = 0; i < CE_COUNT; i++) + ath10k_snoc_rx_post_pipe(&ar_snoc->pipe_info[i]); +} + +static inline void ath10k_snoc_irq_disable(struct ath10k *ar) +{ + ath10k_ce_disable_interrupts(ar); +} + +static inline void ath10k_snoc_irq_enable(struct ath10k *ar) +{ + ath10k_ce_enable_interrupts(ar); +} + +static void ath10k_snoc_rx_pipe_cleanup(struct ath10k_snoc_pipe *snoc_pipe) +{ + struct ath10k_ce_pipe *ce_pipe; + struct ath10k_ce_ring *ce_ring; + struct sk_buff *skb; + struct ath10k *ar; + int i; + + ar = snoc_pipe->hif_ce_state; + ce_pipe = snoc_pipe->ce_hdl; + ce_ring = ce_pipe->dest_ring; + + if (!ce_ring) + return; + + if (!snoc_pipe->buf_sz) + return; + + for (i = 0; i < ce_ring->nentries; i++) { + skb = ce_ring->per_transfer_context[i]; + if (!skb) + continue; + + ce_ring->per_transfer_context[i] = NULL; + + dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr, + skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + } +} + +static void ath10k_snoc_tx_pipe_cleanup(struct ath10k_snoc_pipe *snoc_pipe) +{ + struct ath10k_ce_pipe *ce_pipe; + struct ath10k_ce_ring *ce_ring; + struct ath10k_snoc *ar_snoc; + struct sk_buff *skb; + struct ath10k *ar; + int i; + + ar = snoc_pipe->hif_ce_state; + ar_snoc = ath10k_snoc_priv(ar); + ce_pipe = snoc_pipe->ce_hdl; + ce_ring = ce_pipe->src_ring; + + if (!ce_ring) + return; + + if (!snoc_pipe->buf_sz) + return; + + for (i = 0; i < ce_ring->nentries; i++) { + skb = ce_ring->per_transfer_context[i]; + if (!skb) + continue; + + ce_ring->per_transfer_context[i] = NULL; + + ath10k_htc_tx_completion_handler(ar, skb); + } +} + +static void ath10k_snoc_buffer_cleanup(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_snoc_pipe *pipe_info; + int pipe_num; + + del_timer_sync(&ar_snoc->rx_post_retry); + for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { + pipe_info = &ar_snoc->pipe_info[pipe_num]; + ath10k_snoc_rx_pipe_cleanup(pipe_info); + ath10k_snoc_tx_pipe_cleanup(pipe_info); + } +} + +static void ath10k_snoc_hif_stop(struct ath10k *ar) +{ + ath10k_snoc_irq_disable(ar); + ath10k_snoc_buffer_cleanup(ar); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n"); +} + +static int ath10k_snoc_hif_start(struct ath10k *ar) +{ + ath10k_snoc_irq_enable(ar); + ath10k_snoc_rx_post(ar); + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n"); + + return 0; +} + static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { - .read32 = ath10k_snoc_read32, - .write32 = ath10k_snoc_write32, + .read32 = ath10k_snoc_read32, + .write32 = ath10k_snoc_write32, + .start = ath10k_snoc_hif_start, + .stop = ath10k_snoc_hif_stop, }; static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { -- cgit v1.2.3 From b8c27e86211832b06667f11be3c24acc78828ee5 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:18 +0300 Subject: ath10k: add HTC services for WCN3990 WCN3990 target uses 3 Copy engine(CE1/CE9/CE10) in RX path and CE 11 for pktlog. Add data path HTC ep services and PKTLOG services for WCN3990. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htc.c | 6 ++++++ drivers/net/wireless/ath/ath10k/htc.h | 4 ++++ 2 files changed, 10 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 492dc5b4bbf2..8902720b4e49 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -542,8 +542,14 @@ static const char *htc_service_name(enum ath10k_htc_svc_id id) return "NMI Data"; case ATH10K_HTC_SVC_ID_HTT_DATA_MSG: return "HTT Data"; + case ATH10K_HTC_SVC_ID_HTT_DATA2_MSG: + return "HTT Data"; + case ATH10K_HTC_SVC_ID_HTT_DATA3_MSG: + return "HTT Data"; case ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS: return "RAW"; + case ATH10K_HTC_SVC_ID_HTT_LOG_MSG: + return "PKTLOG"; } return "Unknown"; diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index a2f8814b3e53..34877597dd6a 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h @@ -248,6 +248,7 @@ enum ath10k_htc_svc_gid { ATH10K_HTC_SVC_GRP_WMI = 1, ATH10K_HTC_SVC_GRP_NMI = 2, ATH10K_HTC_SVC_GRP_HTT = 3, + ATH10K_LOG_SERVICE_GROUP = 6, ATH10K_HTC_SVC_GRP_TEST = 254, ATH10K_HTC_SVC_GRP_LAST = 255, @@ -273,6 +274,9 @@ enum ath10k_htc_svc_id { ATH10K_HTC_SVC_ID_HTT_DATA_MSG = SVC(ATH10K_HTC_SVC_GRP_HTT, 0), + ATH10K_HTC_SVC_ID_HTT_DATA2_MSG = SVC(ATH10K_HTC_SVC_GRP_HTT, 1), + ATH10K_HTC_SVC_ID_HTT_DATA3_MSG = SVC(ATH10K_HTC_SVC_GRP_HTT, 2), + ATH10K_HTC_SVC_ID_HTT_LOG_MSG = SVC(ATH10K_LOG_SERVICE_GROUP, 0), /* raw stream service (i.e. flash, tcmd, calibration apps) */ ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS = SVC(ATH10K_HTC_SVC_GRP_TEST, 0), }; -- cgit v1.2.3 From 84efe7f6ebc56dbeb18c3448a487f2265c647d91 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:20 +0300 Subject: ath10k: map HTC services to tx/rx pipes for wcn3990 Add mapping of HTC endpoint services supported by wcn3990 target to tx/rx pipe. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/snoc.c | 168 +++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index dcd8bb7b71b4..a39eee7ed56c 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -154,6 +154,116 @@ static struct ce_attr host_ce_config_wlan[] = { }, }; +static struct service_to_pipe target_service_to_ce_map_wlan[] = { + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(3), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(0), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { /* not used */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(0), + }, + { /* not used */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(2), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG), + __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ + __cpu_to_le32(4), + }, + { + __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(1), + }, + { /* not used */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS), + __cpu_to_le32(PIPEDIR_OUT), + __cpu_to_le32(5), + }, + { /* in = DL = target -> host */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA2_MSG), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(9), + }, + { /* in = DL = target -> host */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA3_MSG), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(10), + }, + { /* in = DL = target -> host pktlog */ + __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_LOG_MSG), + __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ + __cpu_to_le32(11), + }, + /* (Additions here) */ + + { /* must be last */ + __cpu_to_le32(0), + __cpu_to_le32(0), + __cpu_to_le32(0), + }, +}; + void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); @@ -249,6 +359,62 @@ static void ath10k_snoc_rx_post(struct ath10k *ar) ath10k_snoc_rx_post_pipe(&ar_snoc->pipe_info[i]); } +static int ath10k_snoc_hif_map_service_to_pipe(struct ath10k *ar, + u16 service_id, + u8 *ul_pipe, u8 *dl_pipe) +{ + const struct service_to_pipe *entry; + bool ul_set = false, dl_set = false; + int i; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif map service\n"); + + 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; +} + +static void ath10k_snoc_hif_get_default_pipe(struct ath10k *ar, + u8 *ul_pipe, u8 *dl_pipe) +{ + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif get default pipe\n"); + + (void)ath10k_snoc_hif_map_service_to_pipe(ar, + ATH10K_HTC_SVC_ID_RSVD_CTRL, + ul_pipe, dl_pipe); +} + static inline void ath10k_snoc_irq_disable(struct ath10k *ar) { ath10k_ce_disable_interrupts(ar); @@ -358,6 +524,8 @@ static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .write32 = ath10k_snoc_write32, .start = ath10k_snoc_hif_start, .stop = ath10k_snoc_hif_stop, + .map_service_to_pipe = ath10k_snoc_hif_map_service_to_pipe, + .get_default_pipe = ath10k_snoc_hif_get_default_pipe, }; static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { -- cgit v1.2.3 From 0fa4fbe9b8cf7656813382602a6a5d330f01d3ae Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:22 +0300 Subject: ath10k: add hif power-up/power-down methods Add hif power-up/power-down methods for wcn3990 target. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/snoc.c | 61 ++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index a39eee7ed56c..9d402e4afaf9 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -519,6 +519,65 @@ static int ath10k_snoc_hif_start(struct ath10k *ar) return 0; } +static int ath10k_snoc_init_pipes(struct ath10k *ar) +{ + int i, ret; + + for (i = 0; i < CE_COUNT; i++) { + ret = ath10k_ce_init_pipe(ar, i, &host_ce_config_wlan[i]); + if (ret) { + ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n", + i, ret); + return ret; + } + } + + return 0; +} + +static int ath10k_snoc_wlan_enable(struct ath10k *ar) +{ + return 0; +} + +static void ath10k_snoc_wlan_disable(struct ath10k *ar) +{ +} + +static void ath10k_snoc_hif_power_down(struct ath10k *ar) +{ + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n"); + + ath10k_snoc_wlan_disable(ar); +} + +static int ath10k_snoc_hif_power_up(struct ath10k *ar) +{ + int ret; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 driver state = %d\n", + __func__, ar->state); + + ret = ath10k_snoc_wlan_enable(ar); + if (ret) { + ath10k_err(ar, "failed to enable wcn3990: %d\n", ret); + return ret; + } + + ret = ath10k_snoc_init_pipes(ar); + if (ret) { + ath10k_err(ar, "failed to initialize CE: %d\n", ret); + goto err_wlan_enable; + } + + return 0; + +err_wlan_enable: + ath10k_snoc_wlan_disable(ar); + + return ret; +} + static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .read32 = ath10k_snoc_read32, .write32 = ath10k_snoc_write32, @@ -526,6 +585,8 @@ static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .stop = ath10k_snoc_hif_stop, .map_service_to_pipe = ath10k_snoc_hif_map_service_to_pipe, .get_default_pipe = ath10k_snoc_hif_get_default_pipe, + .power_up = ath10k_snoc_hif_power_up, + .power_down = ath10k_snoc_hif_power_down, }; static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { -- cgit v1.2.3 From d390509bdf501c9c8c6e61248e4bc9314c86d854 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:24 +0300 Subject: ath10k: add hif tx methods for wcn3990 Add hif tx/tx-complete methods for wcn3990 target. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/snoc.c | 123 ++++++++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 9d402e4afaf9..899f0a327050 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -42,6 +42,9 @@ static char *const ce_name[] = { "WLAN_CE_11", }; +static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state); +static void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state); + static const struct ath10k_snoc_drv_priv drv_priv = { .hw_rev = ATH10K_HW_WCN3990, .dma_mask = DMA_BIT_MASK(37), @@ -54,7 +57,7 @@ static struct ce_attr host_ce_config_wlan[] = { .src_nentries = 16, .src_sz_max = 2048, .dest_nentries = 0, - .send_cb = NULL, + .send_cb = ath10k_snoc_htc_tx_cb, }, /* CE1: target->host HTT + HTC control */ @@ -81,7 +84,7 @@ static struct ce_attr host_ce_config_wlan[] = { .src_nentries = 32, .src_sz_max = 2048, .dest_nentries = 0, - .send_cb = NULL, + .send_cb = ath10k_snoc_htc_tx_cb, }, /* CE4: host->target HTT */ @@ -90,7 +93,7 @@ static struct ce_attr host_ce_config_wlan[] = { .src_nentries = 256, .src_sz_max = 256, .dest_nentries = 0, - .send_cb = NULL, + .send_cb = ath10k_snoc_htt_tx_cb, }, /* CE5: target->host HTT (ipa_uc->target ) */ @@ -359,6 +362,117 @@ static void ath10k_snoc_rx_post(struct ath10k *ar) ath10k_snoc_rx_post_pipe(&ar_snoc->pipe_info[i]); } +static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state) +{ + struct ath10k *ar = ce_state->ar; + struct sk_buff_head list; + struct sk_buff *skb; + + __skb_queue_head_init(&list); + while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) { + if (!skb) + continue; + + __skb_queue_tail(&list, skb); + } + + while ((skb = __skb_dequeue(&list))) + ath10k_htc_tx_completion_handler(ar, skb); +} + +static void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state) +{ + struct ath10k *ar = ce_state->ar; + struct sk_buff *skb; + + while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) { + if (!skb) + continue; + + dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr, + skb->len, DMA_TO_DEVICE); + ath10k_htt_hif_tx_complete(ar, skb); + } +} + +static int ath10k_snoc_hif_tx_sg(struct ath10k *ar, u8 pipe_id, + struct ath10k_hif_sg_item *items, int n_items) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct ath10k_snoc_pipe *snoc_pipe; + struct ath10k_ce_pipe *ce_pipe; + int err, i = 0; + + snoc_pipe = &ar_snoc->pipe_info[pipe_id]; + ce_pipe = snoc_pipe->ce_hdl; + spin_lock_bh(&ce->ce_lock); + + for (i = 0; i < n_items - 1; i++) { + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "snoc tx item %d paddr %pad len %d n_items %d\n", + i, &items[i].paddr, items[i].len, n_items); + + err = ath10k_ce_send_nolock(ce_pipe, + items[i].transfer_context, + items[i].paddr, + items[i].len, + items[i].transfer_id, + CE_SEND_FLAG_GATHER); + if (err) + goto err; + } + + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "snoc tx item %d paddr %pad len %d n_items %d\n", + i, &items[i].paddr, items[i].len, n_items); + + err = ath10k_ce_send_nolock(ce_pipe, + items[i].transfer_context, + items[i].paddr, + items[i].len, + items[i].transfer_id, + 0); + if (err) + goto err; + + spin_unlock_bh(&ce->ce_lock); + + return 0; + +err: + for (; i > 0; i--) + __ath10k_ce_send_revert(ce_pipe); + + spin_unlock_bh(&ce->ce_lock); + return err; +} + +static u16 ath10k_snoc_hif_get_free_queue_number(struct ath10k *ar, u8 pipe) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "hif get free queue number\n"); + + return ath10k_ce_num_free_src_entries(ar_snoc->pipe_info[pipe].ce_hdl); +} + +static void ath10k_snoc_hif_send_complete_check(struct ath10k *ar, u8 pipe, + int force) +{ + int resources; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif send complete check\n"); + + if (!force) { + resources = ath10k_snoc_hif_get_free_queue_number(ar, pipe); + + if (resources > (host_ce_config_wlan[pipe].src_nentries >> 1)) + return; + } + ath10k_ce_per_engine_service(ar, pipe); +} + static int ath10k_snoc_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id, u8 *ul_pipe, u8 *dl_pipe) @@ -587,6 +701,9 @@ static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .get_default_pipe = ath10k_snoc_hif_get_default_pipe, .power_up = ath10k_snoc_hif_power_up, .power_down = ath10k_snoc_hif_power_down, + .tx_sg = ath10k_snoc_hif_tx_sg, + .send_complete_check = ath10k_snoc_hif_send_complete_check, + .get_free_queue_number = ath10k_snoc_hif_get_free_queue_number, }; static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { -- cgit v1.2.3 From d915105231ca0581a9f87e59ed00bc17a54e254f Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:25 +0300 Subject: ath10k: add hif rx methods for wcn3990 Add hif rx methods in rx path for wcn3990 target. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/snoc.c | 171 +++++++++++++++++++++++++++++---- 1 file changed, 153 insertions(+), 18 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 899f0a327050..6d9cccee9bbe 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -26,6 +26,7 @@ #include #define WCN3990_CE_ATTR_FLAGS 0 #define ATH10K_SNOC_RX_POST_RETRY_MS 50 +#define CE_POLL_PIPE 4 static char *const ce_name[] = { "WLAN_CE_0", @@ -44,6 +45,9 @@ static char *const ce_name[] = { static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state); static void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state); +static void ath10k_snoc_htc_rx_cb(struct ath10k_ce_pipe *ce_state); +static void ath10k_snoc_htt_rx_cb(struct ath10k_ce_pipe *ce_state); +static void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state); static const struct ath10k_snoc_drv_priv drv_priv = { .hw_rev = ATH10K_HW_WCN3990, @@ -53,7 +57,7 @@ static const struct ath10k_snoc_drv_priv drv_priv = { static struct ce_attr host_ce_config_wlan[] = { /* CE0: host->target HTC control streams */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 16, .src_sz_max = 2048, .dest_nentries = 0, @@ -62,25 +66,25 @@ static struct ce_attr host_ce_config_wlan[] = { /* CE1: target->host HTT + HTC control */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 0, .src_sz_max = 2048, .dest_nentries = 512, - .recv_cb = NULL, + .recv_cb = ath10k_snoc_htt_htc_rx_cb, }, /* CE2: target->host WMI */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 0, .src_sz_max = 2048, .dest_nentries = 64, - .recv_cb = NULL, + .recv_cb = ath10k_snoc_htc_rx_cb, }, /* CE3: host->target WMI */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 32, .src_sz_max = 2048, .dest_nentries = 0, @@ -89,7 +93,7 @@ static struct ce_attr host_ce_config_wlan[] = { /* CE4: host->target HTT */ { - .flags = WCN3990_CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, + .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, .src_nentries = 256, .src_sz_max = 256, .dest_nentries = 0, @@ -98,16 +102,16 @@ static struct ce_attr host_ce_config_wlan[] = { /* CE5: target->host HTT (ipa_uc->target ) */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 0, .src_sz_max = 512, .dest_nentries = 512, - .recv_cb = NULL, + .recv_cb = ath10k_snoc_htt_rx_cb, }, /* CE6: target autonomous hif_memcpy */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 0, .src_sz_max = 0, .dest_nentries = 0, @@ -115,7 +119,7 @@ static struct ce_attr host_ce_config_wlan[] = { /* CE7: ce_diag, the Diagnostic Window */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 2, .src_sz_max = 2048, .dest_nentries = 2, @@ -123,7 +127,7 @@ static struct ce_attr host_ce_config_wlan[] = { /* CE8: Target to uMC */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 0, .src_sz_max = 2048, .dest_nentries = 128, @@ -131,29 +135,29 @@ static struct ce_attr host_ce_config_wlan[] = { /* CE9 target->host HTT */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 0, .src_sz_max = 2048, .dest_nentries = 512, - .recv_cb = NULL, + .recv_cb = ath10k_snoc_htt_htc_rx_cb, }, /* CE10: target->host HTT */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 0, .src_sz_max = 2048, .dest_nentries = 512, - .recv_cb = NULL, + .recv_cb = ath10k_snoc_htt_htc_rx_cb, }, /* CE11: target -> host PKTLOG */ { - .flags = WCN3990_CE_ATTR_FLAGS, + .flags = CE_ATTR_FLAGS, .src_nentries = 0, .src_sz_max = 2048, .dest_nentries = 512, - .recv_cb = NULL, + .recv_cb = ath10k_snoc_htt_htc_rx_cb, }, }; @@ -362,6 +366,82 @@ static void ath10k_snoc_rx_post(struct ath10k *ar) ath10k_snoc_rx_post_pipe(&ar_snoc->pipe_info[i]); } +static void ath10k_snoc_process_rx_cb(struct ath10k_ce_pipe *ce_state, + void (*callback)(struct ath10k *ar, + struct sk_buff *skb)) +{ + struct ath10k *ar = ce_state->ar; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_snoc_pipe *pipe_info = &ar_snoc->pipe_info[ce_state->id]; + struct sk_buff *skb; + struct sk_buff_head list; + void *transfer_context; + unsigned int nbytes, max_nbytes; + + __skb_queue_head_init(&list); + while (ath10k_ce_completed_recv_next(ce_state, &transfer_context, + &nbytes) == 0) { + skb = transfer_context; + max_nbytes = skb->len + skb_tailroom(skb); + dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr, + max_nbytes, DMA_FROM_DEVICE); + + if (unlikely(max_nbytes < nbytes)) { + ath10k_warn(ar, "rxed more than expected (nbytes %d, max %d)", + nbytes, max_nbytes); + dev_kfree_skb_any(skb); + continue; + } + + skb_put(skb, nbytes); + __skb_queue_tail(&list, skb); + } + + while ((skb = __skb_dequeue(&list))) { + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc rx ce pipe %d len %d\n", + ce_state->id, skb->len); + + callback(ar, skb); + } + + ath10k_snoc_rx_post_pipe(pipe_info); +} + +static void ath10k_snoc_htc_rx_cb(struct ath10k_ce_pipe *ce_state) +{ + ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler); +} + +static void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state) +{ + /* CE4 polling needs to be done whenever CE pipe which transports + * HTT Rx (target->host) is processed. + */ + ath10k_ce_per_engine_service(ce_state->ar, CE_POLL_PIPE); + + ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler); +} + +static void ath10k_snoc_htt_rx_deliver(struct ath10k *ar, struct sk_buff *skb) +{ + skb_pull(skb, sizeof(struct ath10k_htc_hdr)); + ath10k_htt_t2h_msg_handler(ar, skb); +} + +static void ath10k_snoc_htt_rx_cb(struct ath10k_ce_pipe *ce_state) +{ + ath10k_ce_per_engine_service(ce_state->ar, CE_POLL_PIPE); + ath10k_snoc_process_rx_cb(ce_state, ath10k_snoc_htt_rx_deliver); +} + +static void ath10k_snoc_rx_replenish_retry(struct timer_list *t) +{ + struct ath10k_pci *ar_snoc = from_timer(ar_snoc, t, rx_post_retry); + struct ath10k *ar = ar_snoc->ar; + + ath10k_snoc_rx_post(ar); +} + static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state) { struct ath10k *ar = ce_state->ar; @@ -620,6 +700,8 @@ static void ath10k_snoc_hif_stop(struct ath10k *ar) { ath10k_snoc_irq_disable(ar); ath10k_snoc_buffer_cleanup(ar); + napi_synchronize(&ar->napi); + napi_disable(&ar->napi); ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n"); } @@ -684,6 +766,7 @@ static int ath10k_snoc_hif_power_up(struct ath10k *ar) goto err_wlan_enable; } + napi_enable(&ar->napi); return 0; err_wlan_enable: @@ -711,11 +794,60 @@ static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { .write32 = ath10k_snoc_write32, }; +int ath10k_snoc_get_ce_id_from_irq(struct ath10k *ar, int irq) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + int i; + + for (i = 0; i < CE_COUNT_MAX; i++) { + if (ar_snoc->ce_irqs[i].irq_line == irq) + return i; + } + ath10k_err(ar, "No matching CE id for irq %d\n", irq); + + return -EINVAL; +} + static irqreturn_t ath10k_snoc_per_engine_handler(int irq, void *arg) { + struct ath10k *ar = arg; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + int ce_id = ath10k_snoc_get_ce_id_from_irq(ar, irq); + + if (ce_id < 0 || ce_id >= ARRAY_SIZE(ar_snoc->pipe_info)) { + ath10k_warn(ar, "unexpected/invalid irq %d ce_id %d\n", irq, + ce_id); + return IRQ_HANDLED; + } + + ath10k_snoc_irq_disable(ar); + napi_schedule(&ar->napi); + return IRQ_HANDLED; } +static int ath10k_snoc_napi_poll(struct napi_struct *ctx, int budget) +{ + struct ath10k *ar = container_of(ctx, struct ath10k, napi); + int done = 0; + + ath10k_ce_per_engine_service_any(ar); + done = ath10k_htt_txrx_compl_task(ar, budget); + + if (done < budget) { + napi_complete(ctx); + ath10k_snoc_irq_enable(ar); + } + + return done; +} + +void ath10k_snoc_init_napi(struct ath10k *ar) +{ + netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_snoc_napi_poll, + ATH10K_NAPI_BUDGET); +} + static int ath10k_snoc_request_irq(struct ath10k *ar) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); @@ -796,6 +928,7 @@ static int ath10k_snoc_setup_resource(struct ath10k *ar) struct ath10k_snoc_pipe *pipe; int i, ret; + timer_setup(&ar_snoc->rx_post_retry, ath10k_snoc_rx_replenish_retry, 0); spin_lock_init(&ce->ce_lock); for (i = 0; i < CE_COUNT; i++) { pipe = &ar_snoc->pipe_info[i]; @@ -812,6 +945,7 @@ static int ath10k_snoc_setup_resource(struct ath10k *ar) pipe->buf_sz = host_ce_config_wlan[i].src_sz_max; } + ath10k_snoc_init_napi(ar); return 0; } @@ -820,6 +954,7 @@ static void ath10k_snoc_release_resource(struct ath10k *ar) { int i; + netif_napi_del(&ar->napi); for (i = 0; i < CE_COUNT; i++) ath10k_ce_free_pipe(ar, i); } -- cgit v1.2.3 From 546d407c905bc893886edae52f2323db8eded9b9 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:27 +0300 Subject: ath10k: modify hif tx paddr to dma_addr_t type Change type of hif sg tx paddr to dma_addr_t for supporting target having addressing mode greater than 32 bit. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/hif.h | 2 +- drivers/net/wireless/ath/ath10k/pci.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index 6da4e3369c5a..7abb13c1f10b 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -26,7 +26,7 @@ struct ath10k_hif_sg_item { u16 transfer_id; void *transfer_context; /* NULL = tx completion callback not called */ void *vaddr; /* for debugging mostly */ - u32 paddr; + dma_addr_t paddr; u16 len; }; diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index fd1566cd7d2b..af2cf55c4c1e 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1383,8 +1383,8 @@ int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, for (i = 0; i < n_items - 1; i++) { ath10k_dbg(ar, ATH10K_DBG_PCI, - "pci tx item %d paddr 0x%08x len %d n_items %d\n", - i, items[i].paddr, items[i].len, n_items); + "pci tx item %d paddr %pad len %d n_items %d\n", + i, &items[i].paddr, items[i].len, n_items); ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ", items[i].vaddr, items[i].len); @@ -1401,8 +1401,8 @@ int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, /* `i` is equal to `n_items -1` after for() */ ath10k_dbg(ar, ATH10K_DBG_PCI, - "pci tx item %d paddr 0x%08x len %d n_items %d\n", - i, items[i].paddr, items[i].len, n_items); + "pci tx item %d paddr %pad len %d n_items %d\n", + i, &items[i].paddr, items[i].len, n_items); ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ", items[i].vaddr, items[i].len); -- cgit v1.2.3 From 140d1214ef555bcb14c7720e91d8a9594e4ab506 Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Tue, 10 Apr 2018 18:01:29 +0300 Subject: ath10k: add support to get target info from hif ops wcn3990 does not use bmi. Add support to get target info from hif ops. Signed-off-by: Rakesh Pillai Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 8 ++++++++ drivers/net/wireless/ath/ath10k/hif.h | 13 +++++++++++++ drivers/net/wireless/ath/ath10k/snoc.c | 10 ++++++++++ 3 files changed, 31 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 8a3020dbd4cf..6a9ad4ab8e4c 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2472,6 +2472,14 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ar->hw->wiphy->hw_version = target_info.version; break; case ATH10K_BUS_SNOC: + memset(&target_info, 0, sizeof(target_info)); + ret = ath10k_hif_get_target_info(ar, &target_info); + if (ret) { + ath10k_err(ar, "could not get target info (%d)\n", ret); + goto err_power_down; + } + ar->target_version = target_info.version; + ar->hw->wiphy->hw_version = target_info.version; break; default: ath10k_err(ar, "incorrect hif bus type: %d\n", ar->hif.bus); diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index 7abb13c1f10b..1a59ea0068c2 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -20,6 +20,7 @@ #include #include "core.h" +#include "bmi.h" #include "debug.h" struct ath10k_hif_sg_item { @@ -93,6 +94,9 @@ struct ath10k_hif_ops { /* fetch calibration data from target eeprom */ int (*fetch_cal_eeprom)(struct ath10k *ar, void **data, size_t *data_len); + + int (*get_target_info)(struct ath10k *ar, + struct bmi_target_info *target_info); }; static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id, @@ -218,4 +222,13 @@ static inline int ath10k_hif_fetch_cal_eeprom(struct ath10k *ar, return ar->hif.ops->fetch_cal_eeprom(ar, data, data_len); } +static inline int ath10k_hif_get_target_info(struct ath10k *ar, + struct bmi_target_info *tgt_info) +{ + if (!ar->hif.ops->get_target_info) + return -EOPNOTSUPP; + + return ar->hif.ops->get_target_info(ar, tgt_info); +} + #endif /* _HIF_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 6d9cccee9bbe..1ef0d3b51b8f 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -528,6 +528,15 @@ err: return err; } +static int ath10k_snoc_hif_get_target_info(struct ath10k *ar, + struct bmi_target_info *target_info) +{ + target_info->version = ATH10K_HW_WCN3990; + target_info->type = ATH10K_HW_WCN3990; + + return 0; +} + static u16 ath10k_snoc_hif_get_free_queue_number(struct ath10k *ar, u8 pipe) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); @@ -787,6 +796,7 @@ static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .tx_sg = ath10k_snoc_hif_tx_sg, .send_complete_check = ath10k_snoc_hif_send_complete_check, .get_free_queue_number = ath10k_snoc_hif_get_free_queue_number, + .get_target_info = ath10k_snoc_hif_get_target_info, }; static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { -- cgit v1.2.3 From ea66b12e63ac62de19685c6900903d22e2680be6 Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Tue, 10 Apr 2018 18:01:32 +0300 Subject: ath10k: check all CE for data if irq summary is not retained WCN3990 has interrupts per CE and the interrupt summary is not retained after the interrupt handler has finished execution. We need to check if we received any ce in rx and tx completion path. Generate a interrupt summary with all CE interrupts if the target does not retain interrupt summary after the execution of interrupt handler. Signed-off-by: Rakesh Pillai Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.h | 10 +++++++--- drivers/net/wireless/ath/ath10k/core.c | 13 +++++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 3 +++ 3 files changed, 23 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 2c3c8f5e90ea..d8f9da334529 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -355,14 +355,18 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) (((x) & CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK) >> \ CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB) #define CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS 0x0000 +#define CE_INTERRUPT_SUMMARY (GENMASK(CE_COUNT_MAX - 1, 0)) static inline u32 ath10k_ce_interrupt_summary(struct ath10k *ar) { struct ath10k_ce *ce = ath10k_ce_priv(ar); - return CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET( - ce->bus_ops->read32((ar), CE_WRAPPER_BASE_ADDRESS + - CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS)); + if (!ar->hw_params.per_ce_irq) + return CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET( + ce->bus_ops->read32((ar), CE_WRAPPER_BASE_ADDRESS + + CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS)); + else + return CE_INTERRUPT_SUMMARY; } #endif /* _CE_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 6a9ad4ab8e4c..a21530dacc35 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -119,6 +119,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA9887_HW_1_0_VERSION, @@ -148,6 +149,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -176,6 +178,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -204,6 +207,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA6174_HW_3_0_VERSION, @@ -232,6 +236,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA6174_HW_3_2_VERSION, @@ -263,6 +268,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA99X0_HW_2_0_DEV_VERSION, @@ -297,6 +303,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA9984_HW_1_0_DEV_VERSION, @@ -336,6 +343,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA9888_HW_2_0_DEV_VERSION, @@ -374,6 +382,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA9377_HW_1_0_DEV_VERSION, @@ -402,6 +411,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA9377_HW_1_1_DEV_VERSION, @@ -432,6 +442,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = QCA4019_HW_1_0_DEV_VERSION, @@ -467,6 +478,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .per_ce_irq = false, }, { .id = WCN3990_HW_1_0_DEV_VERSION, @@ -487,6 +499,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = TARGET_HL_10_TLV_NUM_WDS_ENTRIES, .target_64bit = true, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL_DUAL_MAC, + .per_ce_irq = true, }, }; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 413b1b4321f7..3041eba61e54 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -568,6 +568,9 @@ struct ath10k_hw_params { /* Target rx ring fill level */ u32 rx_ring_fill_level; + + /* target supporting per ce IRQ */ + bool per_ce_irq; }; struct htt_rx_desc; -- cgit v1.2.3 From a6a793f98786fe146f8926b02b320f0d9b48a61c Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 10 Apr 2018 18:01:34 +0300 Subject: ath10k: vote for hardware resources for WCN3990 Add clock and regulator votes for WCN3990 WLAN chipset. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/snoc.c | 313 ++++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/snoc.h | 19 ++ 2 files changed, 331 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 1ef0d3b51b8f..2e490ff124f1 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #define WCN3990_CE_ATTR_FLAGS 0 #define ATH10K_SNOC_RX_POST_RETRY_MS 50 #define CE_POLL_PIPE 4 @@ -43,6 +45,17 @@ static char *const ce_name[] = { "WLAN_CE_11", }; +static struct ath10k_wcn3990_vreg_info vreg_cfg[] = { + {NULL, "vdd-0.8-cx-mx", 800000, 800000, 0, 0, false}, + {NULL, "vdd-1.8-xo", 1800000, 1800000, 0, 0, false}, + {NULL, "vdd-1.3-rfa", 1304000, 1304000, 0, 0, false}, + {NULL, "vdd-3.3-ch0", 3312000, 3312000, 0, 0, false}, +}; + +static struct ath10k_wcn3990_clk_info clk_cfg[] = { + {NULL, "cxo_ref_clk_pin", 0, false}, +}; + static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state); static void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state); static void ath10k_snoc_htc_rx_cb(struct ath10k_ce_pipe *ce_state); @@ -969,6 +982,277 @@ static void ath10k_snoc_release_resource(struct ath10k *ar) ath10k_ce_free_pipe(ar, i); } +static int ath10k_get_vreg_info(struct ath10k *ar, struct device *dev, + struct ath10k_wcn3990_vreg_info *vreg_info) +{ + struct regulator *reg; + int ret = 0; + + reg = devm_regulator_get_optional(dev, vreg_info->name); + + if (IS_ERR(reg)) { + ret = PTR_ERR(reg); + + if (ret == -EPROBE_DEFER) { + ath10k_err(ar, "EPROBE_DEFER for regulator: %s\n", + vreg_info->name); + return ret; + } + if (vreg_info->required) { + ath10k_err(ar, "Regulator %s doesn't exist: %d\n", + vreg_info->name, ret); + return ret; + } + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "Optional regulator %s doesn't exist: %d\n", + vreg_info->name, ret); + goto done; + } + + vreg_info->reg = reg; + +done: + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "snog vreg %s min_v %u max_v %u load_ua %u settle_delay %lu\n", + vreg_info->name, vreg_info->min_v, vreg_info->max_v, + vreg_info->load_ua, vreg_info->settle_delay); + + return 0; +} + +static int ath10k_get_clk_info(struct ath10k *ar, struct device *dev, + struct ath10k_wcn3990_clk_info *clk_info) +{ + struct clk *handle; + int ret = 0; + + handle = devm_clk_get(dev, clk_info->name); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + if (clk_info->required) { + ath10k_err(ar, "snoc clock %s isn't available: %d\n", + clk_info->name, ret); + return ret; + } + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc ignoring clock %s: %d\n", + clk_info->name, + ret); + return 0; + } + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc clock %s freq %u\n", + clk_info->name, clk_info->freq); + + clk_info->handle = handle; + + return ret; +} + +static int ath10k_wcn3990_vreg_on(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_wcn3990_vreg_info *vreg_info; + int ret = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(vreg_cfg); i++) { + vreg_info = &ar_snoc->vreg[i]; + + if (!vreg_info->reg) + continue; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc regulator %s being enabled\n", + vreg_info->name); + + ret = regulator_set_voltage(vreg_info->reg, vreg_info->min_v, + vreg_info->max_v); + if (ret) { + ath10k_err(ar, + "failed to set regulator %s voltage-min: %d voltage-max: %d\n", + vreg_info->name, vreg_info->min_v, vreg_info->max_v); + goto err_reg_config; + } + + if (vreg_info->load_ua) { + ret = regulator_set_load(vreg_info->reg, + vreg_info->load_ua); + if (ret < 0) { + ath10k_err(ar, + "failed to set regulator %s load: %d\n", + vreg_info->name, + vreg_info->load_ua); + goto err_reg_config; + } + } + + ret = regulator_enable(vreg_info->reg); + if (ret) { + ath10k_err(ar, "failed to enable regulator %s\n", + vreg_info->name); + goto err_reg_config; + } + + if (vreg_info->settle_delay) + udelay(vreg_info->settle_delay); + } + + return 0; + +err_reg_config: + for (; i >= 0; i--) { + vreg_info = &ar_snoc->vreg[i]; + + if (!vreg_info->reg) + continue; + + regulator_disable(vreg_info->reg); + regulator_set_load(vreg_info->reg, 0); + regulator_set_voltage(vreg_info->reg, 0, vreg_info->max_v); + } + + return ret; +} + +static int ath10k_wcn3990_vreg_off(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_wcn3990_vreg_info *vreg_info; + int ret = 0; + int i; + + for (i = ARRAY_SIZE(vreg_cfg) - 1; i >= 0; i--) { + vreg_info = &ar_snoc->vreg[i]; + + if (!vreg_info->reg) + continue; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc regulator %s being disabled\n", + vreg_info->name); + + ret = regulator_disable(vreg_info->reg); + if (ret) + ath10k_err(ar, "failed to disable regulator %s\n", + vreg_info->name); + + ret = regulator_set_load(vreg_info->reg, 0); + if (ret < 0) + ath10k_err(ar, "failed to set load %s\n", + vreg_info->name); + + ret = regulator_set_voltage(vreg_info->reg, 0, + vreg_info->max_v); + if (ret) + ath10k_err(ar, "failed to set voltage %s\n", + vreg_info->name); + } + + return ret; +} + +static int ath10k_wcn3990_clk_init(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_wcn3990_clk_info *clk_info; + int ret = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(clk_cfg); i++) { + clk_info = &ar_snoc->clk[i]; + + if (!clk_info->handle) + continue; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc clock %s being enabled\n", + clk_info->name); + + if (clk_info->freq) { + ret = clk_set_rate(clk_info->handle, clk_info->freq); + + if (ret) { + ath10k_err(ar, "failed to set clock %s freq %u\n", + clk_info->name, clk_info->freq); + goto err_clock_config; + } + } + + ret = clk_prepare_enable(clk_info->handle); + if (ret) { + ath10k_err(ar, "failed to enable clock %s\n", + clk_info->name); + goto err_clock_config; + } + } + + return 0; + +err_clock_config: + for (; i >= 0; i--) { + clk_info = &ar_snoc->clk[i]; + + if (!clk_info->handle) + continue; + + clk_disable_unprepare(clk_info->handle); + } + + return ret; +} + +static int ath10k_wcn3990_clk_deinit(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct ath10k_wcn3990_clk_info *clk_info; + int i; + + for (i = 0; i < ARRAY_SIZE(clk_cfg); i++) { + clk_info = &ar_snoc->clk[i]; + + if (!clk_info->handle) + continue; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc clock %s being disabled\n", + clk_info->name); + + clk_disable_unprepare(clk_info->handle); + } + + return 0; +} + +static int ath10k_hw_power_on(struct ath10k *ar) +{ + int ret; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power on\n"); + + ret = ath10k_wcn3990_vreg_on(ar); + if (ret) + return ret; + + ret = ath10k_wcn3990_clk_init(ar); + if (ret) + goto vreg_off; + + return ret; + +vreg_off: + ath10k_wcn3990_vreg_off(ar); + return ret; +} + +static int ath10k_hw_power_off(struct ath10k *ar) +{ + int ret; + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power off\n"); + + ath10k_wcn3990_clk_deinit(ar); + + ret = ath10k_wcn3990_vreg_off(ar); + + return ret; +} + static const struct of_device_id ath10k_snoc_dt_match[] = { { .compatible = "qcom,wcn3990-wifi", .data = &drv_priv, @@ -985,6 +1269,7 @@ static int ath10k_snoc_probe(struct platform_device *pdev) struct device *dev; struct ath10k *ar; int ret; + u32 i; of_id = of_match_device(ath10k_snoc_dt_match, &pdev->dev); if (!of_id) { @@ -1031,16 +1316,41 @@ static int ath10k_snoc_probe(struct platform_device *pdev) ath10k_warn(ar, "failed to request irqs: %d\n", ret); goto err_release_resource; } + + ar_snoc->vreg = vreg_cfg; + for (i = 0; i < ARRAY_SIZE(vreg_cfg); i++) { + ret = ath10k_get_vreg_info(ar, dev, &ar_snoc->vreg[i]); + if (ret) + goto err_free_irq; + } + + ar_snoc->clk = clk_cfg; + for (i = 0; i < ARRAY_SIZE(clk_cfg); i++) { + ret = ath10k_get_clk_info(ar, dev, &ar_snoc->clk[i]); + if (ret) + goto err_free_irq; + } + + ret = ath10k_hw_power_on(ar); + if (ret) { + ath10k_err(ar, "failed to power on device: %d\n", ret); + goto err_free_irq; + } + ret = ath10k_core_register(ar, drv_data->hw_rev); if (ret) { ath10k_err(ar, "failed to register driver core: %d\n", ret); - goto err_free_irq; + goto err_hw_power_off; } + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n"); ath10k_warn(ar, "Warning: SNOC support is still work-in-progress, it will not work properly!"); return 0; +err_hw_power_off: + ath10k_hw_power_off(ar); + err_free_irq: ath10k_snoc_free_irq(ar); @@ -1059,6 +1369,7 @@ static int ath10k_snoc_remove(struct platform_device *pdev) ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc remove\n"); ath10k_core_unregister(ar); + ath10k_hw_power_off(ar); ath10k_snoc_free_irq(ar); ath10k_snoc_release_resource(ar); ath10k_core_destroy(ar); diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index cf65b01e0085..05dc98f46ccd 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -52,6 +52,23 @@ struct ath10k_snoc_ce_irq { u32 irq_line; }; +struct ath10k_wcn3990_vreg_info { + struct regulator *reg; + const char *name; + u32 min_v; + u32 max_v; + u32 load_ua; + unsigned long settle_delay; + bool required; +}; + +struct ath10k_wcn3990_clk_info { + struct clk *handle; + const char *name; + u32 freq; + bool required; +}; + struct ath10k_snoc { struct platform_device *dev; struct ath10k *ar; @@ -63,6 +80,8 @@ struct ath10k_snoc { struct ath10k_snoc_ce_irq ce_irqs[CE_COUNT_MAX]; struct ath10k_ce ce; struct timer_list rx_post_retry; + struct ath10k_wcn3990_vreg_info *vreg; + struct ath10k_wcn3990_clk_info *clk; }; static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar) -- cgit v1.2.3 From 5072d87426bb6ed685d3ad9b694f5571859eca06 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 29 Mar 2018 17:53:04 +0100 Subject: ath6kl: fix spelling mistake: "chache" -> "cache" Trivial fix to spelling mistake in message text Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index 0f965e9f38a4..4e94b22eaada 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -645,7 +645,7 @@ static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", "CRC Err", tgt_stats->rx_crc_err); len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", - "Key chache miss", tgt_stats->rx_key_cache_miss); + "Key cache miss", tgt_stats->rx_key_cache_miss); len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", "Decrypt Err", tgt_stats->rx_decrypt_err); len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", -- cgit v1.2.3 From 1e8f77502341035f079039c9aa9a647ebc9d881a Mon Sep 17 00:00:00 2001 From: Manikanta Pubbisetty Date: Thu, 12 Apr 2018 17:46:50 +0530 Subject: ath10k: correct target assert problem due to CE5 stuck Correct a minor bug in the commit 0628467f97b5 ("ath10k: fix copy engine 5 destination ring stuck") which introduced a change to fix firmware assert that happens when ring indices of copy engine 5 are stuck for a specific duration, problem with this fix is that it did not use ring arithmatic. As a result,firmware asserts did not go away entirely athough the frequency of occurrence has reduced. Using ring arithmatic to fix the issue. Tested on QCA9984(fw version-10.4-3.4-00082). Fixes: 0628467f97b5 ("ath10k: fix copy engine 5 destination ring stuck) Signed-off-by: Manikanta Pubbisetty Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index e7e7b342e5b8..3a15923bdd26 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -620,7 +620,7 @@ void ath10k_ce_rx_update_write_idx(struct ath10k_ce_pipe *pipe, u32 nentries) /* Prevent CE ring stuck issue that will occur when ring is full. * Make sure that write index is 1 less than read index. */ - if ((cur_write_idx + nentries) == dest_ring->sw_index) + if (((cur_write_idx + nentries) & nentries_mask) == dest_ring->sw_index) nentries -= 1; write_index = CE_RING_IDX_ADD(nentries_mask, write_index, nentries); -- cgit v1.2.3 From b022ca257ca6eabf38fba0c700956bdd0babf3e1 Mon Sep 17 00:00:00 2001 From: Maharaja Kennadyrajan Date: Fri, 13 Apr 2018 13:18:12 +0530 Subject: ath10k: fix a typo in ath10k_wmi_set_wmm_param() Fix a typo in the function ath10k_wmi_set_wmm_param(). Signed-off-by: Maharaja Kennadyrajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index eb1c8a1a1c88..e12dd28fcf5d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -7648,7 +7648,7 @@ ath10k_wmi_10_2_4_op_gen_pdev_get_tpc_config(struct ath10k *ar, u32 param) cmd->param = __cpu_to_le32(param); ath10k_dbg(ar, ATH10K_DBG_WMI, - "wmi pdev get tcp config param:%d\n", param); + "wmi pdev get tpc config param %d\n", param); return skb; } -- cgit v1.2.3 From c8489668065a283d3027e86e877b103a87f99d22 Mon Sep 17 00:00:00 2001 From: Thomas Hebb Date: Fri, 13 Apr 2018 17:40:26 +0300 Subject: ath10k: search all IEs for variant before falling back commit f2593cb1b291 ("ath10k: Search SMBIOS for OEM board file extension") added a feature to ath10k that allows Board Data File (BDF) conflicts between multiple devices that use the same device IDs but have different calibration requirements to be resolved by allowing a "variant" string to be stored in SMBIOS [and later device tree, added by commit d06f26c5c8a4 ("ath10k: search DT for qcom,ath10k-calibration- variant")] that gets appended to the ID stored in board-2.bin. This original patch had a regression, however. Namely that devices with a variant present in SMBIOS that didn't need custom BDFs could no longer find the default BDF, which has no variant appended. The patch was reverted and re-applied with a fix for this issue in commit 1657b8f84ed9 ("search SMBIOS for OEM board file extension"). But the fix to fall back to a default BDF introduced another issue: the driver currently parses IEs in board-2.bin one by one, and for each one it first checks to see if it matches the ID with the variant appended. If it doesn't, it checks to see if it matches the "fallback" ID with no variant. If a matching BDF is found at any point during this search, the search is terminated and that BDF is used. The issue is that it's very possible (and is currently the case for board-2.bin files present in the ath10k-firmware repository) for the default BDF to occur in an earlier IE than the variant-specific BDF. In this case, the current code will happily choose the default BDF even though a better-matching BDF is present later in the file. This patch fixes the issue by first searching the entire file for the ID with variant, and searching for the fallback ID only if that search fails. It also includes some code cleanup in the area, as ath10k_core_fetch_board_data_api_n() no longer does its own string mangling to remove the variant from an ID, instead leaving that job to a new flag passed to ath10k_core_create_board_name(). I've tested this patch on a QCA4019 and verified that the driver behaves correctly for 1) both fallback and variant BDFs present, 2) only fallback BDF present, and 3) no matching BDFs present. Fixes: 1657b8f84ed9 ("ath10k: search SMBIOS for OEM board file extension") Signed-off-by: Thomas Hebb Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 134 ++++++++++++++++++--------------- 1 file changed, 72 insertions(+), 62 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index a21530dacc35..64674d8ce457 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1266,14 +1266,61 @@ out: return ret; } +static int ath10k_core_search_bd(struct ath10k *ar, + const char *boardname, + const u8 *data, + size_t len) +{ + size_t ie_len; + struct ath10k_fw_ie *hdr; + int ret = -ENOENT, ie_id; + + while (len > sizeof(struct ath10k_fw_ie)) { + hdr = (struct ath10k_fw_ie *)data; + ie_id = le32_to_cpu(hdr->id); + ie_len = le32_to_cpu(hdr->len); + + len -= sizeof(*hdr); + data = hdr->data; + + if (len < ALIGN(ie_len, 4)) { + ath10k_err(ar, "invalid length for board ie_id %d ie_len %zu len %zu\n", + ie_id, ie_len, len); + return -EINVAL; + } + + switch (ie_id) { + case ATH10K_BD_IE_BOARD: + ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len, + boardname); + if (ret == -ENOENT) + /* no match found, continue */ + break; + + /* either found or error, so stop searching */ + goto out; + } + + /* jump over the padding */ + ie_len = ALIGN(ie_len, 4); + + len -= ie_len; + data += ie_len; + } + +out: + /* return result of parse_bd_ie_board() or -ENOENT */ + return ret; +} + static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar, const char *boardname, + const char *fallback_boardname, const char *filename) { - size_t len, magic_len, ie_len; - struct ath10k_fw_ie *hdr; + size_t len, magic_len; const u8 *data; - int ret, ie_id; + int ret; ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, @@ -1311,69 +1358,23 @@ static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar, data += magic_len; len -= magic_len; - while (len > sizeof(struct ath10k_fw_ie)) { - hdr = (struct ath10k_fw_ie *)data; - ie_id = le32_to_cpu(hdr->id); - ie_len = le32_to_cpu(hdr->len); - - len -= sizeof(*hdr); - data = hdr->data; - - if (len < ALIGN(ie_len, 4)) { - ath10k_err(ar, "invalid length for board ie_id %d ie_len %zu len %zu\n", - ie_id, ie_len, len); - ret = -EINVAL; - goto err; - } + /* attempt to find boardname in the IE list */ + ret = ath10k_core_search_bd(ar, boardname, data, len); - switch (ie_id) { - case ATH10K_BD_IE_BOARD: - ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len, - boardname); - if (ret == -ENOENT && ar->id.bdf_ext[0] != '\0') { - /* try default bdf if variant was not found */ - char *s, *v = ",variant="; - char boardname2[100]; - - strlcpy(boardname2, boardname, - sizeof(boardname2)); - - s = strstr(boardname2, v); - if (s) - *s = '\0'; /* strip ",variant=%s" */ + /* if we didn't find it and have a fallback name, try that */ + if (ret == -ENOENT && fallback_boardname) + ret = ath10k_core_search_bd(ar, fallback_boardname, data, len); - ret = ath10k_core_parse_bd_ie_board(ar, data, - ie_len, - boardname2); - } - - if (ret == -ENOENT) - /* no match found, continue */ - break; - else if (ret) - /* there was an error, bail out */ - goto err; - - /* board data found */ - goto out; - } - - /* jump over the padding */ - ie_len = ALIGN(ie_len, 4); - - len -= ie_len; - data += ie_len; - } - -out: - if (!ar->normal_mode_fw.board_data || !ar->normal_mode_fw.board_len) { + if (ret == -ENOENT) { ath10k_err(ar, "failed to fetch board data for %s from %s/%s\n", boardname, ar->hw_params.fw.dir, filename); ret = -ENODATA; - goto err; } + if (ret) + goto err; + return 0; err: @@ -1382,12 +1383,12 @@ err: } static int ath10k_core_create_board_name(struct ath10k *ar, char *name, - size_t name_len) + size_t name_len, bool with_variant) { /* strlen(',variant=') + strlen(ar->id.bdf_ext) */ char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = { 0 }; - if (ar->id.bdf_ext[0] != '\0') + if (with_variant && ar->id.bdf_ext[0] != '\0') scnprintf(variant, sizeof(variant), ",variant=%s", ar->id.bdf_ext); @@ -1413,17 +1414,26 @@ out: static int ath10k_core_fetch_board_file(struct ath10k *ar) { - char boardname[100]; + char boardname[100], fallback_boardname[100]; int ret; - ret = ath10k_core_create_board_name(ar, boardname, sizeof(boardname)); + ret = ath10k_core_create_board_name(ar, boardname, + sizeof(boardname), true); if (ret) { ath10k_err(ar, "failed to create board name: %d", ret); return ret; } + ret = ath10k_core_create_board_name(ar, fallback_boardname, + sizeof(boardname), false); + if (ret) { + ath10k_err(ar, "failed to create fallback board name: %d", ret); + return ret; + } + ar->bd_api = 2; ret = ath10k_core_fetch_board_data_api_n(ar, boardname, + fallback_boardname, ATH10K_BOARD_API2_FILE); if (!ret) goto success; -- cgit v1.2.3 From 5df6e1313044bf0b5326fa54db8a3904d43ec1dc Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Sun, 15 Apr 2018 14:22:27 +0200 Subject: ath10k: add inlined wrappers for htt tx ops These wrappers makes the HTT ops align better with the HIF ops (where similar wrappers are used). It also makes it easier for a target to have unsupported ops (by letting the corresponding function pointer be NULL). Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.c | 4 +-- drivers/net/wireless/ath/ath10k/htt.h | 51 ++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/htt_tx.c | 12 ++++---- drivers/net/wireless/ath/ath10k/mac.c | 2 +- 4 files changed, 60 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 625198dea18b..21a67f82f037 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -257,11 +257,11 @@ int ath10k_htt_setup(struct ath10k_htt *htt) return status; } - status = htt->tx_ops->htt_send_frag_desc_bank_cfg(htt); + status = ath10k_htt_send_frag_desc_bank_cfg(htt); if (status) return status; - status = htt->tx_ops->htt_send_rx_ring_cfg(htt); + status = ath10k_htt_send_rx_ring_cfg(htt); if (status) { ath10k_warn(ar, "failed to setup rx ring: %d\n", status); diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index e5dbb0bdd787..68f3bc98fae7 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -1856,6 +1856,57 @@ struct ath10k_htt_tx_ops { void (*htt_free_txbuff)(struct ath10k_htt *htt); }; +static inline int ath10k_htt_send_rx_ring_cfg(struct ath10k_htt *htt) +{ + if (!htt->tx_ops->htt_send_rx_ring_cfg) + return -EOPNOTSUPP; + + return htt->tx_ops->htt_send_rx_ring_cfg(htt); +} + +static inline int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt) +{ + if (!htt->tx_ops->htt_send_frag_desc_bank_cfg) + return -EOPNOTSUPP; + + return htt->tx_ops->htt_send_frag_desc_bank_cfg(htt); +} + +static inline int ath10k_htt_alloc_frag_desc(struct ath10k_htt *htt) +{ + if (!htt->tx_ops->htt_alloc_frag_desc) + return -EOPNOTSUPP; + + return htt->tx_ops->htt_alloc_frag_desc(htt); +} + +static inline void ath10k_htt_free_frag_desc(struct ath10k_htt *htt) +{ + if (htt->tx_ops->htt_free_frag_desc) + htt->tx_ops->htt_free_frag_desc(htt); +} + +static inline int ath10k_htt_tx(struct ath10k_htt *htt, + enum ath10k_hw_txrx_mode txmode, + struct sk_buff *msdu) +{ + return htt->tx_ops->htt_tx(htt, txmode, msdu); +} + +static inline int ath10k_htt_alloc_txbuff(struct ath10k_htt *htt) +{ + if (!htt->tx_ops->htt_alloc_txbuff) + return -EOPNOTSUPP; + + return htt->tx_ops->htt_alloc_txbuff(htt); +} + +static inline void ath10k_htt_free_txbuff(struct ath10k_htt *htt) +{ + if (htt->tx_ops->htt_free_txbuff) + htt->tx_ops->htt_free_txbuff(htt); +} + struct ath10k_htt_rx_ops { size_t (*htt_get_rx_ring_size)(struct ath10k_htt *htt); void (*htt_config_paddrs_ring)(struct ath10k_htt *htt, void *vaddr); diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index d334b7be1fea..a086958c39b6 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -443,13 +443,13 @@ static int ath10k_htt_tx_alloc_buf(struct ath10k_htt *htt) struct ath10k *ar = htt->ar; int ret; - ret = htt->tx_ops->htt_alloc_txbuff(htt); + ret = ath10k_htt_alloc_txbuff(htt); if (ret) { ath10k_err(ar, "failed to alloc cont tx buffer: %d\n", ret); return ret; } - ret = htt->tx_ops->htt_alloc_frag_desc(htt); + ret = ath10k_htt_alloc_frag_desc(htt); if (ret) { ath10k_err(ar, "failed to alloc cont frag desc: %d\n", ret); goto free_txbuf; @@ -473,10 +473,10 @@ free_txq: ath10k_htt_tx_free_txq(htt); free_frag_desc: - htt->tx_ops->htt_free_frag_desc(htt); + ath10k_htt_free_frag_desc(htt); free_txbuf: - htt->tx_ops->htt_free_txbuff(htt); + ath10k_htt_free_txbuff(htt); return ret; } @@ -530,9 +530,9 @@ void ath10k_htt_tx_destroy(struct ath10k_htt *htt) if (!htt->tx_mem_allocated) return; - htt->tx_ops->htt_free_txbuff(htt); + ath10k_htt_free_txbuff(htt); ath10k_htt_tx_free_txq(htt); - htt->tx_ops->htt_free_frag_desc(htt); + ath10k_htt_free_frag_desc(htt); ath10k_htt_tx_free_txdone_fifo(htt); htt->tx_mem_allocated = false; } diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index bf05a3689558..fc3320f94f45 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3598,7 +3598,7 @@ static int ath10k_mac_tx_submit(struct ath10k *ar, switch (txpath) { case ATH10K_MAC_TX_HTT: - ret = htt->tx_ops->htt_tx(htt, txmode, skb); + ret = ath10k_htt_tx(htt, txmode, skb); break; case ATH10K_MAC_TX_HTT_MGMT: ret = ath10k_htt_mgmt_tx(htt, skb); -- cgit v1.2.3 From 9a5511d5f24f331c1709f398b1cff5d538fbae1d Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Sun, 15 Apr 2018 14:22:28 +0200 Subject: ath10k: add inlined wrappers for htt rx ops Added for the same reason as the TX wrappers. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.h | 37 ++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/htt_rx.c | 14 ++++++------ 2 files changed, 44 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 68f3bc98fae7..4e5fe539eb77 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -1916,6 +1916,43 @@ struct ath10k_htt_rx_ops { void (*htt_reset_paddrs_ring)(struct ath10k_htt *htt, int idx); }; +static inline size_t ath10k_htt_get_rx_ring_size(struct ath10k_htt *htt) +{ + if (!htt->rx_ops->htt_get_rx_ring_size) + return 0; + + return htt->rx_ops->htt_get_rx_ring_size(htt); +} + +static inline void ath10k_htt_config_paddrs_ring(struct ath10k_htt *htt, + void *vaddr) +{ + if (htt->rx_ops->htt_config_paddrs_ring) + htt->rx_ops->htt_config_paddrs_ring(htt, vaddr); +} + +static inline void ath10k_htt_set_paddrs_ring(struct ath10k_htt *htt, + dma_addr_t paddr, + int idx) +{ + if (htt->rx_ops->htt_set_paddrs_ring) + htt->rx_ops->htt_set_paddrs_ring(htt, paddr, idx); +} + +static inline void *ath10k_htt_get_vaddr_ring(struct ath10k_htt *htt) +{ + if (!htt->rx_ops->htt_get_vaddr_ring) + return NULL; + + return htt->rx_ops->htt_get_vaddr_ring(htt); +} + +static inline void ath10k_htt_reset_paddrs_ring(struct ath10k_htt *htt, int idx) +{ + if (htt->rx_ops->htt_reset_paddrs_ring) + htt->rx_ops->htt_reset_paddrs_ring(htt, idx); +} + #define RX_HTT_HDR_STATUS_LEN 64 /* This structure layout is programmed via rx ring setup diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 0315bdad7f85..bd23f6940488 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -182,7 +182,7 @@ static int __ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num) rxcb = ATH10K_SKB_RXCB(skb); rxcb->paddr = paddr; htt->rx_ring.netbufs_ring[idx] = skb; - htt->rx_ops->htt_set_paddrs_ring(htt, paddr, idx); + ath10k_htt_set_paddrs_ring(htt, paddr, idx); htt->rx_ring.fill_cnt++; if (htt->rx_ring.in_ord_rx) { @@ -287,8 +287,8 @@ void ath10k_htt_rx_free(struct ath10k_htt *htt) ath10k_htt_rx_ring_free(htt); dma_free_coherent(htt->ar->dev, - htt->rx_ops->htt_get_rx_ring_size(htt), - htt->rx_ops->htt_get_vaddr_ring(htt), + ath10k_htt_get_rx_ring_size(htt), + ath10k_htt_get_vaddr_ring(htt), htt->rx_ring.base_paddr); dma_free_coherent(htt->ar->dev, @@ -315,7 +315,7 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt) idx = htt->rx_ring.sw_rd_idx.msdu_payld; msdu = htt->rx_ring.netbufs_ring[idx]; htt->rx_ring.netbufs_ring[idx] = NULL; - htt->rx_ops->htt_reset_paddrs_ring(htt, idx); + ath10k_htt_reset_paddrs_ring(htt, idx); idx++; idx &= htt->rx_ring.size_mask; @@ -587,13 +587,13 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt) if (!htt->rx_ring.netbufs_ring) goto err_netbuf; - size = htt->rx_ops->htt_get_rx_ring_size(htt); + size = ath10k_htt_get_rx_ring_size(htt); vaddr_ring = dma_alloc_coherent(htt->ar->dev, size, &paddr, GFP_KERNEL); if (!vaddr_ring) goto err_dma_ring; - htt->rx_ops->htt_config_paddrs_ring(htt, vaddr_ring); + ath10k_htt_config_paddrs_ring(htt, vaddr_ring); htt->rx_ring.base_paddr = paddr; vaddr = dma_alloc_coherent(htt->ar->dev, @@ -627,7 +627,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt) err_dma_idx: dma_free_coherent(htt->ar->dev, - htt->rx_ops->htt_get_rx_ring_size(htt), + ath10k_htt_get_rx_ring_size(htt), vaddr_ring, htt->rx_ring.base_paddr); err_dma_ring: -- cgit v1.2.3 From 6da2b2d46ff937edc3ecea0a36d92252981d033a Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Mon, 16 Apr 2018 09:56:45 +0530 Subject: ath10k: fix fw path name for WCN3990 target FW path is mapped incorrectly for the WCN3990 hw version. Fix fw path with correct hw1.0 name. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/hw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 3041eba61e54..b025a1bf2fde 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -131,7 +131,7 @@ enum qca9377_chip_id_rev { /* WCN3990 1.0 definitions */ #define WCN3990_HW_1_0_DEV_VERSION ATH10K_HW_WCN3990 -#define WCN3990_HW_1_0_FW_DIR ATH10K_FW_DIR "/WCN3990/hw3.0" +#define WCN3990_HW_1_0_FW_DIR ATH10K_FW_DIR "/WCN3990/hw1.0" #define ATH10K_FW_FILE_BASE "firmware" #define ATH10K_FW_API_MAX 6 -- cgit v1.2.3 From 9ff6fde86fd27a0c733c01114eb0d46bd3a33fb7 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 10 Apr 2018 19:35:58 +0200 Subject: wcn36xx: use READ_ONCE() to access desc->ctrl When accessing shared memory to check for the stat of submitted descriptors, make sure to use READ_ONCE(). This will guarantee the compiler treats these memory locations as volatile and doesn't apply any caching. While this doesn't fix any particular problem I ran into, it's best practice to do it this way. Note that this patch also removes the superflous extra condition check in the do-while loop in reap_tx_dxes(), as the loop will break instantly anyway in that case. Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/dxe.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index a6702ada13d3..bd2b946a65c9 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -368,7 +368,7 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch) spin_lock_irqsave(&ch->lock, flags); ctl = ch->tail_blk_ctl; do { - if (ctl->desc->ctrl & WCN36xx_DXE_CTRL_VLD) + if (READ_ONCE(ctl->desc->ctrl) & WCN36xx_DXE_CTRL_VLD) break; if (ctl->skb) { dma_unmap_single(wcn->dev, ctl->desc->src_addr_l, @@ -387,8 +387,7 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch) ctl->skb = NULL; } ctl = ctl->next; - } while (ctl != ch->head_blk_ctl && - !(ctl->desc->ctrl & WCN36xx_DXE_CTRL_VLD)); + } while (ctl != ch->head_blk_ctl); ch->tail_blk_ctl = ctl; spin_unlock_irqrestore(&ch->lock, flags); @@ -530,7 +529,7 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn, int_mask = WCN36XX_DXE_INT_CH3_MASK; } - while (!(dxe->ctrl & WCN36xx_DXE_CTRL_VLD)) { + while (!(READ_ONCE(dxe->ctrl) & WCN36xx_DXE_CTRL_VLD)) { skb = ctl->skb; dma_addr = dxe->dst_addr_l; ret = wcn36xx_dxe_fill_skb(wcn->dev, ctl, GFP_ATOMIC); -- cgit v1.2.3 From 7d9d0d562b54d2953304693f76bc2bbfbe318c27 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Thu, 12 Apr 2018 16:15:07 +0300 Subject: iwlwifi: mvm: add traffic condition monitoring (TCM) Traffic condition monitor gathers data about the traffic load and other conditions and can be used to make decisions regarding latency, throughput etc. This patch introduces the code and data structures to collect this data for future use. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/constants.h | 3 + drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 7 + .../net/wireless/intel/iwlwifi/mvm/debugfs-vif.c | 2 + drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 59 ++++++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 10 + drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 60 +++++- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 6 + drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 11 +- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 35 ++++ drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 231 +++++++++++++++++++++ 10 files changed, 415 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index 96b52a275ee3..2763fc69f04b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -112,6 +112,9 @@ #define IWL_MVM_PARSE_NVM 0 #define IWL_MVM_ADWELL_ENABLE 1 #define IWL_MVM_ADWELL_MAX_BUDGET 0 +#define IWL_MVM_TCM_LOAD_MEDIUM_THRESH 10 /* percentage */ +#define IWL_MVM_TCM_LOAD_HIGH_THRESH 50 /* percentage */ +#define IWL_MVM_TCM_LOWLAT_ENABLE_THRESH 100 /* packets/10 seconds */ #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 2efe9b099556..80a9a7cb83be 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1097,6 +1097,7 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) /* make sure the d0i3 exit work is not pending */ flush_work(&mvm->d0i3_exit_work); + iwl_mvm_pause_tcm(mvm, true); iwl_fw_runtime_suspend(&mvm->fwrt); @@ -2014,6 +2015,8 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED; + iwl_mvm_resume_tcm(mvm); + iwl_fw_runtime_resume(&mvm->fwrt); return ret; @@ -2042,6 +2045,8 @@ static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file) mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_D3; + iwl_mvm_pause_tcm(mvm, true); + iwl_fw_runtime_suspend(&mvm->fwrt); /* start pseudo D3 */ @@ -2104,6 +2109,8 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file) __iwl_mvm_resume(mvm, true); rtnl_unlock(); + iwl_mvm_resume_tcm(mvm); + iwl_fw_runtime_resume(&mvm->fwrt); mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index f7fcf700196b..798605c4f122 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -269,6 +269,8 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file, mvmvif->id, mvmvif->color); pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n", vif->bss_conf.bssid); + pos += scnprintf(buf+pos, bufsz-pos, "Load: %d\n", + mvm->tcm.result.load[mvmvif->id]); pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n"); for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++) pos += scnprintf(buf+pos, bufsz-pos, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index d2cf751db68d..72bab44082ea 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -92,6 +92,8 @@ #include "fw/acpi.h" #include "fw/debugfs.h" +#include + #define IWL_MVM_MAX_ADDRESSES 5 /* RSSI offset for WkP */ #define IWL_RSSI_OFFSET 50 @@ -595,6 +597,51 @@ enum iwl_mvm_tdls_cs_state { IWL_MVM_TDLS_SW_ACTIVE, }; +enum iwl_mvm_traffic_load { + IWL_MVM_TRAFFIC_LOW, + IWL_MVM_TRAFFIC_MEDIUM, + IWL_MVM_TRAFFIC_HIGH, +}; + +DECLARE_EWMA(rate, 16, 16) + +struct iwl_mvm_tcm_mac { + struct { + u32 pkts[IEEE80211_NUM_ACS]; + u32 airtime; + } tx; + struct { + u32 pkts[IEEE80211_NUM_ACS]; + u32 airtime; + u32 last_ampdu_ref; + } rx; + struct { + /* track AP's transfer in client mode */ + u64 rx_bytes; + struct ewma_rate rate; + bool detected; + } uapsd_nonagg_detect; +}; + +struct iwl_mvm_tcm { + struct delayed_work work; + spinlock_t lock; /* used when time elapsed */ + unsigned long ts; /* timestamp when period ends */ + unsigned long ll_ts; + unsigned long uapsd_nonagg_ts; + bool paused; + struct iwl_mvm_tcm_mac data[NUM_MAC_INDEX_DRIVER]; + struct { + u32 elapsed; /* milliseconds for this TCM period */ + u32 airtime[NUM_MAC_INDEX_DRIVER]; + enum iwl_mvm_traffic_load load[NUM_MAC_INDEX_DRIVER]; + enum iwl_mvm_traffic_load global_load; + bool low_latency[NUM_MAC_INDEX_DRIVER]; + bool change[NUM_MAC_INDEX_DRIVER]; + bool global_change; + } result; +}; + /** * struct iwl_mvm_reorder_buffer - per ra/tid/queue reorder buffer * @head_sn: reorder window head sn @@ -978,6 +1025,9 @@ struct iwl_mvm { */ bool temperature_test; /* Debug test temperature is enabled */ + unsigned long bt_coex_last_tcm_ts; + struct iwl_mvm_tcm tcm; + struct iwl_time_quota_cmd last_quota_cmd; #ifdef CONFIG_NL80211_TESTMODE @@ -1906,6 +1956,15 @@ bool iwl_mvm_is_vif_assoc(struct iwl_mvm *mvm); void iwl_mvm_inactivity_check(struct iwl_mvm *mvm); +#define MVM_TCM_PERIOD_MSEC 500 +#define MVM_TCM_PERIOD (HZ * MVM_TCM_PERIOD_MSEC / 1000) +#define MVM_LL_PERIOD (10 * HZ) +void iwl_mvm_tcm_work(struct work_struct *work); +void iwl_mvm_recalc_tcm(struct iwl_mvm *mvm); +void iwl_mvm_pause_tcm(struct iwl_mvm *mvm, bool with_cancel); +void iwl_mvm_resume_tcm(struct iwl_mvm *mvm); +u8 iwl_mvm_tcm_load_percentage(u32 airtime, u32 elapsed); + void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error); unsigned int iwl_mvm_get_wd_timeout(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 224bfa1bcf53..6a3f557543e4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -667,6 +667,12 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, SET_IEEE80211_DEV(mvm->hw, mvm->trans->dev); + spin_lock_init(&mvm->tcm.lock); + INIT_DELAYED_WORK(&mvm->tcm.work, iwl_mvm_tcm_work); + mvm->tcm.ts = jiffies; + mvm->tcm.ll_ts = jiffies; + mvm->tcm.uapsd_nonagg_ts = jiffies; + INIT_DELAYED_WORK(&mvm->cs_tx_unblock_dwork, iwl_mvm_tx_unblock_dwork); /* @@ -859,6 +865,8 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) for (i = 0; i < NVM_MAX_NUM_SECTIONS; i++) kfree(mvm->nvm_sections[i].data); + cancel_delayed_work_sync(&mvm->tcm.work); + iwl_mvm_tof_clean(mvm); mutex_destroy(&mvm->mutex); @@ -1432,6 +1440,7 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) mvm->d0i3_offloading = false; } + iwl_mvm_pause_tcm(mvm, true); /* make sure we have no running tx while configuring the seqno */ synchronize_net(); @@ -1615,6 +1624,7 @@ out: /* the FW might have updated the regdomain */ iwl_mvm_update_changed_regdom(mvm); + iwl_mvm_resume_tcm(mvm); iwl_mvm_unref(mvm, IWL_MVM_REF_EXIT_WORK); mutex_unlock(&mvm->mutex); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index d26833c5ce1f..be80294349c3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -254,6 +254,39 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm, return 0; } +static void iwl_mvm_rx_handle_tcm(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + struct ieee80211_hdr *hdr, u32 len, + struct iwl_rx_phy_info *phy_info, + u32 rate_n_flags) +{ + struct iwl_mvm_sta *mvmsta; + struct iwl_mvm_tcm_mac *mdata; + int mac; + int ac = IEEE80211_AC_BE; /* treat non-QoS as BE */ + + if (ieee80211_is_data_qos(hdr->frame_control)) + ac = tid_to_mac80211_ac[ieee80211_get_tid(hdr)]; + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + mac = mvmsta->mac_id_n_color & FW_CTXT_ID_MSK; + + if (time_after(jiffies, mvm->tcm.ts + MVM_TCM_PERIOD)) + schedule_delayed_work(&mvm->tcm.work, 0); + mdata = &mvm->tcm.data[mac]; + mdata->rx.pkts[ac]++; + + /* count the airtime only once for each ampdu */ + if (mdata->rx.last_ampdu_ref != mvm->ampdu_ref) { + mdata->rx.last_ampdu_ref = mvm->ampdu_ref; + mdata->rx.airtime += le16_to_cpu(phy_info->frame_time); + } + + if (!(rate_n_flags & (RATE_MCS_HT_MSK | RATE_MCS_VHT_MSK))) + return; + +} + static void iwl_mvm_rx_csum(struct ieee80211_sta *sta, struct sk_buff *skb, u32 status) @@ -408,6 +441,12 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, NULL); } + if (!mvm->tcm.paused && len >= sizeof(*hdr) && + !is_multicast_ether_addr(hdr->addr1) && + ieee80211_is_data(hdr->frame_control)) + iwl_mvm_rx_handle_tcm(mvm, sta, hdr, len, phy_info, + rate_n_flags); + if (ieee80211_is_data(hdr->frame_control)) iwl_mvm_rx_csum(sta, skb, rx_pkt_status); } @@ -654,7 +693,7 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, int expected_size; int i; u8 *energy; - __le32 *bytes, *air_time; + __le32 *air_time; __le32 flags; if (!iwl_mvm_has_new_rx_stats_api(mvm)) { @@ -729,13 +768,11 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, struct iwl_notif_statistics_v11 *v11 = (void *)&pkt->data; energy = (void *)&v11->load_stats.avg_energy; - bytes = (void *)&v11->load_stats.byte_count; air_time = (void *)&v11->load_stats.air_time; } else { struct iwl_notif_statistics_cdb *stats = (void *)&pkt->data; energy = (void *)&stats->load_stats.avg_energy; - bytes = (void *)&stats->load_stats.byte_count; air_time = (void *)&stats->load_stats.air_time; } @@ -752,6 +789,23 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, sta->avg_energy = energy[i]; } rcu_read_unlock(); + + /* + * Don't update in case the statistics are not cleared, since + * we will end up counting twice the same airtime, once in TCM + * request and once in statistics notification. + */ + if (!(le32_to_cpu(flags) & IWL_STATISTICS_REPLY_FLG_CLEAR)) + return; + + spin_lock(&mvm->tcm.lock); + for (i = 0; i < NUM_MAC_INDEX_DRIVER; i++) { + struct iwl_mvm_tcm_mac *mdata = &mvm->tcm.data[i]; + u32 airtime = le32_to_cpu(air_time[i]); + + mdata->rx.airtime += airtime; + } + spin_unlock(&mvm->tcm.lock); } void iwl_mvm_rx_statistics(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 4a4ccfd11e5b..f9cd7575b422 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -941,6 +941,12 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, IWL_RX_MPDU_REORDER_BAID_MASK) >> IWL_RX_MPDU_REORDER_BAID_SHIFT); + if (!mvm->tcm.paused && len >= sizeof(*hdr) && + !is_multicast_ether_addr(hdr->addr1) && + ieee80211_is_data(hdr->frame_control) && + time_after(jiffies, mvm->tcm.ts + MVM_TCM_PERIOD)) + schedule_delayed_work(&mvm->tcm.work, 0); + /* * We have tx blocked stations (with CS bit). If we heard * frames from a blocked station on a new channel we can diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index b31f0ffbbbf0..cd7ae6976935 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -76,12 +76,6 @@ #define IWL_DENSE_EBS_SCAN_RATIO 5 #define IWL_SPARSE_EBS_SCAN_RATIO 1 -enum iwl_mvm_traffic_load { - IWL_MVM_TRAFFIC_LOW, - IWL_MVM_TRAFFIC_MEDIUM, - IWL_MVM_TRAFFIC_HIGH, -}; - #define IWL_SCAN_DWELL_ACTIVE 10 #define IWL_SCAN_DWELL_PASSIVE 110 #define IWL_SCAN_DWELL_FRAGMENTED 44 @@ -437,6 +431,7 @@ void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, ieee80211_scan_completed(mvm->hw, &info); iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); cancel_delayed_work(&mvm->scan_timeout_dwork); + iwl_mvm_resume_tcm(mvm); } else { IWL_ERR(mvm, "got scan complete notification but no scan is running\n"); @@ -1568,6 +1563,8 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (ret) return ret; + iwl_mvm_pause_tcm(mvm, false); + ret = iwl_mvm_send_cmd(mvm, &hcmd); if (ret) { /* If the scan failed, it usually means that the FW was unable @@ -1575,6 +1572,7 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * should try to send the command again with different params. */ IWL_ERR(mvm, "Scan failed! ret %d\n", ret); + iwl_mvm_resume_tcm(mvm); return ret; } @@ -1711,6 +1709,7 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, mvm->scan_vif = NULL; iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); cancel_delayed_work(&mvm->scan_timeout_dwork); + iwl_mvm_resume_tcm(mvm); } else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_SCHED) { ieee80211_sched_scan_stopped(mvm->hw); mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 795065974d78..f06a0ee7be28 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -930,6 +930,32 @@ static bool iwl_mvm_txq_should_update(struct iwl_mvm *mvm, int txq_id) return false; } +static void iwl_mvm_tx_airtime(struct iwl_mvm *mvm, + struct iwl_mvm_sta *mvmsta, + int airtime) +{ + int mac = mvmsta->mac_id_n_color & FW_CTXT_ID_MSK; + struct iwl_mvm_tcm_mac *mdata = &mvm->tcm.data[mac]; + + if (mvm->tcm.paused) + return; + + if (time_after(jiffies, mvm->tcm.ts + MVM_TCM_PERIOD)) + schedule_delayed_work(&mvm->tcm.work, 0); + + mdata->tx.airtime += airtime; +} + +static void iwl_mvm_tx_pkt_queued(struct iwl_mvm *mvm, + struct iwl_mvm_sta *mvmsta, int tid) +{ + u32 ac = tid_to_mac80211_ac[tid]; + int mac = mvmsta->mac_id_n_color & FW_CTXT_ID_MSK; + struct iwl_mvm_tcm_mac *mdata = &mvm->tcm.data[mac]; + + mdata->tx.pkts[ac]++; +} + /* * Sets the fields in the Tx cmd that are crypto related */ @@ -1067,6 +1093,8 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, spin_unlock(&mvmsta->lock); + iwl_mvm_tx_pkt_queued(mvm, mvmsta, tid == IWL_MAX_TID_COUNT ? 0 : tid); + return 0; drop_unlock_sta: @@ -1469,6 +1497,9 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, if (!IS_ERR(sta)) { mvmsta = iwl_mvm_sta_from_mac80211(sta); + iwl_mvm_tx_airtime(mvm, mvmsta, + le16_to_cpu(tx_resp->wireless_media_time)); + if (tid != IWL_TID_NON_QOS && tid != IWL_MGMT_TID) { struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; @@ -1610,6 +1641,8 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm, le16_to_cpu(tx_resp->wireless_media_time); mvmsta->tid_data[tid].lq_color = TX_RES_RATE_TABLE_COL_GET(tx_resp->tlc_info); + iwl_mvm_tx_airtime(mvm, mvmsta, + le16_to_cpu(tx_resp->wireless_media_time)); } rcu_read_unlock(); @@ -1800,6 +1833,8 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) le32_to_cpu(ba_res->tx_rate)); } + iwl_mvm_tx_airtime(mvm, mvmsta, + le32_to_cpu(ba_res->wireless_time)); out_unlock: rcu_read_unlock(); out: diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index d99d9ea78e4c..27905f3fe3ba 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -1429,6 +1429,237 @@ void iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm, sta->addr, tid); } +u8 iwl_mvm_tcm_load_percentage(u32 airtime, u32 elapsed) +{ + if (!elapsed) + return 0; + + return (100 * airtime / elapsed) / USEC_PER_MSEC; +} + +static enum iwl_mvm_traffic_load +iwl_mvm_tcm_load(struct iwl_mvm *mvm, u32 airtime, unsigned long elapsed) +{ + u8 load = iwl_mvm_tcm_load_percentage(airtime, elapsed); + + if (load > IWL_MVM_TCM_LOAD_HIGH_THRESH) + return IWL_MVM_TRAFFIC_HIGH; + if (load > IWL_MVM_TCM_LOAD_MEDIUM_THRESH) + return IWL_MVM_TRAFFIC_MEDIUM; + + return IWL_MVM_TRAFFIC_LOW; +} + +struct iwl_mvm_tcm_iter_data { + struct iwl_mvm *mvm; + bool any_sent; +}; + +static void iwl_mvm_tcm_iter(void *_data, u8 *mac, struct ieee80211_vif *vif) +{ + struct iwl_mvm_tcm_iter_data *data = _data; + struct iwl_mvm *mvm = data->mvm; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + bool low_latency, prev = mvmvif->low_latency & LOW_LATENCY_TRAFFIC; + + if (mvmvif->id >= NUM_MAC_INDEX_DRIVER) + return; + + low_latency = mvm->tcm.result.low_latency[mvmvif->id]; + + if (!mvm->tcm.result.change[mvmvif->id] && + prev == low_latency) { + iwl_mvm_update_quotas(mvm, false, NULL); + return; + } + + if (prev != low_latency) { + /* this sends traffic load and updates quota as well */ + iwl_mvm_update_low_latency(mvm, vif, low_latency, + LOW_LATENCY_TRAFFIC); + } else { + iwl_mvm_update_quotas(mvm, false, NULL); + } + + data->any_sent = true; +} + +static void iwl_mvm_tcm_results(struct iwl_mvm *mvm) +{ + struct iwl_mvm_tcm_iter_data data = { + .mvm = mvm, + .any_sent = false, + }; + + mutex_lock(&mvm->mutex); + + ieee80211_iterate_active_interfaces( + mvm->hw, IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_tcm_iter, &data); + + if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) + iwl_mvm_config_scan(mvm); + + mutex_unlock(&mvm->mutex); +} + + +static unsigned long iwl_mvm_calc_tcm_stats(struct iwl_mvm *mvm, + unsigned long ts, + bool handle_uapsd) +{ + unsigned int elapsed = jiffies_to_msecs(ts - mvm->tcm.ts); + u32 total_airtime = 0; + int ac, mac; + bool low_latency = false; + enum iwl_mvm_traffic_load load; + bool handle_ll = time_after(ts, mvm->tcm.ll_ts + MVM_LL_PERIOD); + + if (handle_ll) + mvm->tcm.ll_ts = ts; + if (handle_uapsd) + mvm->tcm.uapsd_nonagg_ts = ts; + + mvm->tcm.result.elapsed = elapsed; + + for (mac = 0; mac < NUM_MAC_INDEX_DRIVER; mac++) { + struct iwl_mvm_tcm_mac *mdata = &mvm->tcm.data[mac]; + u32 vo_vi_pkts = 0; + u32 airtime = mdata->rx.airtime + mdata->tx.airtime; + + total_airtime += airtime; + + load = iwl_mvm_tcm_load(mvm, airtime, elapsed); + mvm->tcm.result.change[mac] = load != mvm->tcm.result.load[mac]; + mvm->tcm.result.load[mac] = load; + mvm->tcm.result.airtime[mac] = airtime; + + for (ac = IEEE80211_AC_VO; ac <= IEEE80211_AC_VI; ac++) + vo_vi_pkts += mdata->rx.pkts[ac] + + mdata->tx.pkts[ac]; + + /* enable immediately with enough packets but defer disabling */ + if (vo_vi_pkts > IWL_MVM_TCM_LOWLAT_ENABLE_THRESH) + mvm->tcm.result.low_latency[mac] = true; + else if (handle_ll) + mvm->tcm.result.low_latency[mac] = false; + + if (handle_ll) { + /* clear old data */ + memset(&mdata->rx.pkts, 0, sizeof(mdata->rx.pkts)); + memset(&mdata->tx.pkts, 0, sizeof(mdata->tx.pkts)); + } + low_latency |= mvm->tcm.result.low_latency[mac]; + + memset(&mdata->rx.airtime, 0, sizeof(mdata->rx.airtime)); + memset(&mdata->tx.airtime, 0, sizeof(mdata->tx.airtime)); + } + + load = iwl_mvm_tcm_load(mvm, total_airtime, elapsed); + mvm->tcm.result.global_change = load != mvm->tcm.result.global_load; + mvm->tcm.result.global_load = load; + + /* + * If the current load isn't low we need to force re-evaluation + * in the TCM period, so that we can return to low load if there + * was no traffic at all (and thus iwl_mvm_recalc_tcm didn't get + * triggered by traffic). + */ + if (load != IWL_MVM_TRAFFIC_LOW) + return MVM_TCM_PERIOD; + /* + * If low-latency is active we need to force re-evaluation after + * (the longer) MVM_LL_PERIOD, so that we can disable low-latency + * when there's no traffic at all. + */ + if (low_latency) + return MVM_LL_PERIOD; + /* + * Otherwise, we don't need to run the work struct because we're + * in the default "idle" state - traffic indication is low (which + * also covers the "no traffic" case) and low-latency is disabled + * so there's no state that may need to be disabled when there's + * no traffic at all. + * + * Note that this has no impact on the regular scheduling of the + * updates triggered by traffic - those happen whenever one of the + * two timeouts expire (if there's traffic at all.) + */ + return 0; +} + +void iwl_mvm_recalc_tcm(struct iwl_mvm *mvm) +{ + unsigned long ts = jiffies; + bool handle_uapsd = + false; + + spin_lock(&mvm->tcm.lock); + if (mvm->tcm.paused || !time_after(ts, mvm->tcm.ts + MVM_TCM_PERIOD)) { + spin_unlock(&mvm->tcm.lock); + return; + } + spin_unlock(&mvm->tcm.lock); + + + spin_lock(&mvm->tcm.lock); + /* re-check if somebody else won the recheck race */ + if (!mvm->tcm.paused && time_after(ts, mvm->tcm.ts + MVM_TCM_PERIOD)) { + /* calculate statistics */ + unsigned long work_delay = iwl_mvm_calc_tcm_stats(mvm, ts, + handle_uapsd); + + /* the memset needs to be visible before the timestamp */ + smp_mb(); + mvm->tcm.ts = ts; + if (work_delay) + schedule_delayed_work(&mvm->tcm.work, work_delay); + } + spin_unlock(&mvm->tcm.lock); + + iwl_mvm_tcm_results(mvm); +} + +void iwl_mvm_tcm_work(struct work_struct *work) +{ + struct delayed_work *delayed_work = to_delayed_work(work); + struct iwl_mvm *mvm = container_of(delayed_work, struct iwl_mvm, + tcm.work); + + iwl_mvm_recalc_tcm(mvm); +} + +void iwl_mvm_pause_tcm(struct iwl_mvm *mvm, bool with_cancel) +{ + spin_lock_bh(&mvm->tcm.lock); + mvm->tcm.paused = true; + spin_unlock_bh(&mvm->tcm.lock); + if (with_cancel) + cancel_delayed_work_sync(&mvm->tcm.work); +} + +void iwl_mvm_resume_tcm(struct iwl_mvm *mvm) +{ + int mac; + + spin_lock_bh(&mvm->tcm.lock); + mvm->tcm.ts = jiffies; + mvm->tcm.ll_ts = jiffies; + for (mac = 0; mac < NUM_MAC_INDEX_DRIVER; mac++) { + struct iwl_mvm_tcm_mac *mdata = &mvm->tcm.data[mac]; + + memset(&mdata->rx.pkts, 0, sizeof(mdata->rx.pkts)); + memset(&mdata->tx.pkts, 0, sizeof(mdata->tx.pkts)); + memset(&mdata->rx.airtime, 0, sizeof(mdata->rx.airtime)); + memset(&mdata->tx.airtime, 0, sizeof(mdata->tx.airtime)); + } + /* The TCM data needs to be reset before "paused" flag changes */ + smp_mb(); + mvm->tcm.paused = false; + spin_unlock_bh(&mvm->tcm.lock); +} + + void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime) { bool ps_disabled; -- cgit v1.2.3 From 85207c66a2f091c005b98fc4976c8daf297b56e7 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 13 Apr 2018 08:58:35 +0300 Subject: iwlwifi: mvm: use TCM data to decide scan priority The code for changing the scan priority is already implemented, but isn't yet in use. Now that TCM data is available, we can base the scan priority decision on the traffic load. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index cd7ae6976935..8f3185b9d365 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -228,7 +228,7 @@ static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac, static enum iwl_mvm_traffic_load iwl_mvm_get_traffic_load(struct iwl_mvm *mvm) { - return IWL_MVM_TRAFFIC_LOW; + return mvm->tcm.result.global_load; } static enum -- cgit v1.2.3 From bde1492d4a15ae37e1388a6f5a7972afb7ca32e3 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 9 Dec 2014 17:08:41 +0200 Subject: iwlwifi: mvm: BT Coex - make the primary / secondary pick traffic aware The primary channel is the channel that will be untouched by BT. The secondary channel might be touched by BT. Hence, we want the primary to be the most active channel. To do so, use the TCM infrastructure. Since the BT keeps sending notifications, we can rely on them to trigger the check. Every 10 seconds, we will check what is the most active context and chose the right primary. We need to wait 10 seconds before we modify the settings because frequent changes in these settings can confuse BT. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 37 +++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 890dbfff3a06..016e03a5034f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -279,6 +279,8 @@ struct iwl_bt_iterator_data { struct ieee80211_chanctx_conf *primary; struct ieee80211_chanctx_conf *secondary; bool primary_ll; + u8 primary_load; + u8 secondary_load; }; static inline @@ -295,6 +297,30 @@ void iwl_mvm_bt_coex_enable_rssi_event(struct iwl_mvm *mvm, enable ? -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH : 0; } +#define MVM_COEX_TCM_PERIOD (HZ * 10) + +static void iwl_mvm_bt_coex_tcm_based_ci(struct iwl_mvm *mvm, + struct iwl_bt_iterator_data *data) +{ + unsigned long now = jiffies; + + if (!time_after(now, mvm->bt_coex_last_tcm_ts + MVM_COEX_TCM_PERIOD)) + return; + + mvm->bt_coex_last_tcm_ts = now; + + /* We assume here that we don't have more than 2 vifs on 2.4GHz */ + + /* if the primary is low latency, it will stay primary */ + if (data->primary_ll) + return; + + if (data->primary_load >= data->secondary_load) + return; + + swap(data->primary, data->secondary); +} + /* must be called under rcu_read_lock */ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) @@ -385,6 +411,11 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, /* there is low latency vif - we will be secondary */ data->secondary = chanctx_conf; } + + if (data->primary == chanctx_conf) + data->primary_load = mvm->tcm.result.load[mvmvif->id]; + else if (data->secondary == chanctx_conf) + data->secondary_load = mvm->tcm.result.load[mvmvif->id]; return; } @@ -398,6 +429,10 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, /* if secondary is not NULL, it might be a GO */ data->secondary = chanctx_conf; + if (data->primary == chanctx_conf) + data->primary_load = mvm->tcm.result.load[mvmvif->id]; + else if (data->secondary == chanctx_conf) + data->secondary_load = mvm->tcm.result.load[mvmvif->id]; /* * don't reduce the Tx power if one of these is true: * we are in LOOSE @@ -449,6 +484,8 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_bt_notif_iterator, &data); + iwl_mvm_bt_coex_tcm_based_ci(mvm, &data); + if (data.primary) { struct ieee80211_chanctx_conf *chan = data.primary; if (WARN_ON(!chan->def.chan)) { -- cgit v1.2.3 From b0ffe455bc5bbdbcf7837274d2476f5597767237 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 11 Nov 2014 12:57:03 +0100 Subject: iwlwifi: mvm: detect U-APSD breaking aggregation Try to detect that the AP is not using aggregation even when there's enough traffic to make it worthwhile; if this is the case and U-APSD is enabled then assume the AP is broken (like so many) and doesn't enable aggregation when U-APSD is used. In this case, disconnect from the AP and blacklist U-APSD for a potential new connection to it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/constants.h | 4 + drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 25 ++++ drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 33 ++++++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 9 ++ drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 47 ++++++++ drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 127 ++++++++++++++++++++- 6 files changed, 244 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index 2763fc69f04b..d61ff66ce07b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -69,6 +69,8 @@ #include +#define IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM 20 + #define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC) #define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC) #define IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT (10 * USEC_PER_MSEC) @@ -115,6 +117,8 @@ #define IWL_MVM_TCM_LOAD_MEDIUM_THRESH 10 /* percentage */ #define IWL_MVM_TCM_LOAD_HIGH_THRESH 50 /* percentage */ #define IWL_MVM_TCM_LOWLAT_ENABLE_THRESH 100 /* packets/10 seconds */ +#define IWL_MVM_UAPSD_NONAGG_PERIOD 5000 /* msecs */ +#define IWL_MVM_UAPSD_NOAGG_LIST_LEN IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 0e6401cd7ccc..1c4178f20441 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1728,6 +1728,27 @@ iwl_dbgfs_send_echo_cmd_write(struct iwl_mvm *mvm, char *buf, return ret ?: count; } +static ssize_t +iwl_dbgfs_uapsd_noagg_bssids_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + u8 buf[IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM * ETH_ALEN * 3 + 1]; + unsigned int pos = 0; + size_t bufsz = sizeof(buf); + int i; + + mutex_lock(&mvm->mutex); + + for (i = 0; i < IWL_MVM_UAPSD_NOAGG_LIST_LEN; i++) + pos += scnprintf(buf + pos, bufsz - pos, "%pM\n", + mvm->uapsd_noagg_bssids[i].addr); + + mutex_unlock(&mvm->mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64); /* Device wide debugfs entries */ @@ -1762,6 +1783,8 @@ MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl, (IWL_RSS_INDIRECTION_TABLE_SIZE * 2)); MVM_DEBUGFS_WRITE_FILE_OPS(inject_packet, 512); +MVM_DEBUGFS_READ_FILE_OPS(uapsd_noagg_bssids); + #ifdef CONFIG_IWLWIFI_BCAST_FILTERING MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256); @@ -1972,6 +1995,8 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) mvm->debugfs_dir, &mvm->drop_bcn_ap_mode)) goto err; + MVM_DEBUGFS_ADD_FILE(uapsd_noagg_bssids, mvm->debugfs_dir, S_IRUSR); + #ifdef CONFIG_IWLWIFI_BCAST_FILTERING if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) { bcast_dir = debugfs_create_dir("bcast_filtering", diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 51b30424575b..08318bdaaf2e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -952,6 +952,16 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: + if (iwl_mvm_vif_from_mac80211(vif)->ap_sta_id == + iwl_mvm_sta_from_mac80211(sta)->sta_id) { + struct iwl_mvm_vif *mvmvif; + u16 macid = iwl_mvm_vif_from_mac80211(vif)->id; + struct iwl_mvm_tcm_mac *mdata = &mvm->tcm.data[macid]; + + mdata->opened_rx_ba_sessions = true; + mvmvif = iwl_mvm_vif_from_mac80211(vif); + cancel_delayed_work(&mvmvif->uapsd_nonagg_detected_wk); + } if (!iwl_enable_rx_ampdu(mvm->cfg)) { ret = -EINVAL; break; @@ -1435,6 +1445,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, mvm->p2p_device_vif = vif; } + iwl_mvm_tcm_add_vif(mvm, vif); + if (vif->type == NL80211_IFTYPE_MONITOR) mvm->monitor_on = true; @@ -1486,6 +1498,10 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, iwl_mvm_prepare_mac_removal(mvm, vif); + if (!(vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_ADHOC)) + iwl_mvm_tcm_rm_vif(mvm, vif); + mutex_lock(&mvm->mutex); if (mvm->bf_allowed_vif == mvmvif) { @@ -2535,6 +2551,16 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, static void iwl_mvm_check_uapsd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, const u8 *bssid) { + int i; + + if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { + struct iwl_mvm_tcm_mac *mdata; + + mdata = &mvm->tcm.data[iwl_mvm_vif_from_mac80211(vif)->id]; + ewma_rate_init(&mdata->uapsd_nonagg_detect.rate); + mdata->opened_rx_ba_sessions = false; + } + if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT)) return; @@ -2549,6 +2575,13 @@ static void iwl_mvm_check_uapsd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return; } + for (i = 0; i < IWL_MVM_UAPSD_NOAGG_LIST_LEN; i++) { + if (ether_addr_equal(mvm->uapsd_noagg_bssids[i].addr, bssid)) { + vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD; + return; + } + } + vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 72bab44082ea..acc36eb1ef39 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -446,6 +446,8 @@ struct iwl_mvm_vif { /* FW identified misbehaving AP */ u8 uapsd_misbehaving_bssid[ETH_ALEN]; + struct delayed_work uapsd_nonagg_detected_wk; + /* Indicates that CSA countdown may be started */ bool csa_countdown; bool csa_failed; @@ -621,6 +623,7 @@ struct iwl_mvm_tcm_mac { struct ewma_rate rate; bool detected; } uapsd_nonagg_detect; + bool opened_rx_ba_sessions; }; struct iwl_mvm_tcm { @@ -1028,6 +1031,10 @@ struct iwl_mvm { unsigned long bt_coex_last_tcm_ts; struct iwl_mvm_tcm tcm; + u8 uapsd_noagg_bssid_write_idx; + struct mac_address uapsd_noagg_bssids[IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM] + __aligned(2); + struct iwl_time_quota_cmd last_quota_cmd; #ifdef CONFIG_NL80211_TESTMODE @@ -1963,6 +1970,8 @@ void iwl_mvm_tcm_work(struct work_struct *work); void iwl_mvm_recalc_tcm(struct iwl_mvm *mvm); void iwl_mvm_pause_tcm(struct iwl_mvm *mvm, bool with_cancel); void iwl_mvm_resume_tcm(struct iwl_mvm *mvm); +void iwl_mvm_tcm_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +void iwl_mvm_tcm_rm_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); u8 iwl_mvm_tcm_load_percentage(u32 airtime, u32 elapsed); void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index be80294349c3..bfb163419c67 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -264,6 +264,12 @@ static void iwl_mvm_rx_handle_tcm(struct iwl_mvm *mvm, struct iwl_mvm_tcm_mac *mdata; int mac; int ac = IEEE80211_AC_BE; /* treat non-QoS as BE */ + struct iwl_mvm_vif *mvmvif; + /* expected throughput in 100Kbps, single stream, 20 MHz */ + static const u8 thresh_tpt[] = { + 9, 18, 30, 42, 60, 78, 90, 96, 120, 135, + }; + u16 thr; if (ieee80211_is_data_qos(hdr->frame_control)) ac = tid_to_mac80211_ac[ieee80211_get_tid(hdr)]; @@ -285,6 +291,35 @@ static void iwl_mvm_rx_handle_tcm(struct iwl_mvm *mvm, if (!(rate_n_flags & (RATE_MCS_HT_MSK | RATE_MCS_VHT_MSK))) return; + mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); + + if (mdata->opened_rx_ba_sessions || + mdata->uapsd_nonagg_detect.detected || + (!mvmvif->queue_params[IEEE80211_AC_VO].uapsd && + !mvmvif->queue_params[IEEE80211_AC_VI].uapsd && + !mvmvif->queue_params[IEEE80211_AC_BE].uapsd && + !mvmvif->queue_params[IEEE80211_AC_BK].uapsd) || + mvmsta->sta_id != mvmvif->ap_sta_id) + return; + + if (rate_n_flags & RATE_MCS_HT_MSK) { + thr = thresh_tpt[rate_n_flags & RATE_HT_MCS_RATE_CODE_MSK]; + thr *= 1 + ((rate_n_flags & RATE_HT_MCS_NSS_MSK) >> + RATE_HT_MCS_NSS_POS); + } else { + if (WARN_ON((rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK) >= + ARRAY_SIZE(thresh_tpt))) + return; + thr = thresh_tpt[rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK]; + thr *= 1 + ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> + RATE_VHT_MCS_NSS_POS); + } + + thr <<= ((rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) >> + RATE_MCS_CHAN_WIDTH_POS); + + mdata->uapsd_nonagg_detect.rx_bytes += len; + ewma_rate_add(&mdata->uapsd_nonagg_detect.rate, thr); } static void iwl_mvm_rx_csum(struct ieee80211_sta *sta, @@ -693,6 +728,7 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, int expected_size; int i; u8 *energy; + __le32 *bytes; __le32 *air_time; __le32 flags; @@ -768,11 +804,13 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, struct iwl_notif_statistics_v11 *v11 = (void *)&pkt->data; energy = (void *)&v11->load_stats.avg_energy; + bytes = (void *)&v11->load_stats.byte_count; air_time = (void *)&v11->load_stats.air_time; } else { struct iwl_notif_statistics_cdb *stats = (void *)&pkt->data; energy = (void *)&stats->load_stats.avg_energy; + bytes = (void *)&stats->load_stats.byte_count; air_time = (void *)&stats->load_stats.air_time; } @@ -802,6 +840,15 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, for (i = 0; i < NUM_MAC_INDEX_DRIVER; i++) { struct iwl_mvm_tcm_mac *mdata = &mvm->tcm.data[i]; u32 airtime = le32_to_cpu(air_time[i]); + u32 rx_bytes = le32_to_cpu(bytes[i]); + + mdata->uapsd_nonagg_detect.rx_bytes += rx_bytes; + if (airtime) { + /* re-init every time to store rate from FW */ + ewma_rate_init(&mdata->uapsd_nonagg_detect.rate); + ewma_rate_add(&mdata->uapsd_nonagg_detect.rate, + rx_bytes * 8 / airtime); + } mdata->rx.airtime += airtime; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 27905f3fe3ba..ea0332a2389e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -1503,12 +1503,109 @@ static void iwl_mvm_tcm_results(struct iwl_mvm *mvm) mutex_unlock(&mvm->mutex); } +static void iwl_mvm_tcm_uapsd_nonagg_detected_wk(struct work_struct *wk) +{ + struct iwl_mvm *mvm; + struct iwl_mvm_vif *mvmvif; + struct ieee80211_vif *vif; + + mvmvif = container_of(wk, struct iwl_mvm_vif, + uapsd_nonagg_detected_wk.work); + vif = container_of((void *)mvmvif, struct ieee80211_vif, drv_priv); + mvm = mvmvif->mvm; + + if (mvm->tcm.data[mvmvif->id].opened_rx_ba_sessions) + return; + + /* remember that this AP is broken */ + memcpy(mvm->uapsd_noagg_bssids[mvm->uapsd_noagg_bssid_write_idx].addr, + vif->bss_conf.bssid, ETH_ALEN); + mvm->uapsd_noagg_bssid_write_idx++; + if (mvm->uapsd_noagg_bssid_write_idx >= IWL_MVM_UAPSD_NOAGG_LIST_LEN) + mvm->uapsd_noagg_bssid_write_idx = 0; + + iwl_mvm_connection_loss(mvm, vif, + "AP isn't using AMPDU with uAPSD enabled"); +} + +static void iwl_mvm_uapsd_agg_disconnect_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + int *mac_id = data; + + if (vif->type != NL80211_IFTYPE_STATION) + return; + + if (mvmvif->id != *mac_id) + return; + + if (!vif->bss_conf.assoc) + return; + + if (!mvmvif->queue_params[IEEE80211_AC_VO].uapsd && + !mvmvif->queue_params[IEEE80211_AC_VI].uapsd && + !mvmvif->queue_params[IEEE80211_AC_BE].uapsd && + !mvmvif->queue_params[IEEE80211_AC_BK].uapsd) + return; + + if (mvm->tcm.data[*mac_id].uapsd_nonagg_detect.detected) + return; + + mvm->tcm.data[*mac_id].uapsd_nonagg_detect.detected = true; + IWL_INFO(mvm, + "detected AP should do aggregation but isn't, likely due to U-APSD\n"); + schedule_delayed_work(&mvmvif->uapsd_nonagg_detected_wk, 15 * HZ); +} + +static void iwl_mvm_check_uapsd_agg_expected_tpt(struct iwl_mvm *mvm, + unsigned int elapsed, + int mac) +{ + u64 bytes = mvm->tcm.data[mac].uapsd_nonagg_detect.rx_bytes; + u64 tpt; + unsigned long rate; + + rate = ewma_rate_read(&mvm->tcm.data[mac].uapsd_nonagg_detect.rate); + + if (!rate || mvm->tcm.data[mac].opened_rx_ba_sessions || + mvm->tcm.data[mac].uapsd_nonagg_detect.detected) + return; + + if (iwl_mvm_has_new_rx_api(mvm)) { + tpt = 8 * bytes; /* kbps */ + do_div(tpt, elapsed); + rate *= 1000; /* kbps */ + if (tpt < 22 * rate / 100) + return; + } else { + /* + * the rate here is actually the threshold, in 100Kbps units, + * so do the needed conversion from bytes to 100Kbps: + * 100kb = bits / (100 * 1000), + * 100kbps = 100kb / (msecs / 1000) == + * (bits / (100 * 1000)) / (msecs / 1000) == + * bits / (100 * msecs) + */ + tpt = (8 * bytes); + do_div(tpt, elapsed * 100); + if (tpt < rate) + return; + } + + ieee80211_iterate_active_interfaces_atomic( + mvm->hw, IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_uapsd_agg_disconnect_iter, &mac); +} static unsigned long iwl_mvm_calc_tcm_stats(struct iwl_mvm *mvm, unsigned long ts, bool handle_uapsd) { unsigned int elapsed = jiffies_to_msecs(ts - mvm->tcm.ts); + unsigned int uapsd_elapsed = + jiffies_to_msecs(ts - mvm->tcm.uapsd_nonagg_ts); u32 total_airtime = 0; int ac, mac; bool low_latency = false; @@ -1551,6 +1648,12 @@ static unsigned long iwl_mvm_calc_tcm_stats(struct iwl_mvm *mvm, } low_latency |= mvm->tcm.result.low_latency[mac]; + if (!mvm->tcm.result.low_latency[mac] && handle_uapsd) + iwl_mvm_check_uapsd_agg_expected_tpt(mvm, uapsd_elapsed, + mac); + /* clear old data */ + if (handle_uapsd) + mdata->uapsd_nonagg_detect.rx_bytes = 0; memset(&mdata->rx.airtime, 0, sizeof(mdata->rx.airtime)); memset(&mdata->tx.airtime, 0, sizeof(mdata->tx.airtime)); } @@ -1592,7 +1695,8 @@ void iwl_mvm_recalc_tcm(struct iwl_mvm *mvm) { unsigned long ts = jiffies; bool handle_uapsd = - false; + time_after(ts, mvm->tcm.uapsd_nonagg_ts + + msecs_to_jiffies(IWL_MVM_UAPSD_NONAGG_PERIOD)); spin_lock(&mvm->tcm.lock); if (mvm->tcm.paused || !time_after(ts, mvm->tcm.ts + MVM_TCM_PERIOD)) { @@ -1601,6 +1705,12 @@ void iwl_mvm_recalc_tcm(struct iwl_mvm *mvm) } spin_unlock(&mvm->tcm.lock); + if (handle_uapsd && iwl_mvm_has_new_rx_api(mvm)) { + mutex_lock(&mvm->mutex); + if (iwl_mvm_request_statistics(mvm, true)) + handle_uapsd = false; + mutex_unlock(&mvm->mutex); + } spin_lock(&mvm->tcm.lock); /* re-check if somebody else won the recheck race */ @@ -1659,6 +1769,21 @@ void iwl_mvm_resume_tcm(struct iwl_mvm *mvm) spin_unlock_bh(&mvm->tcm.lock); } +void iwl_mvm_tcm_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + INIT_DELAYED_WORK(&mvmvif->uapsd_nonagg_detected_wk, + iwl_mvm_tcm_uapsd_nonagg_detected_wk); +} + +void iwl_mvm_tcm_rm_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + cancel_delayed_work_sync(&mvmvif->uapsd_nonagg_detected_wk); +} + void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime) { -- cgit v1.2.3 From b66b5817a0ce0e5653f4f60ab583c19cb5dab546 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 31 Jan 2017 10:39:44 +0200 Subject: iwlwifi: mvm: detect low latency and traffic load per band Detect low latency and traffic load per band. Add support for deciding on scan type and timings per band. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 1 + drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 8 ++ drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 167 ++++++++++++++++++------- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 66 ++++++++-- 4 files changed, 192 insertions(+), 50 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 3c59109bea20..4cf3e32e3dba 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1093,6 +1093,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { mvm->scan_type = IWL_SCAN_TYPE_NOT_SET; + mvm->hb_scan_type = IWL_SCAN_TYPE_NOT_SET; ret = iwl_mvm_config_scan(mvm); if (ret) goto error; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index acc36eb1ef39..2150b785387f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -35,6 +36,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -638,6 +640,7 @@ struct iwl_mvm_tcm { u32 elapsed; /* milliseconds for this TCM period */ u32 airtime[NUM_MAC_INDEX_DRIVER]; enum iwl_mvm_traffic_load load[NUM_MAC_INDEX_DRIVER]; + enum iwl_mvm_traffic_load band_load[NUM_NL80211_BANDS]; enum iwl_mvm_traffic_load global_load; bool low_latency[NUM_MAC_INDEX_DRIVER]; bool change[NUM_MAC_INDEX_DRIVER]; @@ -879,7 +882,10 @@ struct iwl_mvm { unsigned int scan_status; void *scan_cmd; struct iwl_mcast_filter_cmd *mcast_filter_cmd; + /* For CDB this is low band scan type, for non-CDB - type. */ enum iwl_mvm_scan_type scan_type; + enum iwl_mvm_scan_type hb_scan_type; + enum iwl_mvm_sched_scan_pass_all_states sched_scan_pass_all; struct delayed_work scan_timeout_dwork; @@ -1828,6 +1834,8 @@ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum iwl_mvm_low_latency_cause cause); /* get SystemLowLatencyMode - only needed for beacon threshold? */ bool iwl_mvm_low_latency(struct iwl_mvm *mvm); +bool iwl_mvm_low_latency_band(struct iwl_mvm *mvm, enum nl80211_band band); + /* get VMACLowLatencyMode */ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 8f3185b9d365..8fcd92dcaaa7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -19,9 +20,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA + * along with this program * * The full GNU General Public License is included in this distribution * in the file called COPYING. @@ -117,7 +116,9 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = { }; struct iwl_mvm_scan_params { + /* For CDB this is low band scan type, for non-CDB - type. */ enum iwl_mvm_scan_type type; + enum iwl_mvm_scan_type hb_type; u32 n_channels; u16 delay; int n_ssids; @@ -231,12 +232,18 @@ static enum iwl_mvm_traffic_load iwl_mvm_get_traffic_load(struct iwl_mvm *mvm) return mvm->tcm.result.global_load; } +static enum iwl_mvm_traffic_load +iwl_mvm_get_traffic_load_band(struct iwl_mvm *mvm, enum nl80211_band band) +{ + return mvm->tcm.result.band_load[band]; +} + static enum -iwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm, bool p2p_device) +iwl_mvm_scan_type _iwl_mvm_get_scan_type(struct iwl_mvm *mvm, bool p2p_device, + enum iwl_mvm_traffic_load load, + bool low_latency) { int global_cnt = 0; - enum iwl_mvm_traffic_load load; - bool low_latency; ieee80211_iterate_active_interfaces_atomic(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, @@ -245,9 +252,6 @@ iwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm, bool p2p_device) if (!global_cnt) return IWL_SCAN_TYPE_UNASSOC; - load = iwl_mvm_get_traffic_load(mvm); - low_latency = iwl_mvm_low_latency(mvm); - if ((load == IWL_MVM_TRAFFIC_HIGH || low_latency) && !p2p_device && fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) return IWL_SCAN_TYPE_FRAGMENTED; @@ -258,25 +262,57 @@ iwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm, bool p2p_device) return IWL_SCAN_TYPE_WILD; } +static enum +iwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm, bool p2p_device) +{ + enum iwl_mvm_traffic_load load; + bool low_latency; + + load = iwl_mvm_get_traffic_load(mvm); + low_latency = iwl_mvm_low_latency(mvm); + + return _iwl_mvm_get_scan_type(mvm, p2p_device, load, low_latency); +} + +static enum +iwl_mvm_scan_type iwl_mvm_get_scan_type_band(struct iwl_mvm *mvm, + bool p2p_device, + enum nl80211_band band) +{ + enum iwl_mvm_traffic_load load; + bool low_latency; + + load = iwl_mvm_get_traffic_load_band(mvm, band); + low_latency = iwl_mvm_low_latency_band(mvm, band); + + return _iwl_mvm_get_scan_type(mvm, p2p_device, load, low_latency); +} + static int iwl_mvm_get_measurement_dwell(struct iwl_mvm *mvm, struct cfg80211_scan_request *req, struct iwl_mvm_scan_params *params) { + u32 duration = scan_timing[params->type].max_out_time; + if (!req->duration) return 0; - if (req->duration_mandatory && - req->duration > scan_timing[params->type].max_out_time) { + if (iwl_mvm_is_cdb_supported(mvm)) { + u32 hb_time = scan_timing[params->hb_type].max_out_time; + + duration = min_t(u32, duration, hb_time); + } + + if (req->duration_mandatory && req->duration > duration) { IWL_DEBUG_SCAN(mvm, "Measurement scan - too long dwell %hu (max out time %u)\n", req->duration, - scan_timing[params->type].max_out_time); + duration); return -EOPNOTSUPP; } - return min_t(u32, (u32)req->duration, - scan_timing[params->type].max_out_time); + return min_t(u32, (u32)req->duration, duration); } static inline bool iwl_mvm_rrm_scan_needed(struct iwl_mvm *mvm) @@ -1025,22 +1061,38 @@ static void iwl_mvm_fill_scan_config_v1(struct iwl_mvm *mvm, void *config, static void iwl_mvm_fill_scan_config(struct iwl_mvm *mvm, void *config, u32 flags, u8 channel_flags) { - enum iwl_mvm_scan_type type = iwl_mvm_get_scan_type(mvm, false); struct iwl_scan_config *cfg = config; cfg->flags = cpu_to_le32(flags); cfg->tx_chains = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm)); cfg->rx_chains = cpu_to_le32(iwl_mvm_scan_rx_ant(mvm)); cfg->legacy_rates = iwl_mvm_scan_config_rates(mvm); - cfg->out_of_channel_time[0] = - cpu_to_le32(scan_timing[type].max_out_time); - cfg->suspend_time[0] = cpu_to_le32(scan_timing[type].suspend_time); if (iwl_mvm_is_cdb_supported(mvm)) { - cfg->suspend_time[1] = - cpu_to_le32(scan_timing[type].suspend_time); - cfg->out_of_channel_time[1] = + enum iwl_mvm_scan_type lb_type, hb_type; + + lb_type = iwl_mvm_get_scan_type_band(mvm, false, + NL80211_BAND_2GHZ); + hb_type = iwl_mvm_get_scan_type_band(mvm, false, + NL80211_BAND_5GHZ); + + cfg->out_of_channel_time[SCAN_LB_LMAC_IDX] = + cpu_to_le32(scan_timing[lb_type].max_out_time); + cfg->suspend_time[SCAN_LB_LMAC_IDX] = + cpu_to_le32(scan_timing[lb_type].suspend_time); + + cfg->out_of_channel_time[SCAN_HB_LMAC_IDX] = + cpu_to_le32(scan_timing[hb_type].max_out_time); + cfg->suspend_time[SCAN_HB_LMAC_IDX] = + cpu_to_le32(scan_timing[hb_type].suspend_time); + } else { + enum iwl_mvm_scan_type type = + iwl_mvm_get_scan_type(mvm, false); + + cfg->out_of_channel_time[SCAN_LB_LMAC_IDX] = cpu_to_le32(scan_timing[type].max_out_time); + cfg->suspend_time[SCAN_LB_LMAC_IDX] = + cpu_to_le32(scan_timing[type].suspend_time); } iwl_mvm_fill_scan_dwell(mvm, &cfg->dwell); @@ -1060,7 +1112,8 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) struct iwl_host_cmd cmd = { .id = iwl_cmd_id(SCAN_CFG_CMD, IWL_ALWAYS_LONG_GROUP, 0), }; - enum iwl_mvm_scan_type type = iwl_mvm_get_scan_type(mvm, false); + enum iwl_mvm_scan_type type; + enum iwl_mvm_scan_type hb_type = IWL_SCAN_TYPE_NOT_SET; int num_channels = mvm->nvm_data->bands[NL80211_BAND_2GHZ].n_channels + mvm->nvm_data->bands[NL80211_BAND_5GHZ].n_channels; @@ -1070,8 +1123,18 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) if (WARN_ON(num_channels > mvm->fw->ucode_capa.n_scan_channels)) return -ENOBUFS; - if (type == mvm->scan_type) - return 0; + if (iwl_mvm_is_cdb_supported(mvm)) { + type = iwl_mvm_get_scan_type_band(mvm, false, + NL80211_BAND_2GHZ); + hb_type = iwl_mvm_get_scan_type_band(mvm, false, + NL80211_BAND_5GHZ); + if (type == mvm->scan_type && hb_type == mvm->hb_scan_type) + return 0; + } else { + type = iwl_mvm_get_scan_type(mvm, false); + if (type == mvm->scan_type) + return 0; + } if (iwl_mvm_has_new_tx_api(mvm)) cmd_size = sizeof(struct iwl_scan_config); @@ -1102,10 +1165,15 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) IWL_CHANNEL_FLAG_EBS_ADD | IWL_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE; + /* + * Check for fragmented scan on LMAC2 - high band. + * LMAC1 - low band is checked above. + */ if (iwl_mvm_has_new_tx_api(mvm)) { - flags |= (type == IWL_SCAN_TYPE_FRAGMENTED) ? - SCAN_CONFIG_FLAG_SET_LMAC2_FRAGMENTED : - SCAN_CONFIG_FLAG_CLEAR_LMAC2_FRAGMENTED; + if (iwl_mvm_is_cdb_supported(mvm)) + flags |= (hb_type == IWL_SCAN_TYPE_FRAGMENTED) ? + SCAN_CONFIG_FLAG_SET_LMAC2_FRAGMENTED : + SCAN_CONFIG_FLAG_CLEAR_LMAC2_FRAGMENTED; iwl_mvm_fill_scan_config(mvm, cfg, flags, channel_flags); } else { iwl_mvm_fill_scan_config_v1(mvm, cfg, flags, channel_flags); @@ -1118,8 +1186,10 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) IWL_DEBUG_SCAN(mvm, "Sending UMAC scan config\n"); ret = iwl_mvm_send_cmd(mvm, &cmd); - if (!ret) + if (!ret) { mvm->scan_type = type; + mvm->hb_scan_type = hb_type; + } kfree(cfg); return ret; @@ -1173,7 +1243,7 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, cpu_to_le32(timing->suspend_time); if (iwl_mvm_is_cdb_supported(mvm)) { - hb_timing = &scan_timing[params->type]; + hb_timing = &scan_timing[params->hb_type]; cmd->v7.max_out_time[SCAN_HB_LMAC_IDX] = cpu_to_le32(hb_timing->max_out_time); @@ -1203,7 +1273,7 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, cmd->v1.fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED; if (iwl_mvm_is_cdb_supported(mvm)) { - hb_timing = &scan_timing[params->type]; + hb_timing = &scan_timing[params->hb_type]; cmd->v6.max_out_time[SCAN_HB_LMAC_IDX] = cpu_to_le32(hb_timing->max_out_time); @@ -1212,8 +1282,7 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, } if (iwl_mvm_has_new_tx_api(mvm)) { - cmd->v6.scan_priority = - cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); + cmd->v6.scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); cmd->v6.max_out_time[SCAN_LB_LMAC_IDX] = cpu_to_le32(timing->max_out_time); cmd->v6.suspend_time[SCAN_LB_LMAC_IDX] = @@ -1257,11 +1326,12 @@ static u16 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm, if (params->n_ssids == 1 && params->ssids[0].ssid_len != 0) flags |= IWL_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT; - if (params->type == IWL_SCAN_TYPE_FRAGMENTED) { + if (params->type == IWL_SCAN_TYPE_FRAGMENTED) flags |= IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED; - if (iwl_mvm_is_cdb_supported(mvm)) - flags |= IWL_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED; - } + + if (iwl_mvm_is_cdb_supported(mvm) && + params->hb_type == IWL_SCAN_TYPE_FRAGMENTED) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED; if (iwl_mvm_rrm_scan_needed(mvm) && fw_has_capa(&mvm->fw->ucode_capa, @@ -1492,6 +1562,21 @@ void iwl_mvm_scan_timeout_wk(struct work_struct *work) iwl_force_nmi(mvm->trans); } +static void iwl_mvm_fill_scan_type(struct iwl_mvm *mvm, + struct iwl_mvm_scan_params *params, + bool p2p) +{ + if (iwl_mvm_is_cdb_supported(mvm)) { + params->type = + iwl_mvm_get_scan_type_band(mvm, p2p, + NL80211_BAND_2GHZ); + params->hb_type = + iwl_mvm_get_scan_type_band(mvm, p2p, + NL80211_BAND_5GHZ); + } else { + params->type = iwl_mvm_get_scan_type(mvm, p2p); + } +} int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct cfg80211_scan_request *req, struct ieee80211_scan_ies *ies) @@ -1539,9 +1624,8 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, params.scan_plans = &scan_plan; params.n_scan_plans = 1; - params.type = - iwl_mvm_get_scan_type(mvm, - vif->type == NL80211_IFTYPE_P2P_DEVICE); + iwl_mvm_fill_scan_type(mvm, ¶ms, + vif->type == NL80211_IFTYPE_P2P_DEVICE); ret = iwl_mvm_get_measurement_dwell(mvm, req, ¶ms); if (ret < 0) @@ -1636,9 +1720,8 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, params.n_scan_plans = req->n_scan_plans; params.scan_plans = req->scan_plans; - params.type = - iwl_mvm_get_scan_type(mvm, - vif->type == NL80211_IFTYPE_P2P_DEVICE); + iwl_mvm_fill_scan_type(mvm, ¶ms, + vif->type == NL80211_IFTYPE_P2P_DEVICE); /* In theory, LMAC scans can handle a 32-bit delay, but since * waiting for over 18 hours to start the scan is a bit silly diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index ea0332a2389e..815d2d141fd8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -1074,23 +1074,48 @@ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return iwl_mvm_power_update_mac(mvm); } +struct iwl_mvm_low_latency_iter { + bool result; + bool result_per_band[NUM_NL80211_BANDS]; +}; + static void iwl_mvm_ll_iter(void *_data, u8 *mac, struct ieee80211_vif *vif) { - bool *result = _data; + struct iwl_mvm_low_latency_iter *result = _data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + enum nl80211_band band; + + if (iwl_mvm_vif_low_latency(mvmvif)) { + result->result = true; + + if (!mvmvif->phy_ctxt) + return; - if (iwl_mvm_vif_low_latency(iwl_mvm_vif_from_mac80211(vif))) - *result = true; + band = mvmvif->phy_ctxt->channel->band; + result->result_per_band[band] = true; + } } bool iwl_mvm_low_latency(struct iwl_mvm *mvm) { - bool result = false; + struct iwl_mvm_low_latency_iter data = {}; ieee80211_iterate_active_interfaces_atomic( mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_ll_iter, &result); + iwl_mvm_ll_iter, &data); - return result; + return data.result; +} + +bool iwl_mvm_low_latency_band(struct iwl_mvm *mvm, enum nl80211_band band) +{ + struct iwl_mvm_low_latency_iter data = {}; + + ieee80211_iterate_active_interfaces_atomic( + mvm->hw, IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_ll_iter, &data); + + return data.result_per_band[band]; } struct iwl_bss_iter_data { @@ -1599,6 +1624,18 @@ static void iwl_mvm_check_uapsd_agg_expected_tpt(struct iwl_mvm *mvm, iwl_mvm_uapsd_agg_disconnect_iter, &mac); } +static void iwl_mvm_tcm_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + u32 *band = _data; + + if (!mvmvif->phy_ctxt) + return; + + band[mvmvif->id] = mvmvif->phy_ctxt->channel->band; +} + static unsigned long iwl_mvm_calc_tcm_stats(struct iwl_mvm *mvm, unsigned long ts, bool handle_uapsd) @@ -1607,9 +1644,11 @@ static unsigned long iwl_mvm_calc_tcm_stats(struct iwl_mvm *mvm, unsigned int uapsd_elapsed = jiffies_to_msecs(ts - mvm->tcm.uapsd_nonagg_ts); u32 total_airtime = 0; - int ac, mac; + u32 band_airtime[NUM_NL80211_BANDS] = {0}; + u32 band[NUM_MAC_INDEX_DRIVER] = {0}; + int ac, mac, i; bool low_latency = false; - enum iwl_mvm_traffic_load load; + enum iwl_mvm_traffic_load load, band_load; bool handle_ll = time_after(ts, mvm->tcm.ll_ts + MVM_LL_PERIOD); if (handle_ll) @@ -1619,12 +1658,18 @@ static unsigned long iwl_mvm_calc_tcm_stats(struct iwl_mvm *mvm, mvm->tcm.result.elapsed = elapsed; + ieee80211_iterate_active_interfaces_atomic(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_tcm_iterator, + &band); + for (mac = 0; mac < NUM_MAC_INDEX_DRIVER; mac++) { struct iwl_mvm_tcm_mac *mdata = &mvm->tcm.data[mac]; u32 vo_vi_pkts = 0; u32 airtime = mdata->rx.airtime + mdata->tx.airtime; total_airtime += airtime; + band_airtime[band[mac]] += airtime; load = iwl_mvm_tcm_load(mvm, airtime, elapsed); mvm->tcm.result.change[mac] = load != mvm->tcm.result.load[mac]; @@ -1662,6 +1707,11 @@ static unsigned long iwl_mvm_calc_tcm_stats(struct iwl_mvm *mvm, mvm->tcm.result.global_change = load != mvm->tcm.result.global_load; mvm->tcm.result.global_load = load; + for (i = 0; i < NUM_NL80211_BANDS; i++) { + band_load = iwl_mvm_tcm_load(mvm, band_airtime[i], elapsed); + mvm->tcm.result.band_load[i] = band_load; + } + /* * If the current load isn't low we need to force re-evaluation * in the TCM period, so that we can return to low load if there -- cgit v1.2.3 From 622111a2d21baca39bb8d5cf56c2d509e50fe278 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Jun 2017 09:07:11 +0200 Subject: iwlwifi: mvm: clean up scan capability checks Introduce and use iwl_mvm_cdb_scan_api(), which checks the family. Most of this will go away once the 22000 firmware supports adaptive dwell, after which the V6 scan API won't be used, but the V3 scan *config* API will still need to be distinguished. In any case, this gets rid of the completely bogus has_new_tx_api() checks. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 10 ++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 15 ++++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 2150b785387f..2411cc91f833 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1356,6 +1356,16 @@ static inline bool iwl_mvm_is_cdb_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_CDB_SUPPORT); } +static inline bool iwl_mvm_cdb_scan_api(struct iwl_mvm *mvm) +{ + /* + * TODO: should this be the same as iwl_mvm_is_cdb_supported()? + * but then there's a little bit of code in scan that won't make + * any sense... + */ + return mvm->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22000; +} + static inline bool iwl_mvm_has_new_rx_stats_api(struct iwl_mvm *mvm) { return fw_has_api(&mvm->fw->ucode_capa, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 8fcd92dcaaa7..8c5f4f96d6d4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -147,7 +147,7 @@ static inline void *iwl_mvm_get_scan_req_umac_data(struct iwl_mvm *mvm) if (iwl_mvm_is_adaptive_dwell_supported(mvm)) return (void *)&cmd->v7.data; - if (iwl_mvm_has_new_tx_api(mvm)) + if (iwl_mvm_cdb_scan_api(mvm)) return (void *)&cmd->v6.data; return (void *)&cmd->v1.data; @@ -164,7 +164,7 @@ iwl_mvm_get_scan_req_umac_channel(struct iwl_mvm *mvm) if (iwl_mvm_is_adaptive_dwell_supported(mvm)) return &cmd->v7.channel; - if (iwl_mvm_has_new_tx_api(mvm)) + if (iwl_mvm_cdb_scan_api(mvm)) return &cmd->v6.channel; return &cmd->v1.channel; @@ -1136,7 +1136,7 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) return 0; } - if (iwl_mvm_has_new_tx_api(mvm)) + if (iwl_mvm_cdb_scan_api(mvm)) cmd_size = sizeof(struct iwl_scan_config); else cmd_size = sizeof(struct iwl_scan_config_v1); @@ -1169,7 +1169,7 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) * Check for fragmented scan on LMAC2 - high band. * LMAC1 - low band is checked above. */ - if (iwl_mvm_has_new_tx_api(mvm)) { + if (iwl_mvm_cdb_scan_api(mvm)) { if (iwl_mvm_is_cdb_supported(mvm)) flags |= (hb_type == IWL_SCAN_TYPE_FRAGMENTED) ? SCAN_CONFIG_FLAG_SET_LMAC2_FRAGMENTED : @@ -1281,8 +1281,9 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, cpu_to_le32(hb_timing->suspend_time); } - if (iwl_mvm_has_new_tx_api(mvm)) { - cmd->v6.scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); + if (iwl_mvm_cdb_scan_api(mvm)) { + cmd->v6.scan_priority = + cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); cmd->v6.max_out_time[SCAN_LB_LMAC_IDX] = cpu_to_le32(timing->max_out_time); cmd->v6.suspend_time[SCAN_LB_LMAC_IDX] = @@ -1909,7 +1910,7 @@ int iwl_mvm_scan_size(struct iwl_mvm *mvm) base_size = IWL_SCAN_REQ_UMAC_SIZE_V8; else if (iwl_mvm_is_adaptive_dwell_supported(mvm)) base_size = IWL_SCAN_REQ_UMAC_SIZE_V7; - else if (iwl_mvm_has_new_tx_api(mvm)) + else if (iwl_mvm_cdb_scan_api(mvm)) base_size = IWL_SCAN_REQ_UMAC_SIZE_V6; if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) -- cgit v1.2.3 From cf58c9e0915aad684aa8e9b82afd260c67ee7b22 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 13 Apr 2018 13:17:16 +0300 Subject: iwlwifi: mvm: fix OOC priority in scans The code that sets the correct out-of-channel priority depending on the scan type was accidentally removed during a rebase. Add it back. Fixes: c1a7515393e4 ("iwlwifi: mvm: add adaptive dwell support") Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 8c5f4f96d6d4..4b3753d78d03 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1297,6 +1297,11 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, cpu_to_le32(timing->suspend_time); } } + + if (iwl_mvm_is_regular_scan(params)) + cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); + else + cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_2); } static void -- cgit v1.2.3 From 84226ca1c5d34e6a8492d12848e9cdf7752b834b Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Thu, 2 Nov 2017 04:07:52 +0200 Subject: iwlwifi: mvm: support offload of AMSDU rate control Support the new APIs and activate AMSDU based on the offloaded TLC decisions. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/datapath.h | 5 +++ drivers/net/wireless/intel/iwlwifi/fw/api/rs.h | 18 ++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 8 +++-- drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 42 +++++++++++++++++++++- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 15 +++++--- drivers/net/wireless/intel/iwlwifi/mvm/rs.h | 5 ++- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 7 ++-- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 11 ++++-- 8 files changed, 96 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h index a57c7223df0f..184cee98c359 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -92,6 +92,11 @@ enum iwl_data_path_subcmd_ids { */ TLC_MNG_NOTIF_REQ_CMD = 0x10, + /** + * @TLC_MNG_AMSDU_ENABLE_NOTIF: &struct iwl_tlc_amsdu_notif + */ + TLC_MNG_AMSDU_ENABLE_NOTIF = 0xF6, + /** * @TLC_MNG_UPDATE_NOTIF: &struct iwl_tlc_update_notif */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h index e49a6f7be613..1a8f3154a1fe 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h @@ -205,7 +205,7 @@ enum iwl_tlc_mng_ht_rates { * @non_ht_supp_rates: bitmap of supported legacy rates * @ht_supp_rates: bitmap of supported HT/VHT rates, valid bits are 0-9 * @mode: &enum iwl_tlc_mng_cfg_mode - * @reserved2: reserved + * @amsdu: TX amsdu is supported * @he_supp_rates: bitmap of supported HE rates * @sgi_ch_width_supp: bitmap of SGI support per channel width * @he_gi_support: 11ax HE guard interval @@ -222,13 +222,27 @@ struct iwl_tlc_config_cmd { __le16 non_ht_supp_rates; __le16 ht_supp_rates[MAX_RS_ANT_NUM]; u8 mode; - u8 reserved2; + u8 amsdu; __le16 he_supp_rates; u8 sgi_ch_width_supp; u8 he_gi_support; __le32 max_ampdu_cnt; } __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_1 */ +/** + * struct iwl_tlc_amsdu_notif - TLC AMSDU configuration + * @sta_id: station id + * @reserved: reserved + * @amsdu_size: Max AMSDU size, in bytes + * @amsdu_enabled: bitmap for per-TID AMSDU enablement + */ +struct iwl_tlc_amsdu_notif { + u8 sta_id; + u8 reserved[3]; + __le16 amsdu_size; + __le16 amsdu_enabled; +} __packed; /* TLC_MNG_AMSDU_ENABLE_NTFY_API_S_VER_1 */ + #define IWL_TLC_NOTIF_INIT_RATE_POS 0 #define IWL_TLC_NOTIF_INIT_RATE_MSK BIT(IWL_TLC_NOTIF_INIT_RATE_POS) #define IWL_TLC_NOTIF_REQ_INTERVAL (500) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 6a3f557543e4..1ef4ac21f32a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -250,6 +250,9 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, RX_HANDLER_SYNC), RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, RX_HANDLER_SYNC), + RX_HANDLER_GRP(DATA_PATH_GROUP, TLC_MNG_UPDATE_NOTIF, + iwl_mvm_tlc_update_notif, RX_HANDLER_SYNC), + RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, RX_HANDLER_ASYNC_LOCKED), RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, @@ -309,6 +312,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { iwl_mvm_mu_mimo_grp_notif, RX_HANDLER_SYNC), RX_HANDLER_GRP(DATA_PATH_GROUP, STA_PM_NOTIF, iwl_mvm_sta_pm_notif, RX_HANDLER_SYNC), + RX_HANDLER_GRP(DATA_PATH_GROUP, TLC_MNG_AMSDU_ENABLE_NOTIF, + iwl_mvm_tlc_amsdu_notif, RX_HANDLER_SYNC), }; #undef RX_HANDLER #undef RX_HANDLER_GRP @@ -445,6 +450,7 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = { HCMD_NAME(DQA_ENABLE_CMD), HCMD_NAME(UPDATE_MU_GROUPS_CMD), HCMD_NAME(TRIGGER_RX_QUEUES_NOTIF_CMD), + HCMD_NAME(TLC_MNG_AMSDU_ENABLE_NOTIF), HCMD_NAME(STA_PM_NOTIF), HCMD_NAME(MU_GROUP_MGMT_NOTIF), HCMD_NAME(RX_QUEUES_NOTIFICATION), @@ -1034,8 +1040,6 @@ static void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode, iwl_mvm_rx_queue_notif(mvm, rxb, 0); else if (cmd == WIDE_ID(LEGACY_GROUP, FRAME_RELEASE)) iwl_mvm_rx_frame_release(mvm, napi, rxb, 0); - else if (cmd == WIDE_ID(DATA_PATH_GROUP, TLC_MNG_UPDATE_NOTIF)) - iwl_mvm_tlc_update_notif(mvm, pkt); else iwl_mvm_rx_common(mvm, rxb, pkt); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index fb5745660509..4e818bce469b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -228,8 +228,47 @@ static void rs_fw_tlc_mng_notif_req_config(struct iwl_mvm *mvm, u8 sta_id) IWL_ERR(mvm, "Failed to send TLC notif request (%d)\n", ret); } -void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) +void iwl_mvm_tlc_amsdu_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_tlc_amsdu_notif *notif; + struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; + u16 size; + + notif = (void *)pkt->data; + + if (WARN_ON(notif->sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id))) + return; + + rcu_read_lock(); + + sta = rcu_dereference(mvm->fw_id_to_mac_id[notif->sta_id]); + if (IS_ERR_OR_NULL(sta)) { + rcu_read_unlock(); + IWL_ERR(mvm, "Invalid sta id (%d) in FW TLC notification\n", + notif->sta_id); + return; + } + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + + size = min(le16_to_cpu(notif->amsdu_size), sta->max_amsdu_len); + mvmsta->amsdu_enabled = le16_to_cpu(notif->amsdu_enabled); + mvmsta->max_amsdu_len = size; + + IWL_DEBUG_RATE(mvm, + "AMSDU notification. AMSDU size: %d, AMSDU selected size: %d, AMSDU TID bitmap 0x%X\n", + le16_to_cpu(notif->amsdu_size), size, + mvmsta->amsdu_enabled); + + rcu_read_unlock(); +}; + +void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_tlc_update_notif *notif; struct iwl_mvm_sta *mvmsta; struct iwl_lq_sta_rs_fw *lq_sta; @@ -273,6 +312,7 @@ void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, .max_supp_ss = sta->rx_nss, .max_ampdu_cnt = cpu_to_le32(mvmsta->max_agg_bufsize), .sgi_ch_width_supp = rs_fw_sgi_cw_support(sta), + .amsdu = iwl_mvm_is_csum_supported(mvm), }; int ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 5d776ec1840f..af7bc3b7b0c3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -1715,12 +1715,18 @@ static void rs_set_amsdu_len(struct iwl_mvm *mvm, struct ieee80211_sta *sta, { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + /* + * In case TLC offload is not active amsdu_enabled is either 0xFFFF + * or 0, since there is no per-TID alg. + */ if ((!is_vht(&tbl->rate) && !is_ht(&tbl->rate)) || tbl->rate.index < IWL_RATE_MCS_5_INDEX || scale_action == RS_ACTION_DOWNSCALE) - mvmsta->tlc_amsdu = false; + mvmsta->amsdu_enabled = 0; else - mvmsta->tlc_amsdu = true; + mvmsta->amsdu_enabled = 0xFFFF; + + mvmsta->max_amsdu_len = sta->max_amsdu_len; } /* @@ -3134,7 +3140,8 @@ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, sband = hw->wiphy->bands[band]; lq_sta->lq.sta_id = mvmsta->sta_id; - mvmsta->tlc_amsdu = false; + mvmsta->amsdu_enabled = 0; + mvmsta->max_amsdu_len = sta->max_amsdu_len; for (j = 0; j < LQ_SIZE; j++) rs_rate_scale_clear_tbl_windows(mvm, &lq_sta->lq_info[j]); @@ -3744,7 +3751,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, (rate->sgi) ? "SGI" : "NGI", (rate->ldpc) ? "LDPC" : "BCC", (lq_sta->is_agg) ? "AGG on" : "", - (mvmsta->tlc_amsdu) ? "AMSDU on" : ""); + (mvmsta->amsdu_enabled) ? "AMSDU on" : ""); } desc += scnprintf(buff + desc, bufsz - desc, "last tx rate=0x%X\n", lq_sta->last_rate_n_flags); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h index fb18cb8c233d..736ac9642921 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h @@ -454,5 +454,8 @@ void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, enum nl80211_band band); int rs_fw_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, bool enable); -void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt); +void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_tlc_amsdu_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); #endif /* __rs__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 5ffd6adbc383..60502c81dfce 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -391,7 +391,9 @@ struct iwl_mvm_rxq_dup_data { * @tx_protection: reference counter for controlling the Tx protection. * @tt_tx_protection: is thermal throttling enable Tx protection? * @disable_tx: is tx to this STA disabled? - * @tlc_amsdu: true if A-MSDU is allowed + * @amsdu_enabled: bitmap of TX AMSDU allowed TIDs. + * In case TLC offload is not active it is either 0xFFFF or 0. + * @max_amsdu_len: max AMSDU length * @agg_tids: bitmap of tids whose status is operational aggregated (IWL_AGG_ON) * @sleep_tx_count: the number of frames that we told the firmware to let out * even when that station is asleep. This is useful in case the queue @@ -436,7 +438,8 @@ struct iwl_mvm_sta { bool tt_tx_protection; bool disable_tx; - bool tlc_amsdu; + u16 amsdu_enabled; + u16 max_amsdu_len; bool sleeping; bool associated; u8 agg_tids; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index f06a0ee7be28..90381348697c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -774,9 +774,9 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, dbg_max_amsdu_len = READ_ONCE(mvm->max_amsdu_len); - if (!sta->max_amsdu_len || + if (!mvmsta->max_amsdu_len || !ieee80211_is_data_qos(hdr->frame_control) || - (!mvmsta->tlc_amsdu && !dbg_max_amsdu_len)) + (!mvmsta->amsdu_enabled && !dbg_max_amsdu_len)) return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb); /* @@ -803,7 +803,12 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, !mvmsta->tid_data[tid].amsdu_in_ampdu_allowed) return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb); - max_amsdu_len = sta->max_amsdu_len; + if (iwl_mvm_vif_low_latency(iwl_mvm_vif_from_mac80211(mvmsta->vif)) || + tid_to_mac80211_ac[tid] < IEEE80211_AC_BE || + !(mvmsta->amsdu_enabled & BIT(tid))) + return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb); + + max_amsdu_len = mvmsta->max_amsdu_len; /* the Tx FIFO to which this A-MSDU will be routed */ txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, tid_to_mac80211_ac[tid]); -- cgit v1.2.3 From f79b8f9dc77238f03d7fffd8f34976cfc7b076b5 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 25 Dec 2017 15:15:06 +0200 Subject: iwlwifi: pcie: implement the overlow queue for Gen2 devices When we enable TSO, we can have a lot of packets in the operation mode that will be pushed to the transport no matter what is the queue's fullness state. To cope with that the transport can buffer those packets and add them to the ring later when there is more room. This implementation was missing in the Gen2 devices' code. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 27 ++++++++++++++++++++--- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 2 +- 2 files changed, 25 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index fabae0f60683..b605b364ed3f 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -488,6 +488,23 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, spin_lock(&txq->lock); + if (iwl_queue_space(txq) < txq->high_mark) { + iwl_stop_queue(trans, txq); + + /* don't put the packet on the ring, if there is no room */ + if (unlikely(iwl_queue_space(txq) < 3)) { + struct iwl_device_cmd **dev_cmd_ptr; + + dev_cmd_ptr = (void *)((u8 *)skb->cb + + trans_pcie->dev_cmd_offs); + + *dev_cmd_ptr = dev_cmd; + __skb_queue_tail(&txq->overflow_q, skb); + spin_unlock(&txq->lock); + return 0; + } + } + idx = iwl_pcie_get_cmd_index(txq, txq->write_ptr); /* Set up driver data for this TFD */ @@ -523,9 +540,6 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, /* Tell device the write index *just past* this latest filled TFD */ txq->write_ptr = iwl_queue_inc_wrap(txq->write_ptr); iwl_pcie_gen2_txq_inc_wr_ptr(trans, txq); - if (iwl_queue_space(txq) < txq->high_mark) - iwl_stop_queue(trans, txq); - /* * At this point the frame is "transmitted" successfully * and we will get a TX status notification eventually. @@ -957,6 +971,13 @@ void iwl_pcie_gen2_txq_unmap(struct iwl_trans *trans, int txq_id) spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); } } + + while (!skb_queue_empty(&txq->overflow_q)) { + struct sk_buff *skb = __skb_dequeue(&txq->overflow_q); + + iwl_op_mode_free_skb(trans->op_mode, skb); + } + spin_unlock_bh(&txq->lock); /* just in case - this queue may have been stopped */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 1a566287993d..86873b99e5d7 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1166,7 +1166,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, * In that case, iwl_queue_space will be small again * and we won't wake mac80211's queue. */ - iwl_trans_pcie_tx(trans, skb, dev_cmd_ptr, txq_id); + iwl_trans_tx(trans, skb, dev_cmd_ptr, txq_id); } spin_lock_bh(&txq->lock); -- cgit v1.2.3 From 422b5dd4294c3c5a3d88c77041f1fceff1d2e4ce Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Wed, 27 Dec 2017 22:10:28 +0200 Subject: iwlwifi: move timestamp functions from debugfs.h to dbg.h These functions are not debugfs functions so they should be in dbg.h instad in debugfs.h. Signed-off-by: Haim Dreyfuss Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 36 +++++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/debugfs.c | 1 + drivers/net/wireless/intel/iwlwifi/fw/debugfs.h | 31 --------------------- 3 files changed, 37 insertions(+), 31 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 72259bff9922..507d9a49fa97 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -227,4 +227,40 @@ static inline void iwl_fw_cancel_dump(struct iwl_fw_runtime *fwrt) cancel_delayed_work_sync(&fwrt->dump.wk); } +#ifdef CONFIG_IWLWIFI_DEBUGFS +static inline void iwl_fw_cancel_timestamp(struct iwl_fw_runtime *fwrt) +{ + fwrt->timestamp.delay = 0; + cancel_delayed_work_sync(&fwrt->timestamp.wk); +} + +void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt, u32 delay); + +static inline void iwl_fw_suspend_timestamp(struct iwl_fw_runtime *fwrt) +{ + cancel_delayed_work_sync(&fwrt->timestamp.wk); +} + +static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) +{ + if (!fwrt->timestamp.delay) + return; + + schedule_delayed_work(&fwrt->timestamp.wk, + round_jiffies_relative(fwrt->timestamp.delay)); +} + +#else + +static inline void iwl_fw_cancel_timestamp(struct iwl_fw_runtime *fwrt) {} + +static inline void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt, + u32 delay) {} + +static inline void iwl_fw_suspend_timestamp(struct iwl_fw_runtime *fwrt) {} + +static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {} + +#endif /* CONFIG_IWLWIFI_DEBUGFS */ + #endif /* __iwl_fw_dbg_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c index 8f005cd69559..8ba5a60ec9ed 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c @@ -64,6 +64,7 @@ *****************************************************************************/ #include "api/commands.h" #include "debugfs.h" +#include "dbg.h" #define FWRT_DEBUGFS_READ_FILE_OPS(name) \ static ssize_t iwl_dbgfs_##name##_read(struct iwl_fw_runtime *fwrt, \ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h index d93f6a4bb22d..cbbfa8e9e66d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h @@ -69,28 +69,6 @@ int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt, struct dentry *dbgfs_dir); -static inline void iwl_fw_cancel_timestamp(struct iwl_fw_runtime *fwrt) -{ - fwrt->timestamp.delay = 0; - cancel_delayed_work_sync(&fwrt->timestamp.wk); -} - -static inline void iwl_fw_suspend_timestamp(struct iwl_fw_runtime *fwrt) -{ - cancel_delayed_work_sync(&fwrt->timestamp.wk); -} - -static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) -{ - if (!fwrt->timestamp.delay) - return; - - schedule_delayed_work(&fwrt->timestamp.wk, - round_jiffies_relative(fwrt->timestamp.delay)); -} - -void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt, u32 delay); - #else static inline int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt, struct dentry *dbgfs_dir) @@ -98,13 +76,4 @@ static inline int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt, return 0; } -static inline void iwl_fw_cancel_timestamp(struct iwl_fw_runtime *fwrt) {} - -static inline void iwl_fw_suspend_timestamp(struct iwl_fw_runtime *fwrt) {} - -static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {} - -static inline void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt, - u32 delay) {} - #endif /* CONFIG_IWLWIFI_DEBUGFS */ -- cgit v1.2.3 From e0498146c8792b1ebc321c0e29e633b6a0918a6e Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 4 Jan 2018 13:53:55 +0200 Subject: iwlwifi: pcie: allocate shorter TX queues for 22000 devices When support for shorter TX queues was introduced, it didn't include the actual allocation of shorter queue, which is the main motive for the change. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 2 +- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index b605b364ed3f..734a5fc3584d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -993,7 +993,7 @@ static void iwl_pcie_gen2_txq_free_memory(struct iwl_trans *trans, /* De-alloc circular buffer of TFDs */ if (txq->tfds) { dma_free_coherent(dev, - trans_pcie->tfd_size * TFD_QUEUE_SIZE_MAX, + trans_pcie->tfd_size * txq->n_window, txq->tfds, txq->dma_addr); dma_free_coherent(dev, sizeof(*txq->first_tb_bufs) * txq->n_window, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 86873b99e5d7..4493520aae1e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -495,6 +495,9 @@ int iwl_pcie_txq_alloc(struct iwl_trans *trans, struct iwl_txq *txq, if (WARN_ON(txq->entries || txq->tfds)) return -EINVAL; + if (trans->cfg->use_tfh) + tfd_sz = trans_pcie->tfd_size * slots_num; + timer_setup(&txq->stuck_timer, iwl_pcie_txq_stuck_timer, 0); txq->trans_pcie = trans_pcie; -- cgit v1.2.3 From 01302f5b4a5e5791b3938ab8d3216232b1830b90 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 4 Jan 2018 13:47:09 +0200 Subject: iwlwifi: Revert "iwlwifi: pcie: dynamic Tx command queue size" This reverts commit dd05f9aab4426ff178b12d601e50d19d336eba30. Shorter TX queues support was added eventually without the need for the parameters this patch added. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 1 - drivers/net/wireless/intel/iwlwifi/iwl-config.h | 3 --- .../net/wireless/intel/iwlwifi/pcie/ctxt-info.c | 2 +- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 3 --- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 8 ++------ drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 23 ++-------------------- 6 files changed, 5 insertions(+), 35 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index dffd9df782b0..f2b6e0e8d787 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -137,7 +137,6 @@ static const struct iwl_ht_params iwl_22000_ht_params = { .gen2 = true, \ .nvm_type = IWL_NVM_EXT, \ .dbgc_supported = true, \ - .tx_cmd_queue_size = 32, \ .min_umac_error_event_table = 0x400000 const struct iwl_cfg iwl22000_2ac_cfg_hr = { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index f0f5636dd3ea..687bed30c851 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -333,8 +333,6 @@ struct iwl_pwr_tx_backoff { * @gen2: 22000 and on transport operation * @cdb: CDB support * @nvm_type: see &enum iwl_nvm_type - * @tx_cmd_queue_size: size of the cmd queue. If zero, use the same value as - * the regular queues * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -386,7 +384,6 @@ struct iwl_cfg { gen2:1, cdb:1, dbgc_supported:1; - u16 tx_cmd_queue_size; u8 valid_tx_ant; u8 valid_rx_ant; u8 non_shared_ant; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c index 5ef216f3a60b..3fc4343581ee 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c @@ -244,7 +244,7 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans, ctxt_info->hcmd_cfg.cmd_queue_addr = cpu_to_le64(trans_pcie->txq[trans_pcie->cmd_queue]->dma_addr); ctxt_info->hcmd_cfg.cmd_queue_size = - TFD_QUEUE_CB_SIZE(trans_pcie->tx_cmd_queue_size); + TFD_QUEUE_CB_SIZE(TFD_CMD_SLOTS); /* allocate ucode sections in dram and set addresses */ ret = iwl_pcie_ctxt_info_init_fw_sec(trans, fw, ctxt_info); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index ca3b64ff4dad..a8833028e1cf 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -383,7 +383,6 @@ struct iwl_self_init_dram { * @hw_init_mask: initial unmasked hw causes * @fh_mask: current unmasked fh causes * @hw_mask: current unmasked hw causes - * @tx_cmd_queue_size: the size of the tx command queue */ struct iwl_trans_pcie { struct iwl_rxq *rxq; @@ -465,7 +464,6 @@ struct iwl_trans_pcie { u32 fh_mask; u32 hw_mask; cpumask_t affinity_mask[IWL_MAX_RX_HW_QUEUES]; - u16 tx_cmd_queue_size; }; static inline struct iwl_trans_pcie * @@ -537,7 +535,6 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, struct sk_buff_head *skbs); void iwl_trans_pcie_tx_reset(struct iwl_trans *trans); -void iwl_pcie_set_tx_cmd_queue_size(struct iwl_trans *trans); static inline u16 iwl_pcie_tfd_tb_get_len(struct iwl_trans *trans, void *_tfd, u8 idx) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 734a5fc3584d..7bdb9c9e04b1 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -1173,8 +1173,6 @@ int iwl_pcie_gen2_tx_init(struct iwl_trans *trans) struct iwl_txq *cmd_queue; int txq_id = trans_pcie->cmd_queue, ret; - iwl_pcie_set_tx_cmd_queue_size(trans); - /* alloc and init the command queue */ if (!trans_pcie->txq[txq_id]) { cmd_queue = kzalloc(sizeof(*cmd_queue), GFP_KERNEL); @@ -1183,8 +1181,7 @@ int iwl_pcie_gen2_tx_init(struct iwl_trans *trans) return -ENOMEM; } trans_pcie->txq[txq_id] = cmd_queue; - ret = iwl_pcie_txq_alloc(trans, cmd_queue, - trans_pcie->tx_cmd_queue_size, true); + ret = iwl_pcie_txq_alloc(trans, cmd_queue, TFD_CMD_SLOTS, true); if (ret) { IWL_ERR(trans, "Tx %d queue init failed\n", txq_id); goto error; @@ -1193,8 +1190,7 @@ int iwl_pcie_gen2_tx_init(struct iwl_trans *trans) cmd_queue = trans_pcie->txq[txq_id]; } - ret = iwl_pcie_txq_init(trans, cmd_queue, - trans_pcie->tx_cmd_queue_size, true); + ret = iwl_pcie_txq_init(trans, cmd_queue, TFD_CMD_SLOTS, true); if (ret) { IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id); goto error; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 4493520aae1e..cf468b9f5a82 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -953,8 +953,7 @@ static int iwl_pcie_tx_alloc(struct iwl_trans *trans) txq_id++) { bool cmd_queue = (txq_id == trans_pcie->cmd_queue); - slots_num = cmd_queue ? trans_pcie->tx_cmd_queue_size : - TFD_TX_CMD_SLOTS; + slots_num = cmd_queue ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; trans_pcie->txq[txq_id] = &trans_pcie->txq_memory[txq_id]; ret = iwl_pcie_txq_alloc(trans, trans_pcie->txq[txq_id], slots_num, cmd_queue); @@ -973,21 +972,6 @@ error: return ret; } -void iwl_pcie_set_tx_cmd_queue_size(struct iwl_trans *trans) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - int queue_size = TFD_CMD_SLOTS; - - if (trans->cfg->tx_cmd_queue_size) - queue_size = trans->cfg->tx_cmd_queue_size; - - if (WARN_ON(!(is_power_of_2(queue_size) && - TFD_QUEUE_CB_SIZE(queue_size) > 0))) - trans_pcie->tx_cmd_queue_size = TFD_CMD_SLOTS; - else - trans_pcie->tx_cmd_queue_size = queue_size; -} - int iwl_pcie_tx_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -995,8 +979,6 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) int txq_id, slots_num; bool alloc = false; - iwl_pcie_set_tx_cmd_queue_size(trans); - if (!trans_pcie->txq_memory) { ret = iwl_pcie_tx_alloc(trans); if (ret) @@ -1020,8 +1002,7 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) txq_id++) { bool cmd_queue = (txq_id == trans_pcie->cmd_queue); - slots_num = cmd_queue ? trans_pcie->tx_cmd_queue_size : - TFD_TX_CMD_SLOTS; + slots_num = cmd_queue ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; ret = iwl_pcie_txq_init(trans, trans_pcie->txq[txq_id], slots_num, cmd_queue); if (ret) { -- cgit v1.2.3 From 5369774c84eac674af1741c4322ad7728694d80b Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 4 Jan 2018 14:17:06 +0200 Subject: iwlwifi: add TX queue size parameter to TX queue allocation As preparation for dynamic queue sizing, add a parameter of the TX queue size to the dynamic queue allocation op mode API. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/txq.h | 1 + drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 8 ++++---- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 3 ++- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 2 +- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 2 +- 5 files changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/txq.h b/drivers/net/wireless/intel/iwlwifi/fw/api/txq.h index dfa111bb411e..1f45b2ce5295 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/txq.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/txq.h @@ -131,6 +131,7 @@ enum iwl_tx_queue_cfg_actions { TX_QUEUE_CFG_TFD_SHORT_FORMAT = BIT(1), }; +#define IWL_DEFAULT_QUEUE_SIZE 256 /** * struct iwl_tx_queue_cfg_cmd - txq hw scheduler config command * @sta_id: station id diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index c25ed1a0bbb0..a92832711683 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -554,7 +554,7 @@ struct iwl_trans_ops { /* 22000 functions */ int (*txq_alloc)(struct iwl_trans *trans, struct iwl_tx_queue_cfg_cmd *cmd, - int cmd_id, + int cmd_id, int size, unsigned int queue_wdg_timeout); void (*txq_free)(struct iwl_trans *trans, int queue); @@ -952,8 +952,8 @@ iwl_trans_txq_free(struct iwl_trans *trans, int queue) static inline int iwl_trans_txq_alloc(struct iwl_trans *trans, struct iwl_tx_queue_cfg_cmd *cmd, - int cmd_id, - unsigned int queue_wdg_timeout) + int cmd_id, int size, + unsigned int wdg_timeout) { might_sleep(); @@ -965,7 +965,7 @@ iwl_trans_txq_alloc(struct iwl_trans *trans, return -EIO; } - return trans->ops->txq_alloc(trans, cmd, cmd_id, queue_wdg_timeout); + return trans->ops->txq_alloc(trans, cmd, cmd_id, size, wdg_timeout); } static inline void iwl_trans_txq_set_shared_mode(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 815d2d141fd8..81c02d6e3d82 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -733,7 +733,8 @@ int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue, if (cmd.tid == IWL_MAX_TID_COUNT) cmd.tid = IWL_MGMT_TID; queue = iwl_trans_txq_alloc(mvm->trans, (void *)&cmd, - SCD_QUEUE_CFG, timeout); + SCD_QUEUE_CFG, IWL_DEFAULT_QUEUE_SIZE, + timeout); if (queue < 0) { IWL_DEBUG_TX_QUEUES(mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index a8833028e1cf..cda66340d357 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -819,7 +819,7 @@ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr); int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, struct iwl_tx_queue_cfg_cmd *cmd, - int cmd_id, + int cmd_id, int size, unsigned int timeout); void iwl_trans_pcie_dyn_txq_free(struct iwl_trans *trans, int queue); int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 7bdb9c9e04b1..b3d151ec8fe4 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -1041,7 +1041,7 @@ static void iwl_pcie_gen2_txq_free(struct iwl_trans *trans, int txq_id) int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, struct iwl_tx_queue_cfg_cmd *cmd, - int cmd_id, + int cmd_id, int size, unsigned int timeout) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); -- cgit v1.2.3 From 3cfb6de73df3bceaf1942297659177ac50267852 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 4 Jan 2018 14:02:51 +0200 Subject: iwlwifi: pcie: use the queue size as sent by opmode Op mode will begin tp use varying size of TX queue. All the infra is in place, allow it. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index b3d151ec8fe4..a235dda1f70b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -1067,12 +1067,12 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, return -ENOMEM; } - ret = iwl_pcie_txq_alloc(trans, txq, TFD_TX_CMD_SLOTS, false); + ret = iwl_pcie_txq_alloc(trans, txq, size, false); if (ret) { IWL_ERR(trans, "Tx queue alloc failed\n"); goto error; } - ret = iwl_pcie_txq_init(trans, txq, TFD_TX_CMD_SLOTS, false); + ret = iwl_pcie_txq_init(trans, txq, size, false); if (ret) { IWL_ERR(trans, "Tx queue init failed\n"); goto error; @@ -1082,7 +1082,7 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, cmd->tfdq_addr = cpu_to_le64(txq->dma_addr); cmd->byte_cnt_addr = cpu_to_le64(txq->bc_tbl.dma); - cmd->cb_size = cpu_to_le32(TFD_QUEUE_CB_SIZE(TFD_TX_CMD_SLOTS)); + cmd->cb_size = cpu_to_le32(TFD_QUEUE_CB_SIZE(size)); ret = iwl_trans_send_cmd(trans, &hcmd); if (ret) -- cgit v1.2.3 From 251985c92865bc68a0b17a6409a640914f3ab1ba Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 4 Jan 2018 14:06:07 +0200 Subject: iwlwifi: mvm: use shorter queues for mgmt and auxilary queues In 22000 devices, aka gen2, the TFS is 256 bytes. In order to save memory, use shorter TX queue for aux and mgmt queues, since there isn't much traffic on them. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/txq.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/txq.h b/drivers/net/wireless/intel/iwlwifi/fw/api/txq.h index 1f45b2ce5295..6ac240b6eace 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/txq.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/txq.h @@ -132,6 +132,7 @@ enum iwl_tx_queue_cfg_actions { }; #define IWL_DEFAULT_QUEUE_SIZE 256 +#define IWL_MGMT_QUEUE_SIZE 16 /** * struct iwl_tx_queue_cfg_cmd - txq hw scheduler config command * @sta_id: station id diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 81c02d6e3d82..e597bc193e5c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -728,13 +728,14 @@ int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue, .sta_id = sta_id, .tid = tid, }; - int queue; + int queue, size = IWL_DEFAULT_QUEUE_SIZE; - if (cmd.tid == IWL_MAX_TID_COUNT) + if (cmd.tid == IWL_MAX_TID_COUNT) { cmd.tid = IWL_MGMT_TID; + size = IWL_MGMT_QUEUE_SIZE; + } queue = iwl_trans_txq_alloc(mvm->trans, (void *)&cmd, - SCD_QUEUE_CFG, IWL_DEFAULT_QUEUE_SIZE, - timeout); + SCD_QUEUE_CFG, size, timeout); if (queue < 0) { IWL_DEBUG_TX_QUEUES(mvm, -- cgit v1.2.3 From 9c4f7d5127402294b50c9ff18fad66639f3b81d0 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Sun, 14 Jan 2018 19:06:09 +0200 Subject: iwlwifi: move all NVM parsing code to the common files Move all the NVM file handling code to iwl-nvm-parse.c where all this stuff belongs. This cleans up the MVM specific code and allows easier reuse by other opmodes if needed. Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 214 ++++++++++++++++++++- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h | 23 +++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 7 +- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 15 +- drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 208 +------------------- 5 files changed, 247 insertions(+), 220 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 8928613e033e..3437ed480e31 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -8,6 +8,7 @@ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -35,6 +36,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -68,6 +70,7 @@ #include #include #include +#include #include "iwl-drv.h" #include "iwl-modparams.h" @@ -76,6 +79,7 @@ #include "iwl-io.h" #include "iwl-csr.h" #include "fw/acpi.h" +#include "fw/api/nvm-reg.h" /* NVM offsets (in words) definitions */ enum nvm_offsets { @@ -146,8 +150,8 @@ static const u8 iwl_ext_nvm_channels[] = { 149, 153, 157, 161, 165, 169, 173, 177, 181 }; -#define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels) -#define IWL_NUM_CHANNELS_EXT ARRAY_SIZE(iwl_ext_nvm_channels) +#define IWL_NVM_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels) +#define IWL_NVM_NUM_CHANNELS_EXT ARRAY_SIZE(iwl_ext_nvm_channels) #define NUM_2GHZ_CHANNELS 14 #define NUM_2GHZ_CHANNELS_EXT 14 #define FIRST_2GHZ_HT_MINUS 5 @@ -301,11 +305,11 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, const u8 *nvm_chan; if (cfg->nvm_type != IWL_NVM_EXT) { - num_of_ch = IWL_NUM_CHANNELS; + num_of_ch = IWL_NVM_NUM_CHANNELS; nvm_chan = &iwl_nvm_channels[0]; num_2ghz_channels = NUM_2GHZ_CHANNELS; } else { - num_of_ch = IWL_NUM_CHANNELS_EXT; + num_of_ch = IWL_NVM_NUM_CHANNELS_EXT; nvm_chan = &iwl_ext_nvm_channels[0]; num_2ghz_channels = NUM_2GHZ_CHANNELS_EXT; } @@ -720,12 +724,12 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (cfg->nvm_type != IWL_NVM_EXT) data = kzalloc(sizeof(*data) + sizeof(struct ieee80211_channel) * - IWL_NUM_CHANNELS, + IWL_NVM_NUM_CHANNELS, GFP_KERNEL); else data = kzalloc(sizeof(*data) + sizeof(struct ieee80211_channel) * - IWL_NUM_CHANNELS_EXT, + IWL_NVM_NUM_CHANNELS_EXT, GFP_KERNEL); if (!data) return NULL; @@ -859,7 +863,7 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, int valid_rules = 0; bool new_rule; int max_num_ch = cfg->nvm_type == IWL_NVM_EXT ? - IWL_NUM_CHANNELS_EXT : IWL_NUM_CHANNELS; + IWL_NVM_NUM_CHANNELS_EXT : IWL_NVM_NUM_CHANNELS; if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES)) return ERR_PTR(-EINVAL); @@ -938,3 +942,199 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, return regd; } IWL_EXPORT_SYMBOL(iwl_parse_nvm_mcc_info); + +#define IWL_MAX_NVM_SECTION_SIZE 0x1b58 +#define IWL_MAX_EXT_NVM_SECTION_SIZE 0x1ffc +#define MAX_NVM_FILE_LEN 16384 + +void iwl_nvm_fixups(u32 hw_id, unsigned int section, u8 *data, + unsigned int len) +{ +#define IWL_4165_DEVICE_ID 0x5501 +#define NVM_SKU_CAP_MIMO_DISABLE BIT(5) + + if (section == NVM_SECTION_TYPE_PHY_SKU && + hw_id == IWL_4165_DEVICE_ID && data && len >= 5 && + (data[4] & NVM_SKU_CAP_MIMO_DISABLE)) + /* OTP 0x52 bug work around: it's a 1x1 device */ + data[3] = ANT_B | (ANT_B << 4); +} +IWL_EXPORT_SYMBOL(iwl_nvm_fixups); + +/* + * Reads external NVM from a file into mvm->nvm_sections + * + * HOW TO CREATE THE NVM FILE FORMAT: + * ------------------------------ + * 1. create hex file, format: + * 3800 -> header + * 0000 -> header + * 5a40 -> data + * + * rev - 6 bit (word1) + * len - 10 bit (word1) + * id - 4 bit (word2) + * rsv - 12 bit (word2) + * + * 2. flip 8bits with 8 bits per line to get the right NVM file format + * + * 3. create binary file from the hex file + * + * 4. save as "iNVM_xxx.bin" under /lib/firmware + */ +int iwl_read_external_nvm(struct iwl_trans *trans, + const char *nvm_file_name, + struct iwl_nvm_section *nvm_sections) +{ + int ret, section_size; + u16 section_id; + const struct firmware *fw_entry; + const struct { + __le16 word1; + __le16 word2; + u8 data[]; + } *file_sec; + const u8 *eof; + u8 *temp; + int max_section_size; + const __le32 *dword_buff; + +#define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) +#define NVM_WORD2_ID(x) (x >> 12) +#define EXT_NVM_WORD2_LEN(x) (2 * (((x) & 0xFF) << 8 | (x) >> 8)) +#define EXT_NVM_WORD1_ID(x) ((x) >> 4) +#define NVM_HEADER_0 (0x2A504C54) +#define NVM_HEADER_1 (0x4E564D2A) +#define NVM_HEADER_SIZE (4 * sizeof(u32)) + + IWL_DEBUG_EEPROM(trans->dev, "Read from external NVM\n"); + + /* Maximal size depends on NVM version */ + if (trans->cfg->nvm_type != IWL_NVM_EXT) + max_section_size = IWL_MAX_NVM_SECTION_SIZE; + else + max_section_size = IWL_MAX_EXT_NVM_SECTION_SIZE; + + /* + * Obtain NVM image via request_firmware. Since we already used + * request_firmware_nowait() for the firmware binary load and only + * get here after that we assume the NVM request can be satisfied + * synchronously. + */ + ret = request_firmware(&fw_entry, nvm_file_name, trans->dev); + if (ret) { + IWL_ERR(trans, "ERROR: %s isn't available %d\n", + nvm_file_name, ret); + return ret; + } + + IWL_INFO(trans, "Loaded NVM file %s (%zu bytes)\n", + nvm_file_name, fw_entry->size); + + if (fw_entry->size > MAX_NVM_FILE_LEN) { + IWL_ERR(trans, "NVM file too large\n"); + ret = -EINVAL; + goto out; + } + + eof = fw_entry->data + fw_entry->size; + dword_buff = (__le32 *)fw_entry->data; + + /* some NVM file will contain a header. + * The header is identified by 2 dwords header as follow: + * dword[0] = 0x2A504C54 + * dword[1] = 0x4E564D2A + * + * This header must be skipped when providing the NVM data to the FW. + */ + if (fw_entry->size > NVM_HEADER_SIZE && + dword_buff[0] == cpu_to_le32(NVM_HEADER_0) && + dword_buff[1] == cpu_to_le32(NVM_HEADER_1)) { + file_sec = (void *)(fw_entry->data + NVM_HEADER_SIZE); + IWL_INFO(trans, "NVM Version %08X\n", le32_to_cpu(dword_buff[2])); + IWL_INFO(trans, "NVM Manufacturing date %08X\n", + le32_to_cpu(dword_buff[3])); + + /* nvm file validation, dword_buff[2] holds the file version */ + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 && + CSR_HW_REV_STEP(trans->hw_rev) == SILICON_C_STEP && + le32_to_cpu(dword_buff[2]) < 0xE4A) { + ret = -EFAULT; + goto out; + } + } else { + file_sec = (void *)fw_entry->data; + } + + while (true) { + if (file_sec->data > eof) { + IWL_ERR(trans, + "ERROR - NVM file too short for section header\n"); + ret = -EINVAL; + break; + } + + /* check for EOF marker */ + if (!file_sec->word1 && !file_sec->word2) { + ret = 0; + break; + } + + if (trans->cfg->nvm_type != IWL_NVM_EXT) { + section_size = + 2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1)); + section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2)); + } else { + section_size = 2 * EXT_NVM_WORD2_LEN( + le16_to_cpu(file_sec->word2)); + section_id = EXT_NVM_WORD1_ID( + le16_to_cpu(file_sec->word1)); + } + + if (section_size > max_section_size) { + IWL_ERR(trans, "ERROR - section too large (%d)\n", + section_size); + ret = -EINVAL; + break; + } + + if (!section_size) { + IWL_ERR(trans, "ERROR - section empty\n"); + ret = -EINVAL; + break; + } + + if (file_sec->data + section_size > eof) { + IWL_ERR(trans, + "ERROR - NVM file too short for section (%d bytes)\n", + section_size); + ret = -EINVAL; + break; + } + + if (WARN(section_id >= NVM_MAX_NUM_SECTIONS, + "Invalid NVM section ID %d\n", section_id)) { + ret = -EINVAL; + break; + } + + temp = kmemdup(file_sec->data, section_size, GFP_KERNEL); + if (!temp) { + ret = -ENOMEM; + break; + } + + iwl_nvm_fixups(trans->hw_id, section_id, temp, section_size); + + kfree(nvm_sections[section_id].data); + nvm_sections[section_id].data = temp; + nvm_sections[section_id].length = section_size; + + /* advance to the next section */ + file_sec = (void *)(file_sec->data + section_size); + } +out: + release_firmware(fw_entry); + return ret; +} +IWL_EXPORT_SYMBOL(iwl_read_external_nvm); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h index 306736c7a042..6b108cae61b8 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h @@ -7,6 +7,7 @@ * * Copyright(c) 2008 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -109,4 +111,25 @@ struct ieee80211_regdomain * iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, int num_of_ch, __le32 *channels, u16 fw_mcc); +/** + * struct iwl_nvm_section - describes an NVM section in memory. + * + * This struct holds an NVM section read from the NIC using NVM_ACCESS_CMD, + * and saved for later use by the driver. Not all NVM sections are saved + * this way, only the needed ones. + */ +struct iwl_nvm_section { + u16 length; + const u8 *data; +}; + +/** + * iwl_read_external_nvm - Reads external NVM from a file into nvm_sections + */ +int iwl_read_external_nvm(struct iwl_trans *trans, + const char *nvm_file_name, + struct iwl_nvm_section *nvm_sections); +void iwl_nvm_fixups(u32 hw_id, unsigned int section, u8 *data, + unsigned int len); + #endif /* __iwl_nvm_parse_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 4cf3e32e3dba..d5a612add59f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -35,6 +36,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -79,6 +81,8 @@ #include "mvm.h" #include "fw/dbg.h" #include "iwl-phy-db.h" +#include "iwl-modparams.h" +#include "iwl-nvm-parse.h" #define MVM_UCODE_ALIVE_TIMEOUT HZ #define MVM_UCODE_CALIB_TIMEOUT (2*HZ) @@ -381,7 +385,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) /* Load NVM to NIC if needed */ if (mvm->nvm_file_name) { - iwl_mvm_read_external_nvm(mvm); + iwl_read_external_nvm(mvm->trans, mvm->nvm_file_name, + mvm->nvm_sections); iwl_mvm_load_nvm_to_nic(mvm); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 2411cc91f833..6a4ba160c59e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -92,7 +92,7 @@ #include "fw/runtime.h" #include "fw/dbg.h" #include "fw/acpi.h" -#include "fw/debugfs.h" +#include "iwl-nvm-parse.h" #include @@ -508,18 +508,6 @@ enum iwl_mvm_sched_scan_pass_all_states { SCHED_SCAN_PASS_ALL_FOUND, }; -/** - * struct iwl_nvm_section - describes an NVM section in memory. - * - * This struct holds an NVM section read from the NIC using NVM_ACCESS_CMD, - * and saved for later use by the driver. Not all NVM sections are saved - * this way, only the needed ones. - */ -struct iwl_nvm_section { - u16 length; - const u8 *data; -}; - /** * struct iwl_mvm_tt_mgnt - Thermal Throttling Management structure * @ct_kill_exit: worker to exit thermal kill @@ -1511,7 +1499,6 @@ void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm); /* NVM */ int iwl_nvm_init(struct iwl_mvm *mvm); int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm); -int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm); static inline u8 iwl_mvm_get_valid_tx_ant(struct iwl_mvm *mvm) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index 5bfe5306524c..cf48517944ec 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -35,6 +36,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -76,9 +78,7 @@ #include "fw/acpi.h" /* Default NVM size to read */ -#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024) -#define IWL_MAX_NVM_SECTION_SIZE 0x1b58 -#define IWL_MAX_EXT_NVM_SECTION_SIZE 0x1ffc +#define IWL_NVM_DEFAULT_CHUNK_SIZE (2 * 1024) #define NVM_WRITE_OPCODE 1 #define NVM_READ_OPCODE 0 @@ -229,19 +229,6 @@ static int iwl_nvm_write_section(struct iwl_mvm *mvm, u16 section, return 0; } -static void iwl_mvm_nvm_fixups(struct iwl_mvm *mvm, unsigned int section, - u8 *data, unsigned int len) -{ -#define IWL_4165_DEVICE_ID 0x5501 -#define NVM_SKU_CAP_MIMO_DISABLE BIT(5) - - if (section == NVM_SECTION_TYPE_PHY_SKU && - mvm->trans->hw_id == IWL_4165_DEVICE_ID && data && len >= 5 && - (data[4] & NVM_SKU_CAP_MIMO_DISABLE)) - /* OTP 0x52 bug work around: it's a 1x1 device */ - data[3] = ANT_B | (ANT_B << 4); -} - /* * Reads an NVM section completely. * NICs prior to 7000 family doesn't have a real NVM, but just read @@ -282,7 +269,7 @@ static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section, offset += ret; } - iwl_mvm_nvm_fixups(mvm, section, data, offset); + iwl_nvm_fixups(mvm->trans->hw_id, section, data, offset); IWL_DEBUG_EEPROM(mvm->trans->dev, "NVM section %d read completed\n", section); @@ -355,184 +342,6 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) lar_enabled); } -#define MAX_NVM_FILE_LEN 16384 - -/* - * Reads external NVM from a file into mvm->nvm_sections - * - * HOW TO CREATE THE NVM FILE FORMAT: - * ------------------------------ - * 1. create hex file, format: - * 3800 -> header - * 0000 -> header - * 5a40 -> data - * - * rev - 6 bit (word1) - * len - 10 bit (word1) - * id - 4 bit (word2) - * rsv - 12 bit (word2) - * - * 2. flip 8bits with 8 bits per line to get the right NVM file format - * - * 3. create binary file from the hex file - * - * 4. save as "iNVM_xxx.bin" under /lib/firmware - */ -int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) -{ - int ret, section_size; - u16 section_id; - const struct firmware *fw_entry; - const struct { - __le16 word1; - __le16 word2; - u8 data[]; - } *file_sec; - const u8 *eof; - u8 *temp; - int max_section_size; - const __le32 *dword_buff; - -#define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) -#define NVM_WORD2_ID(x) (x >> 12) -#define EXT_NVM_WORD2_LEN(x) (2 * (((x) & 0xFF) << 8 | (x) >> 8)) -#define EXT_NVM_WORD1_ID(x) ((x) >> 4) -#define NVM_HEADER_0 (0x2A504C54) -#define NVM_HEADER_1 (0x4E564D2A) -#define NVM_HEADER_SIZE (4 * sizeof(u32)) - - IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n"); - - /* Maximal size depends on NVM version */ - if (mvm->trans->cfg->nvm_type != IWL_NVM_EXT) - max_section_size = IWL_MAX_NVM_SECTION_SIZE; - else - max_section_size = IWL_MAX_EXT_NVM_SECTION_SIZE; - - /* - * Obtain NVM image via request_firmware. Since we already used - * request_firmware_nowait() for the firmware binary load and only - * get here after that we assume the NVM request can be satisfied - * synchronously. - */ - ret = request_firmware(&fw_entry, mvm->nvm_file_name, - mvm->trans->dev); - if (ret) { - IWL_ERR(mvm, "ERROR: %s isn't available %d\n", - mvm->nvm_file_name, ret); - return ret; - } - - IWL_INFO(mvm, "Loaded NVM file %s (%zu bytes)\n", - mvm->nvm_file_name, fw_entry->size); - - if (fw_entry->size > MAX_NVM_FILE_LEN) { - IWL_ERR(mvm, "NVM file too large\n"); - ret = -EINVAL; - goto out; - } - - eof = fw_entry->data + fw_entry->size; - dword_buff = (__le32 *)fw_entry->data; - - /* some NVM file will contain a header. - * The header is identified by 2 dwords header as follow: - * dword[0] = 0x2A504C54 - * dword[1] = 0x4E564D2A - * - * This header must be skipped when providing the NVM data to the FW. - */ - if (fw_entry->size > NVM_HEADER_SIZE && - dword_buff[0] == cpu_to_le32(NVM_HEADER_0) && - dword_buff[1] == cpu_to_le32(NVM_HEADER_1)) { - file_sec = (void *)(fw_entry->data + NVM_HEADER_SIZE); - IWL_INFO(mvm, "NVM Version %08X\n", le32_to_cpu(dword_buff[2])); - IWL_INFO(mvm, "NVM Manufacturing date %08X\n", - le32_to_cpu(dword_buff[3])); - - /* nvm file validation, dword_buff[2] holds the file version */ - if (mvm->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 && - CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_C_STEP && - le32_to_cpu(dword_buff[2]) < 0xE4A) { - ret = -EFAULT; - goto out; - } - } else { - file_sec = (void *)fw_entry->data; - } - - while (true) { - if (file_sec->data > eof) { - IWL_ERR(mvm, - "ERROR - NVM file too short for section header\n"); - ret = -EINVAL; - break; - } - - /* check for EOF marker */ - if (!file_sec->word1 && !file_sec->word2) { - ret = 0; - break; - } - - if (mvm->trans->cfg->nvm_type != IWL_NVM_EXT) { - section_size = - 2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1)); - section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2)); - } else { - section_size = 2 * EXT_NVM_WORD2_LEN( - le16_to_cpu(file_sec->word2)); - section_id = EXT_NVM_WORD1_ID( - le16_to_cpu(file_sec->word1)); - } - - if (section_size > max_section_size) { - IWL_ERR(mvm, "ERROR - section too large (%d)\n", - section_size); - ret = -EINVAL; - break; - } - - if (!section_size) { - IWL_ERR(mvm, "ERROR - section empty\n"); - ret = -EINVAL; - break; - } - - if (file_sec->data + section_size > eof) { - IWL_ERR(mvm, - "ERROR - NVM file too short for section (%d bytes)\n", - section_size); - ret = -EINVAL; - break; - } - - if (WARN(section_id >= NVM_MAX_NUM_SECTIONS, - "Invalid NVM section ID %d\n", section_id)) { - ret = -EINVAL; - break; - } - - temp = kmemdup(file_sec->data, section_size, GFP_KERNEL); - if (!temp) { - ret = -ENOMEM; - break; - } - - iwl_mvm_nvm_fixups(mvm, section_id, temp, section_size); - - kfree(mvm->nvm_sections[section_id].data); - mvm->nvm_sections[section_id].data = temp; - mvm->nvm_sections[section_id].length = section_size; - - /* advance to the next section */ - file_sec = (void *)(file_sec->data + section_size); - } -out: - release_firmware(fw_entry); - return ret; -} - /* Loads the NVM data stored in mvm->nvm_sections into the NIC */ int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm) { @@ -585,7 +394,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm) break; } - iwl_mvm_nvm_fixups(mvm, section, temp, ret); + iwl_nvm_fixups(mvm->trans->hw_id, section, temp, ret); mvm->nvm_sections[section].data = temp; mvm->nvm_sections[section].length = ret; @@ -624,14 +433,17 @@ int iwl_nvm_init(struct iwl_mvm *mvm) /* Only if PNVM selected in the mod param - load external NVM */ if (mvm->nvm_file_name) { /* read External NVM file from the mod param */ - ret = iwl_mvm_read_external_nvm(mvm); + ret = iwl_read_external_nvm(mvm->trans, mvm->nvm_file_name, + mvm->nvm_sections); if (ret) { mvm->nvm_file_name = nvm_file_C; if ((ret == -EFAULT || ret == -ENOENT) && mvm->nvm_file_name) { /* in case nvm file was failed try again */ - ret = iwl_mvm_read_external_nvm(mvm); + ret = iwl_read_external_nvm(mvm->trans, + mvm->nvm_file_name, + mvm->nvm_sections); if (ret) return ret; } else { -- cgit v1.2.3 From 8f66e064c9db418c6c3037aa2c217dc7b18f3276 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 17 Jan 2018 16:35:39 +0200 Subject: iwlwifi: mvm: use the new get_tid function This saves some typing and is overall more readable. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 7 +++---- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 11 ++++------- 2 files changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index f9cd7575b422..34791628cfb3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -112,7 +112,7 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb, return -1; if (ieee80211_is_data_qos(hdr->frame_control)) - tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; + tid = ieee80211_get_tid(hdr); else tid = 0; @@ -347,8 +347,7 @@ static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue, if (ieee80211_is_data_qos(hdr->frame_control)) /* frame has qos control */ - tid = *ieee80211_get_qos_ctl(hdr) & - IEEE80211_QOS_CTL_TID_MASK; + tid = ieee80211_get_tid(hdr); else tid = IWL_MAX_TID_COUNT; @@ -628,7 +627,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, bool amsdu = desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU; bool last_subframe = desc->amsdu_info & IWL_RX_MPDU_AMSDU_LAST_SUBFRAME; - u8 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; + u8 tid = ieee80211_get_tid(hdr); u8 sub_frame_idx = desc->amsdu_info & IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK; struct iwl_mvm_reorder_buf_entry *entries; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 90381348697c..d0916f2552e2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -767,7 +767,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, u16 snap_ip_tcp, pad; unsigned int dbg_max_amsdu_len; netdev_features_t netdev_flags = NETIF_F_CSUM_MASK | NETIF_F_SG; - u8 *qc, tid, txf; + u8 tid, txf; snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) + tcp_hdrlen(skb); @@ -790,8 +790,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb); } - qc = ieee80211_get_qos_ctl(hdr); - tid = *qc & IEEE80211_QOS_CTL_TID_MASK; + tid = ieee80211_get_tid(hdr); if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) return -EINVAL; @@ -846,7 +845,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, */ num_subframes = (max_amsdu_len + pad) / (subf_len + pad); if (num_subframes > 1) - *qc |= IEEE80211_QOS_CTL_A_MSDU_PRESENT; + *ieee80211_get_qos_ctl(hdr) |= IEEE80211_QOS_CTL_A_MSDU_PRESENT; tcp_payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) - tcp_hdrlen(skb) + skb->data_len; @@ -1007,9 +1006,7 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, * assignment of MGMT TID */ if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) { - u8 *qc = NULL; - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + tid = ieee80211_get_tid(hdr); if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) goto drop_unlock_sta; -- cgit v1.2.3 From 3506832b098850a8aafee19512e79c33debab380 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Sun, 28 Jan 2018 18:27:52 +0200 Subject: iwlwifi: pcie: gen2: fix race in cmd fifo write ptr Avoid a race where two (or more) commands get the same index: 1. T1 calls enqueue_hcmd and the local TFD index is assigned to txq->write_ptr; 2. Context switch 'before incrementing txq->write_ptr'; 3. T2 calls enqueue_hcmd and the local TFD index is assigned to txq->write_ptr; 4. Now the index is set to the same value for both commands of T1 and T2. To prevent this from happening, set the local TFD index inside the critical section (the index is set by global txq write pointer). Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index a235dda1f70b..48890a1c825f 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -569,15 +569,13 @@ static int iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans, unsigned long flags; void *dup_buf = NULL; dma_addr_t phys_addr; - int i, cmd_pos, idx = iwl_pcie_get_cmd_index(txq, txq->write_ptr); + int i, cmd_pos, idx; u16 copy_size, cmd_size, tb0_size; bool had_nocopy = false; u8 group_id = iwl_cmd_groupid(cmd->id); const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD]; u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD]; - struct iwl_tfh_tfd *tfd = iwl_pcie_get_tfd(trans, txq, txq->write_ptr); - - memset(tfd, 0, sizeof(*tfd)); + struct iwl_tfh_tfd *tfd; copy_size = sizeof(struct iwl_cmd_header_wide); cmd_size = sizeof(struct iwl_cmd_header_wide); @@ -648,6 +646,10 @@ static int iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans, spin_lock_bh(&txq->lock); + idx = iwl_pcie_get_cmd_index(txq, txq->write_ptr); + tfd = iwl_pcie_get_tfd(trans, txq, txq->write_ptr); + memset(tfd, 0, sizeof(*tfd)); + if (iwl_queue_space(txq) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { spin_unlock_bh(&txq->lock); -- cgit v1.2.3 From 4883145a8e17fd0c232a80dbc212eaebf57b061d Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 29 Jan 2018 10:00:05 +0200 Subject: iwlwifi: mvm: set the MFP flag for keys that are used by MFP stations 22000 devices rely on this flag to install the key to the right queues. For earlier devices we didn't have a key / queue mapping and the key was sent along with the Tx command for each Tx hence the problem didn't arise. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 80067eb9ea05..4f9d3e13d7e5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -2887,7 +2888,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, u32 sta_id, struct ieee80211_key_conf *key, bool mcast, u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags, - u8 key_offset) + u8 key_offset, bool mfp) { union { struct iwl_mvm_add_sta_key_cmd_v1 cmd_v1; @@ -2960,6 +2961,8 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, if (mcast) key_flags |= cpu_to_le16(STA_KEY_MULTICAST); + if (mfp) + key_flags |= cpu_to_le16(STA_KEY_MFP); u.cmd.common.key_offset = key_offset; u.cmd.common.key_flags = key_flags; @@ -3101,11 +3104,13 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, struct ieee80211_key_seq seq; u16 p1k[5]; u32 sta_id; + bool mfp = false; if (sta) { struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); sta_id = mvm_sta->sta_id; + mfp = sta->mfp; } else if (vif->type == NL80211_IFTYPE_AP && !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -3127,7 +3132,8 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, ieee80211_get_key_rx_seq(keyconf, 0, &seq); ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); ret = iwl_mvm_send_sta_key(mvm, sta_id, keyconf, mcast, - seq.tkip.iv32, p1k, 0, key_offset); + seq.tkip.iv32, p1k, 0, key_offset, + mfp); break; case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_WEP40: @@ -3135,11 +3141,11 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: ret = iwl_mvm_send_sta_key(mvm, sta_id, keyconf, mcast, - 0, NULL, 0, key_offset); + 0, NULL, 0, key_offset, mfp); break; default: ret = iwl_mvm_send_sta_key(mvm, sta_id, keyconf, mcast, - 0, NULL, 0, key_offset); + 0, NULL, 0, key_offset, mfp); } return ret; @@ -3366,6 +3372,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, { struct iwl_mvm_sta *mvm_sta; bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); + bool mfp = sta ? sta->mfp : false; rcu_read_lock(); @@ -3373,7 +3380,8 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, if (WARN_ON_ONCE(!mvm_sta)) goto unlock; iwl_mvm_send_sta_key(mvm, mvm_sta->sta_id, keyconf, mcast, - iv32, phase1key, CMD_ASYNC, keyconf->hw_key_idx); + iv32, phase1key, CMD_ASYNC, keyconf->hw_key_idx, + mfp); unlock: rcu_read_unlock(); -- cgit v1.2.3 From 2c2b4bbc5d1f5c37e16d108f7a0c4e2a36c4f423 Mon Sep 17 00:00:00 2001 From: Naftali Goldstein Date: Mon, 15 Jan 2018 12:32:30 +0200 Subject: iwlwifi: mvm: update rs-fw API Update rs-fw API to match changes in FW. Specifically, the TLC_MNG_NOTIF_REQ_CMD command and TLC_MNG_AMSDU_ENABLE_NOTIF notification are removed, the A-MSDU related info is received from FW via the TLC_MNG_UPDATE_NOTIF, and the TLC_MNG_CONFIG_CMD uses version 2 of its data structure. Additionally, constify some arguments in a couple of functions. Signed-off-by: Naftali Goldstein Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/datapath.h | 10 -- drivers/net/wireless/intel/iwlwifi/fw/api/rs.h | 168 +++++++-------------- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 2 + drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 3 - drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 143 +++++++----------- drivers/net/wireless/intel/iwlwifi/mvm/rs.h | 2 - drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 4 +- 7 files changed, 114 insertions(+), 218 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h index 184cee98c359..5f6e855006dd 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -87,16 +87,6 @@ enum iwl_data_path_subcmd_ids { */ TLC_MNG_CONFIG_CMD = 0xF, - /** - * @TLC_MNG_NOTIF_REQ_CMD: &struct iwl_tlc_notif_req_config_cmd - */ - TLC_MNG_NOTIF_REQ_CMD = 0x10, - - /** - * @TLC_MNG_AMSDU_ENABLE_NOTIF: &struct iwl_tlc_amsdu_notif - */ - TLC_MNG_AMSDU_ENABLE_NOTIF = 0xF6, - /** * @TLC_MNG_UPDATE_NOTIF: &struct iwl_tlc_update_notif */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h index 1a8f3154a1fe..21e13a315421 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -28,6 +29,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -64,62 +66,38 @@ /** * enum iwl_tlc_mng_cfg_flags_enum - options for TLC config flags - * @IWL_TLC_MNG_CFG_FLAGS_CCK_MSK: CCK support - * @IWL_TLC_MNG_CFG_FLAGS_DD_MSK: enable DD * @IWL_TLC_MNG_CFG_FLAGS_STBC_MSK: enable STBC * @IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK: enable LDPC - * @IWL_TLC_MNG_CFG_FLAGS_BF_MSK: enable BFER - * @IWL_TLC_MNG_CFG_FLAGS_DCM_MSK: enable DCM */ enum iwl_tlc_mng_cfg_flags { - IWL_TLC_MNG_CFG_FLAGS_CCK_MSK = BIT(0), - IWL_TLC_MNG_CFG_FLAGS_DD_MSK = BIT(1), - IWL_TLC_MNG_CFG_FLAGS_STBC_MSK = BIT(2), - IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK = BIT(3), - IWL_TLC_MNG_CFG_FLAGS_BF_MSK = BIT(4), - IWL_TLC_MNG_CFG_FLAGS_DCM_MSK = BIT(5), + IWL_TLC_MNG_CFG_FLAGS_STBC_MSK = BIT(0), + IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK = BIT(1), }; /** * enum iwl_tlc_mng_cfg_cw - channel width options - * @IWL_TLC_MNG_MAX_CH_WIDTH_20MHZ: 20MHZ channel - * @IWL_TLC_MNG_MAX_CH_WIDTH_40MHZ: 40MHZ channel - * @IWL_TLC_MNG_MAX_CH_WIDTH_80MHZ: 80MHZ channel - * @IWL_TLC_MNG_MAX_CH_WIDTH_160MHZ: 160MHZ channel - * @IWL_TLC_MNG_MAX_CH_WIDTH_LAST: maximum value + * @IWL_TLC_MNG_CH_WIDTH_20MHZ: 20MHZ channel + * @IWL_TLC_MNG_CH_WIDTH_40MHZ: 40MHZ channel + * @IWL_TLC_MNG_CH_WIDTH_80MHZ: 80MHZ channel + * @IWL_TLC_MNG_CH_WIDTH_160MHZ: 160MHZ channel + * @IWL_TLC_MNG_CH_WIDTH_LAST: maximum value */ enum iwl_tlc_mng_cfg_cw { - IWL_TLC_MNG_MAX_CH_WIDTH_20MHZ, - IWL_TLC_MNG_MAX_CH_WIDTH_40MHZ, - IWL_TLC_MNG_MAX_CH_WIDTH_80MHZ, - IWL_TLC_MNG_MAX_CH_WIDTH_160MHZ, - IWL_TLC_MNG_MAX_CH_WIDTH_LAST = IWL_TLC_MNG_MAX_CH_WIDTH_160MHZ, + IWL_TLC_MNG_CH_WIDTH_20MHZ, + IWL_TLC_MNG_CH_WIDTH_40MHZ, + IWL_TLC_MNG_CH_WIDTH_80MHZ, + IWL_TLC_MNG_CH_WIDTH_160MHZ, + IWL_TLC_MNG_CH_WIDTH_LAST = IWL_TLC_MNG_CH_WIDTH_160MHZ, }; /** * enum iwl_tlc_mng_cfg_chains - possible chains * @IWL_TLC_MNG_CHAIN_A_MSK: chain A * @IWL_TLC_MNG_CHAIN_B_MSK: chain B - * @IWL_TLC_MNG_CHAIN_C_MSK: chain C */ enum iwl_tlc_mng_cfg_chains { IWL_TLC_MNG_CHAIN_A_MSK = BIT(0), IWL_TLC_MNG_CHAIN_B_MSK = BIT(1), - IWL_TLC_MNG_CHAIN_C_MSK = BIT(2), -}; - -/** - * enum iwl_tlc_mng_cfg_gi - guard interval options - * @IWL_TLC_MNG_SGI_20MHZ_MSK: enable short GI for 20MHZ - * @IWL_TLC_MNG_SGI_40MHZ_MSK: enable short GI for 40MHZ - * @IWL_TLC_MNG_SGI_80MHZ_MSK: enable short GI for 80MHZ - * @IWL_TLC_MNG_SGI_160MHZ_MSK: enable short GI for 160MHZ - */ -enum iwl_tlc_mng_cfg_gi { - IWL_TLC_MNG_SGI_20MHZ_MSK = BIT(0), - IWL_TLC_MNG_SGI_40MHZ_MSK = BIT(1), - IWL_TLC_MNG_SGI_80MHZ_MSK = BIT(2), - IWL_TLC_MNG_SGI_160MHZ_MSK = BIT(3), }; /** @@ -145,25 +123,7 @@ enum iwl_tlc_mng_cfg_mode { }; /** - * enum iwl_tlc_mng_vht_he_types - VHT HE types - * @IWL_TLC_MNG_VALID_VHT_HE_TYPES_SU: VHT HT single user - * @IWL_TLC_MNG_VALID_VHT_HE_TYPES_SU_EXT: VHT HT single user extended - * @IWL_TLC_MNG_VALID_VHT_HE_TYPES_MU: VHT HT multiple users - * @IWL_TLC_MNG_VALID_VHT_HE_TYPES_TRIG_BASED: trigger based - * @IWL_TLC_MNG_VALID_VHT_HE_TYPES_NUM: a count of possible types - */ -enum iwl_tlc_mng_vht_he_types { - IWL_TLC_MNG_VALID_VHT_HE_TYPES_SU = 0, - IWL_TLC_MNG_VALID_VHT_HE_TYPES_SU_EXT, - IWL_TLC_MNG_VALID_VHT_HE_TYPES_MU, - IWL_TLC_MNG_VALID_VHT_HE_TYPES_TRIG_BASED, - IWL_TLC_MNG_VALID_VHT_HE_TYPES_NUM = - IWL_TLC_MNG_VALID_VHT_HE_TYPES_TRIG_BASED, - -}; - -/** - * enum iwl_tlc_mng_ht_rates - HT/VHT rates + * enum iwl_tlc_mng_ht_rates - HT/VHT/HE rates * @IWL_TLC_MNG_HT_RATE_MCS0: index of MCS0 * @IWL_TLC_MNG_HT_RATE_MCS1: index of MCS1 * @IWL_TLC_MNG_HT_RATE_MCS2: index of MCS2 @@ -174,6 +134,8 @@ enum iwl_tlc_mng_vht_he_types { * @IWL_TLC_MNG_HT_RATE_MCS7: index of MCS7 * @IWL_TLC_MNG_HT_RATE_MCS8: index of MCS8 * @IWL_TLC_MNG_HT_RATE_MCS9: index of MCS9 + * @IWL_TLC_MNG_HT_RATE_MCS10: index of MCS10 + * @IWL_TLC_MNG_HT_RATE_MCS11: index of MCS11 * @IWL_TLC_MNG_HT_RATE_MAX: maximal rate for HT/VHT */ enum iwl_tlc_mng_ht_rates { @@ -187,95 +149,73 @@ enum iwl_tlc_mng_ht_rates { IWL_TLC_MNG_HT_RATE_MCS7, IWL_TLC_MNG_HT_RATE_MCS8, IWL_TLC_MNG_HT_RATE_MCS9, - IWL_TLC_MNG_HT_RATE_MAX = IWL_TLC_MNG_HT_RATE_MCS9, + IWL_TLC_MNG_HT_RATE_MCS10, + IWL_TLC_MNG_HT_RATE_MCS11, + IWL_TLC_MNG_HT_RATE_MAX = IWL_TLC_MNG_HT_RATE_MCS11, }; /* Maximum supported tx antennas number */ -#define MAX_RS_ANT_NUM 3 +#define MAX_NSS 2 /** * struct tlc_config_cmd - TLC configuration * @sta_id: station id * @reserved1: reserved - * @max_supp_ch_width: channel width - * @flags: bitmask of &enum iwl_tlc_mng_cfg_flags - * @chains: bitmask of &enum iwl_tlc_mng_cfg_chains - * @max_supp_ss: valid values are 0-3, 0 - spatial streams are not supported - * @valid_vht_he_types: bitmap of &enum iwl_tlc_mng_vht_he_types - * @non_ht_supp_rates: bitmap of supported legacy rates - * @ht_supp_rates: bitmap of supported HT/VHT rates, valid bits are 0-9 + * @max_ch_width: max supported channel width from @enum iwl_tlc_mng_cfg_cw * @mode: &enum iwl_tlc_mng_cfg_mode + * @chains: bitmask of &enum iwl_tlc_mng_cfg_chains * @amsdu: TX amsdu is supported - * @he_supp_rates: bitmap of supported HE rates + * @flags: bitmask of &enum iwl_tlc_mng_cfg_flags + * @non_ht_rates: bitmap of supported legacy rates + * @ht_rates: bitmap of &enum iwl_tlc_mng_ht_rates, per + * pair (0 - 80mhz width and below, 1 - 160mhz). + * @max_mpdu_len: max MPDU length, in bytes * @sgi_ch_width_supp: bitmap of SGI support per channel width - * @he_gi_support: 11ax HE guard interval - * @max_ampdu_cnt: max AMPDU size (frames count) + * use BIT(@enum iwl_tlc_mng_cfg_cw) + * @reserved2: reserved */ struct iwl_tlc_config_cmd { u8 sta_id; u8 reserved1[3]; - u8 max_supp_ch_width; - u8 chains; - u8 max_supp_ss; - u8 valid_vht_he_types; - __le16 flags; - __le16 non_ht_supp_rates; - __le16 ht_supp_rates[MAX_RS_ANT_NUM]; + u8 max_ch_width; u8 mode; + u8 chains; u8 amsdu; - __le16 he_supp_rates; + __le16 flags; + __le16 non_ht_rates; + __le16 ht_rates[MAX_NSS][2]; + __le16 max_mpdu_len; u8 sgi_ch_width_supp; - u8 he_gi_support; - __le32 max_ampdu_cnt; -} __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_1 */ - -/** - * struct iwl_tlc_amsdu_notif - TLC AMSDU configuration - * @sta_id: station id - * @reserved: reserved - * @amsdu_size: Max AMSDU size, in bytes - * @amsdu_enabled: bitmap for per-TID AMSDU enablement - */ -struct iwl_tlc_amsdu_notif { - u8 sta_id; - u8 reserved[3]; - __le16 amsdu_size; - __le16 amsdu_enabled; -} __packed; /* TLC_MNG_AMSDU_ENABLE_NTFY_API_S_VER_1 */ - -#define IWL_TLC_NOTIF_INIT_RATE_POS 0 -#define IWL_TLC_NOTIF_INIT_RATE_MSK BIT(IWL_TLC_NOTIF_INIT_RATE_POS) -#define IWL_TLC_NOTIF_REQ_INTERVAL (500) + u8 reserved2[1]; +} __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_2 */ /** - * struct iwl_tlc_notif_req_config_cmd - request notif on specific changes - * @sta_id: relevant station - * @reserved1: reserved - * @flags: bitmap of requested notifications %IWL_TLC_NOTIF_INIT_\* - * @interval: minimum time between notifications from TLC to the driver (msec) - * @reserved2: reserved + * enum iwl_tlc_update_flags - updated fields + * @IWL_TLC_NOTIF_FLAG_RATE: last initial rate update + * @IWL_TLC_NOTIF_FLAG_AMSDU: umsdu parameters update */ -struct iwl_tlc_notif_req_config_cmd { - u8 sta_id; - u8 reserved1; - __le16 flags; - __le16 interval; - __le16 reserved2; -} __packed; /* TLC_MNG_NOTIF_REQ_CMD_API_S_VER_1 */ +enum iwl_tlc_update_flags { + IWL_TLC_NOTIF_FLAG_RATE = BIT(0), + IWL_TLC_NOTIF_FLAG_AMSDU = BIT(1), +}; /** * struct iwl_tlc_update_notif - TLC notification from FW * @sta_id: station id * @reserved: reserved * @flags: bitmap of notifications reported - * @values: field per flag in struct iwl_tlc_notif_req_config_cmd + * @rate: current initial rate + * @amsdu_size: Max AMSDU size, in bytes + * @amsdu_enabled: bitmap for per-TID AMSDU enablement */ struct iwl_tlc_update_notif { u8 sta_id; - u8 reserved; - __le16 flags; - __le32 values[16]; -} __packed; /* TLC_MNG_UPDATE_NTFY_API_S_VER_1 */ + u8 reserved[3]; + __le32 flags; + __le32 rate; + __le32 amsdu_size; + __le32 amsdu_enabled; +} __packed; /* TLC_MNG_UPDATE_NTFY_API_S_VER_2 */ /** * enum iwl_tlc_debug_flags - debug options diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 687bed30c851..14e69e7a2287 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -151,6 +151,8 @@ enum iwl_nvm_type { #define ANT_AC (ANT_A | ANT_C) #define ANT_BC (ANT_B | ANT_C) #define ANT_ABC (ANT_A | ANT_B | ANT_C) +#define MAX_ANT_NUM 3 + static inline u8 num_of_ant(u8 mask) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 1ef4ac21f32a..de46e6258a5c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -312,8 +312,6 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { iwl_mvm_mu_mimo_grp_notif, RX_HANDLER_SYNC), RX_HANDLER_GRP(DATA_PATH_GROUP, STA_PM_NOTIF, iwl_mvm_sta_pm_notif, RX_HANDLER_SYNC), - RX_HANDLER_GRP(DATA_PATH_GROUP, TLC_MNG_AMSDU_ENABLE_NOTIF, - iwl_mvm_tlc_amsdu_notif, RX_HANDLER_SYNC), }; #undef RX_HANDLER #undef RX_HANDLER_GRP @@ -450,7 +448,6 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = { HCMD_NAME(DQA_ENABLE_CMD), HCMD_NAME(UPDATE_MU_GROUPS_CMD), HCMD_NAME(TRIGGER_RX_QUEUES_NOTIF_CMD), - HCMD_NAME(TLC_MNG_AMSDU_ENABLE_NOTIF), HCMD_NAME(STA_PM_NOTIF), HCMD_NAME(MU_GROUP_MGMT_NOTIF), HCMD_NAME(RX_QUEUES_NOTIFICATION), diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 4e818bce469b..b8b2b819e8e7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -26,6 +27,7 @@ * BSD LICENSE * * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -65,14 +67,14 @@ static u8 rs_fw_bw_from_sta_bw(struct ieee80211_sta *sta) { switch (sta->bandwidth) { case IEEE80211_STA_RX_BW_160: - return IWL_TLC_MNG_MAX_CH_WIDTH_160MHZ; + return IWL_TLC_MNG_CH_WIDTH_160MHZ; case IEEE80211_STA_RX_BW_80: - return IWL_TLC_MNG_MAX_CH_WIDTH_80MHZ; + return IWL_TLC_MNG_CH_WIDTH_80MHZ; case IEEE80211_STA_RX_BW_40: - return IWL_TLC_MNG_MAX_CH_WIDTH_40MHZ; + return IWL_TLC_MNG_CH_WIDTH_40MHZ; case IEEE80211_STA_RX_BW_20: default: - return IWL_TLC_MNG_MAX_CH_WIDTH_20MHZ; + return IWL_TLC_MNG_CH_WIDTH_20MHZ; } } @@ -85,7 +87,9 @@ static u8 rs_fw_set_active_chains(u8 chains) if (chains & ANT_B) fw_chains |= IWL_TLC_MNG_CHAIN_B_MSK; if (chains & ANT_C) - fw_chains |= IWL_TLC_MNG_CHAIN_C_MSK; + WARN(false, + "tlc offload doesn't support antenna C. chains: 0x%x\n", + chains); return fw_chains; } @@ -97,13 +101,13 @@ static u8 rs_fw_sgi_cw_support(struct ieee80211_sta *sta) u8 supp = 0; if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20) - supp |= IWL_TLC_MNG_SGI_20MHZ_MSK; + supp |= BIT(IWL_TLC_MNG_CH_WIDTH_20MHZ); if (ht_cap->cap & IEEE80211_HT_CAP_SGI_40) - supp |= IWL_TLC_MNG_SGI_40MHZ_MSK; + supp |= BIT(IWL_TLC_MNG_CH_WIDTH_40MHZ); if (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80) - supp |= IWL_TLC_MNG_SGI_80MHZ_MSK; + supp |= BIT(IWL_TLC_MNG_CH_WIDTH_80MHZ); if (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_160) - supp |= IWL_TLC_MNG_SGI_160MHZ_MSK; + supp |= BIT(IWL_TLC_MNG_CH_WIDTH_160MHZ); return supp; } @@ -114,9 +118,7 @@ static u16 rs_fw_set_config_flags(struct iwl_mvm *mvm, struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; bool vht_ena = vht_cap && vht_cap->vht_supported; - u16 flags = IWL_TLC_MNG_CFG_FLAGS_CCK_MSK | - IWL_TLC_MNG_CFG_FLAGS_DCM_MSK | - IWL_TLC_MNG_CFG_FLAGS_DD_MSK; + u16 flags = 0; if (mvm->cfg->ht_params->stbc && (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && @@ -129,16 +131,11 @@ static u16 rs_fw_set_config_flags(struct iwl_mvm *mvm, (vht_ena && (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC)))) flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK; - if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BEAMFORMER) && - (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && - (vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)) - flags |= IWL_TLC_MNG_CFG_FLAGS_BF_MSK; - return flags; } static -int rs_fw_vht_highest_rx_mcs_index(struct ieee80211_sta_vht_cap *vht_cap, +int rs_fw_vht_highest_rx_mcs_index(const struct ieee80211_sta_vht_cap *vht_cap, int nss) { u16 rx_mcs = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map) & @@ -160,15 +157,16 @@ int rs_fw_vht_highest_rx_mcs_index(struct ieee80211_sta_vht_cap *vht_cap, return 0; } -static void rs_fw_vht_set_enabled_rates(struct ieee80211_sta *sta, - struct ieee80211_sta_vht_cap *vht_cap, - struct iwl_tlc_config_cmd *cmd) +static void +rs_fw_vht_set_enabled_rates(const struct ieee80211_sta *sta, + const struct ieee80211_sta_vht_cap *vht_cap, + struct iwl_tlc_config_cmd *cmd) { u16 supp; int i, highest_mcs; for (i = 0; i < sta->rx_nss; i++) { - if (i == MAX_RS_ANT_NUM) + if (i == MAX_NSS) break; highest_mcs = rs_fw_vht_highest_rx_mcs_index(vht_cap, i + 1); @@ -179,7 +177,9 @@ static void rs_fw_vht_set_enabled_rates(struct ieee80211_sta *sta, if (sta->bandwidth == IEEE80211_STA_RX_BW_20) supp &= ~BIT(IWL_TLC_MNG_HT_RATE_MCS9); - cmd->ht_supp_rates[i] = cpu_to_le16(supp); + cmd->ht_rates[i][0] = cpu_to_le16(supp); + if (sta->bandwidth == IEEE80211_STA_RX_BW_160) + cmd->ht_rates[i][1] = cmd->ht_rates[i][0]; } } @@ -190,8 +190,8 @@ static void rs_fw_set_supp_rates(struct ieee80211_sta *sta, int i; unsigned long tmp; unsigned long supp; /* must be unsigned long for for_each_set_bit */ - struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; - struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; + const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; + const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; /* non HT rates */ supp = 0; @@ -199,99 +199,71 @@ static void rs_fw_set_supp_rates(struct ieee80211_sta *sta, for_each_set_bit(i, &tmp, BITS_PER_LONG) supp |= BIT(sband->bitrates[i].hw_value); - cmd->non_ht_supp_rates = cpu_to_le16(supp); + cmd->non_ht_rates = cpu_to_le16(supp); cmd->mode = IWL_TLC_MNG_MODE_NON_HT; - /* HT/VHT rates */ if (vht_cap && vht_cap->vht_supported) { cmd->mode = IWL_TLC_MNG_MODE_VHT; rs_fw_vht_set_enabled_rates(sta, vht_cap, cmd); } else if (ht_cap && ht_cap->ht_supported) { cmd->mode = IWL_TLC_MNG_MODE_HT; - cmd->ht_supp_rates[0] = cpu_to_le16(ht_cap->mcs.rx_mask[0]); - cmd->ht_supp_rates[1] = cpu_to_le16(ht_cap->mcs.rx_mask[1]); + cmd->ht_rates[0][0] = cpu_to_le16(ht_cap->mcs.rx_mask[0]); + cmd->ht_rates[1][0] = cpu_to_le16(ht_cap->mcs.rx_mask[1]); } } -static void rs_fw_tlc_mng_notif_req_config(struct iwl_mvm *mvm, u8 sta_id) -{ - u32 cmd_id = iwl_cmd_id(TLC_MNG_NOTIF_REQ_CMD, DATA_PATH_GROUP, 0); - struct iwl_tlc_notif_req_config_cmd cfg_cmd = { - .sta_id = sta_id, - .flags = cpu_to_le16(IWL_TLC_NOTIF_INIT_RATE_MSK), - .interval = cpu_to_le16(IWL_TLC_NOTIF_REQ_INTERVAL), - }; - int ret; - - ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cfg_cmd), &cfg_cmd); - if (ret) - IWL_ERR(mvm, "Failed to send TLC notif request (%d)\n", ret); -} - -void iwl_mvm_tlc_amsdu_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) +void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_tlc_amsdu_notif *notif; + struct iwl_tlc_update_notif *notif; struct ieee80211_sta *sta; struct iwl_mvm_sta *mvmsta; - u16 size; - - notif = (void *)pkt->data; - - if (WARN_ON(notif->sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id))) - return; + struct iwl_lq_sta_rs_fw *lq_sta; + u32 flags; rcu_read_lock(); + notif = (void *)pkt->data; sta = rcu_dereference(mvm->fw_id_to_mac_id[notif->sta_id]); if (IS_ERR_OR_NULL(sta)) { - rcu_read_unlock(); IWL_ERR(mvm, "Invalid sta id (%d) in FW TLC notification\n", notif->sta_id); - return; + goto out; } mvmsta = iwl_mvm_sta_from_mac80211(sta); - size = min(le16_to_cpu(notif->amsdu_size), sta->max_amsdu_len); - mvmsta->amsdu_enabled = le16_to_cpu(notif->amsdu_enabled); - mvmsta->max_amsdu_len = size; - - IWL_DEBUG_RATE(mvm, - "AMSDU notification. AMSDU size: %d, AMSDU selected size: %d, AMSDU TID bitmap 0x%X\n", - le16_to_cpu(notif->amsdu_size), size, - mvmsta->amsdu_enabled); - - rcu_read_unlock(); -}; - -void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_tlc_update_notif *notif; - struct iwl_mvm_sta *mvmsta; - struct iwl_lq_sta_rs_fw *lq_sta; - - rcu_read_lock(); - - notif = (void *)pkt->data; - mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, notif->sta_id); - if (!mvmsta) { IWL_ERR(mvm, "Invalid sta id (%d) in FW TLC notification\n", notif->sta_id); goto out; } + flags = le32_to_cpu(notif->flags); + lq_sta = &mvmsta->lq_sta.rs_fw; - if (le16_to_cpu(notif->flags) & IWL_TLC_NOTIF_INIT_RATE_MSK) { - lq_sta->last_rate_n_flags = - le32_to_cpu(notif->values[IWL_TLC_NOTIF_INIT_RATE_POS]); + if (flags & IWL_TLC_NOTIF_FLAG_RATE) { + lq_sta->last_rate_n_flags = le32_to_cpu(notif->rate); IWL_DEBUG_RATE(mvm, "new rate_n_flags: 0x%X\n", lq_sta->last_rate_n_flags); } + + if (flags & IWL_TLC_NOTIF_FLAG_AMSDU) { + u16 size = le32_to_cpu(notif->amsdu_size); + + if (WARN_ON(sta->max_amsdu_len < size)) + goto out; + + mvmsta->amsdu_enabled = le32_to_cpu(notif->amsdu_enabled); + mvmsta->max_amsdu_len = size; + + IWL_DEBUG_RATE(mvm, + "AMSDU update. AMSDU size: %d, AMSDU selected size: %d, AMSDU TID bitmap 0x%X\n", + le32_to_cpu(notif->amsdu_size), size, + mvmsta->amsdu_enabled); + } out: rcu_read_unlock(); } @@ -306,11 +278,10 @@ void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct ieee80211_supported_band *sband; struct iwl_tlc_config_cmd cfg_cmd = { .sta_id = mvmsta->sta_id, - .max_supp_ch_width = rs_fw_bw_from_sta_bw(sta), + .max_ch_width = rs_fw_bw_from_sta_bw(sta), .flags = cpu_to_le16(rs_fw_set_config_flags(mvm, sta)), .chains = rs_fw_set_active_chains(iwl_mvm_get_valid_tx_ant(mvm)), - .max_supp_ss = sta->rx_nss, - .max_ampdu_cnt = cpu_to_le32(mvmsta->max_agg_bufsize), + .max_mpdu_len = cpu_to_le16(sta->max_amsdu_len), .sgi_ch_width_supp = rs_fw_sgi_cw_support(sta), .amsdu = iwl_mvm_is_csum_supported(mvm), }; @@ -327,8 +298,6 @@ void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cfg_cmd), &cfg_cmd); if (ret) IWL_ERR(mvm, "Failed to send rate scale config (%d)\n", ret); - - rs_fw_tlc_mng_notif_req_config(mvm, cfg_cmd.sta_id); } int rs_fw_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h index 736ac9642921..5e89141656c0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h @@ -456,6 +456,4 @@ int rs_fw_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, bool enable); void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); -void iwl_mvm_tlc_amsdu_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb); #endif /* __rs__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index e597bc193e5c..0497c7a44def 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -278,8 +278,8 @@ u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx) u8 ind = last_idx; int i; - for (i = 0; i < MAX_RS_ANT_NUM; i++) { - ind = (ind + 1) % MAX_RS_ANT_NUM; + for (i = 0; i < MAX_ANT_NUM; i++) { + ind = (ind + 1) % MAX_ANT_NUM; if (valid & BIT(ind)) return ind; } -- cgit v1.2.3 From 4ae80f6c8d86c415527b8bfff7c85ebe6268fc9c Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Mon, 14 Aug 2017 13:06:48 +0300 Subject: iwlwifi: support api ver2 of NVM_GET_INFO resp NVM_GET_INFO API has changed to support indication of 11ax support. Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/nvm-reg.h | 42 ++++++++++++++-------- drivers/net/wireless/intel/iwlwifi/fw/nvm.c | 14 +++++--- .../net/wireless/intel/iwlwifi/iwl-eeprom-parse.h | 1 + 3 files changed, 38 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index 37c57bcbfb4a..8d6dc9189985 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -189,23 +189,37 @@ struct iwl_nvm_get_info_general { u8 reserved; } __packed; /* GRP_REGULATORY_NVM_GET_INFO_GENERAL_S_VER_1 */ +/** + * enum iwl_nvm_mac_sku_flags - flags in &iwl_nvm_get_info_sku + * @NVM_MAC_SKU_FLAGS_BAND_2_4_ENABLED: true if 2.4 band enabled + * @NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED: true if 5.2 band enabled + * @NVM_MAC_SKU_FLAGS_802_11N_ENABLED: true if 11n enabled + * @NVM_MAC_SKU_FLAGS_802_11AC_ENABLED: true if 11ac enabled + * @NVM_MAC_SKU_FLAGS_802_11AX_ENABLED: true if 11ax enabled + * @NVM_MAC_SKU_FLAGS_MIMO_DISABLED: true if MIMO disabled + * @NVM_MAC_SKU_FLAGS_WAPI_ENABLED: true if WAPI enabled + * @NVM_MAC_SKU_FLAGS_REG_CHECK_ENABLED: true if regulatory checker enabled + * @NVM_MAC_SKU_FLAGS_API_LOCK_ENABLED: true if API lock enabled + */ +enum iwl_nvm_mac_sku_flags { + NVM_MAC_SKU_FLAGS_BAND_2_4_ENABLED = BIT(0), + NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED = BIT(1), + NVM_MAC_SKU_FLAGS_802_11N_ENABLED = BIT(2), + NVM_MAC_SKU_FLAGS_802_11AC_ENABLED = BIT(3), + NVM_MAC_SKU_FLAGS_802_11AX_ENABLED = BIT(4), + NVM_MAC_SKU_FLAGS_MIMO_DISABLED = BIT(5), + NVM_MAC_SKU_FLAGS_WAPI_ENABLED = BIT(8), + NVM_MAC_SKU_FLAGS_REG_CHECK_ENABLED = BIT(14), + NVM_MAC_SKU_FLAGS_API_LOCK_ENABLED = BIT(15), +}; + /** * struct iwl_nvm_get_info_sku - mac information - * @enable_24g: band 2.4G enabled - * @enable_5g: band 5G enabled - * @enable_11n: 11n enabled - * @enable_11ac: 11ac enabled - * @mimo_disable: MIMO enabled - * @ext_crypto: Extended crypto enabled + * @mac_sku_flags: flags for SKU, see &enum iwl_nvm_mac_sku_flags */ struct iwl_nvm_get_info_sku { - __le32 enable_24g; - __le32 enable_5g; - __le32 enable_11n; - __le32 enable_11ac; - __le32 mimo_disable; - __le32 ext_crypto; -} __packed; /* GRP_REGULATORY_NVM_GET_INFO_MAC_SKU_SECTION_S_VER_1 */ + __le32 mac_sku_flags; +} __packed; /* REGULATORY_NVM_GET_INFO_MAC_SKU_SECTION_S_VER_2 */ /** * struct iwl_nvm_get_info_phy - phy information @@ -243,7 +257,7 @@ struct iwl_nvm_get_info_rsp { struct iwl_nvm_get_info_sku mac_sku; struct iwl_nvm_get_info_phy phy_sku; struct iwl_nvm_get_info_regulatory regulatory; -} __packed; /* GRP_REGULATORY_NVM_GET_INFO_CMD_RSP_S_VER_1 */ +} __packed; /* GRP_REGULATORY_NVM_GET_INFO_CMD_RSP_S_VER_2 */ /** * struct iwl_nvm_access_complete_cmd - NVM_ACCESS commands are completed diff --git a/drivers/net/wireless/intel/iwlwifi/fw/nvm.c b/drivers/net/wireless/intel/iwlwifi/fw/nvm.c index bd2e1fb43f5a..ff44d9031e1a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/nvm.c @@ -86,6 +86,7 @@ struct iwl_nvm_data *iwl_fw_get_nvm(struct iwl_fw_runtime *fwrt) bool lar_fw_supported = !iwlwifi_mod_params.lar_disable && fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_LAR_SUPPORT); + u32 mac_flags; ret = iwl_trans_send_cmd(trans, &hcmd); if (ret) @@ -125,16 +126,19 @@ struct iwl_nvm_data *iwl_fw_get_nvm(struct iwl_fw_runtime *fwrt) nvm->nvm_version = le16_to_cpu(rsp->general.nvm_version); /* Initialize MAC sku data */ + mac_flags = le32_to_cpu(rsp->mac_sku.mac_sku_flags); nvm->sku_cap_11ac_enable = - le32_to_cpu(rsp->mac_sku.enable_11ac); + !!(mac_flags & NVM_MAC_SKU_FLAGS_802_11AC_ENABLED); nvm->sku_cap_11n_enable = - le32_to_cpu(rsp->mac_sku.enable_11n); + !!(mac_flags & NVM_MAC_SKU_FLAGS_802_11N_ENABLED); + nvm->sku_cap_11ax_enable = + !!(mac_flags & NVM_MAC_SKU_FLAGS_802_11AX_ENABLED); nvm->sku_cap_band_24GHz_enable = - le32_to_cpu(rsp->mac_sku.enable_24g); + !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_2_4_ENABLED); nvm->sku_cap_band_52GHz_enable = - le32_to_cpu(rsp->mac_sku.enable_5g); + !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED); nvm->sku_cap_mimo_disabled = - le32_to_cpu(rsp->mac_sku.mimo_disable); + !!(mac_flags & NVM_MAC_SKU_FLAGS_MIMO_DISABLED); /* Initialize PHY sku data */ nvm->valid_tx_ant = (u8)le32_to_cpu(rsp->phy_sku.tx_chains); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h index b33888991b94..16bea75e82f1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h @@ -85,6 +85,7 @@ struct iwl_nvm_data { bool sku_cap_band_52GHz_enable; bool sku_cap_11n_enable; bool sku_cap_11ac_enable; + bool sku_cap_11ax_enable; bool sku_cap_amt_enable; bool sku_cap_ipan_enable; bool sku_cap_mimo_disabled; -- cgit v1.2.3 From 4b82455ca51ed23cf0fd6a24ba72a40fd4794b82 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Tue, 15 Aug 2017 20:26:09 +0300 Subject: iwlwifi: use flags to denote modifiers for the channel maps Instead of having a boolean for each modifier we need to handle in the channel maps, create a bitmask with flags that denote each modification. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/nvm.c | 10 +++++---- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 25 ++++++++++++++-------- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h | 14 ++++++++++-- 3 files changed, 34 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/nvm.c b/drivers/net/wireless/intel/iwlwifi/fw/nvm.c index ff44d9031e1a..beefb89194a9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/nvm.c @@ -87,6 +87,7 @@ struct iwl_nvm_data *iwl_fw_get_nvm(struct iwl_fw_runtime *fwrt) fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_LAR_SUPPORT); u32 mac_flags; + u32 sbands_flags = 0; ret = iwl_trans_send_cmd(trans, &hcmd); if (ret) @@ -144,15 +145,16 @@ struct iwl_nvm_data *iwl_fw_get_nvm(struct iwl_fw_runtime *fwrt) nvm->valid_tx_ant = (u8)le32_to_cpu(rsp->phy_sku.tx_chains); nvm->valid_rx_ant = (u8)le32_to_cpu(rsp->phy_sku.rx_chains); - /* Initialize regulatory data */ - nvm->lar_enabled = - le32_to_cpu(rsp->regulatory.lar_enabled) && lar_fw_supported; + if (le32_to_cpu(rsp->regulatory.lar_enabled) && lar_fw_supported) { + nvm->lar_enabled = true; + sbands_flags |= IWL_NVM_SBANDS_FLAGS_LAR; + } iwl_init_sbands(trans->dev, trans->cfg, nvm, rsp->regulatory.channel_profile, nvm->valid_tx_ant & fwrt->fw->valid_tx_ant, nvm->valid_rx_ant & fwrt->fw->valid_rx_ant, - nvm->lar_enabled, false); + sbands_flags); iwl_free_resp(&hcmd); return nvm; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 3437ed480e31..735b211364d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -295,7 +295,7 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz, static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, struct iwl_nvm_data *data, const __le16 * const nvm_ch_flags, - bool lar_supported, bool no_wide_in_5ghz) + u32 sbands_flags) { int ch_idx; int n_channels = 0; @@ -323,7 +323,8 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, continue; /* workaround to disable wide channels in 5GHz */ - if (no_wide_in_5ghz && is_5ghz) { + if ((sbands_flags & IWL_NVM_SBANDS_FLAGS_NO_WIDE_IN_5GHZ) && + is_5ghz) { ch_flags &= ~(NVM_CHANNEL_40MHZ | NVM_CHANNEL_80MHZ | NVM_CHANNEL_160MHZ); @@ -332,7 +333,8 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, if (ch_flags & NVM_CHANNEL_160MHZ) data->vht160_supported = true; - if (!lar_supported && !(ch_flags & NVM_CHANNEL_VALID)) { + if (!(sbands_flags & IWL_NVM_SBANDS_FLAGS_LAR) && + !(ch_flags & NVM_CHANNEL_VALID)) { /* * Channels might become valid later if lar is * supported, hence we still want to add them to @@ -362,7 +364,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, channel->max_power = IWL_DEFAULT_MAX_TX_POWER; /* don't put limitations in case we're using LAR */ - if (!lar_supported) + if (!(sbands_flags & IWL_NVM_SBANDS_FLAGS_LAR)) channel->flags = iwl_get_channel_flags(nvm_chan[ch_idx], ch_idx, is_5ghz, ch_flags, cfg); @@ -460,15 +462,14 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, struct iwl_nvm_data *data, const __le16 *nvm_ch_flags, - u8 tx_chains, u8 rx_chains, bool lar_supported, - bool no_wide_in_5ghz) + u8 tx_chains, u8 rx_chains, u32 sbands_flags) { int n_channels; int n_used = 0; struct ieee80211_supported_band *sband; n_channels = iwl_init_channel_map(dev, cfg, data, nvm_ch_flags, - lar_supported, no_wide_in_5ghz); + sbands_flags); sband = &data->bands[NL80211_BAND_2GHZ]; sband->band = NL80211_BAND_2GHZ; sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS]; @@ -716,8 +717,8 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, struct device *dev = trans->dev; struct iwl_nvm_data *data; bool lar_enabled; - bool no_wide_in_5ghz = iwl_nvm_no_wide_in_5ghz(dev, cfg, nvm_hw); u32 sku, radio_cfg; + u32 sbands_flags = 0; u16 lar_config; const __le16 *ch_section; @@ -790,8 +791,14 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, return NULL; } + if (lar_fw_supported && lar_enabled) + sbands_flags |= IWL_NVM_SBANDS_FLAGS_LAR; + + if (iwl_nvm_no_wide_in_5ghz(dev, cfg, nvm_hw)) + sbands_flags |= IWL_NVM_SBANDS_FLAGS_NO_WIDE_IN_5GHZ; + iwl_init_sbands(dev, cfg, data, ch_section, tx_chains, rx_chains, - lar_fw_supported && lar_enabled, no_wide_in_5ghz); + sbands_flags); data->calib_version = 255; return data; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h index 6b108cae61b8..868baa508a16 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h @@ -69,6 +69,17 @@ #include #include "iwl-eeprom-parse.h" +/** + * enum iwl_nvm_sbands_flags - modification flags for the channel profiles + * + * @IWL_NVM_SBANDS_FLAGS_LAR: LAR is enabled + * @IWL_NVM_SBANDS_FLAGS_NO_WIDE_IN_5GHZ: disallow 40, 80 and 160MHz on 5GHz + */ +enum iwl_nvm_sbands_flags { + IWL_NVM_SBANDS_FLAGS_LAR = BIT(0), + IWL_NVM_SBANDS_FLAGS_NO_WIDE_IN_5GHZ = BIT(1), +}; + /** * iwl_parse_nvm_data - parse NVM data and return values * @@ -95,8 +106,7 @@ void iwl_set_hw_address_from_csr(struct iwl_trans *trans, */ void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, struct iwl_nvm_data *data, const __le16 *nvm_ch_flags, - u8 tx_chains, u8 rx_chains, bool lar_supported, - bool no_wide_in_5ghz); + u8 tx_chains, u8 rx_chains, u32 sbands_flags); /** * iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW -- cgit v1.2.3 From 28e9c00fe1f0b1ff811d23dcffbf632b85f33797 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Thu, 17 Aug 2017 19:02:04 +0300 Subject: iwlwifi: remove upper case letters in sku_capa_band_*_enable The sku_capa_band_24GHz_enable and sku_capa_band_52GHz_enable symbols cause checkpatch to complain whenever we use them. To prevent this, convert them to all lower case. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/dvm/main.c | 8 ++++---- drivers/net/wireless/intel/iwlwifi/fw/nvm.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h | 4 ++-- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index e68254e12764..030482b357a3 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -1200,16 +1200,16 @@ static int iwl_eeprom_init_hw_params(struct iwl_priv *priv) return -EINVAL; } - if (!data->sku_cap_11n_enable && !data->sku_cap_band_24GHz_enable && - !data->sku_cap_band_52GHz_enable) { + if (!data->sku_cap_11n_enable && !data->sku_cap_band_24ghz_enable && + !data->sku_cap_band_52ghz_enable) { IWL_ERR(priv, "Invalid device sku\n"); return -EINVAL; } IWL_DEBUG_INFO(priv, "Device SKU: 24GHz %s %s, 52GHz %s %s, 11.n %s %s\n", - data->sku_cap_band_24GHz_enable ? "" : "NOT", "enabled", - data->sku_cap_band_52GHz_enable ? "" : "NOT", "enabled", + data->sku_cap_band_24ghz_enable ? "" : "NOT", "enabled", + data->sku_cap_band_52ghz_enable ? "" : "NOT", "enabled", data->sku_cap_11n_enable ? "" : "NOT", "enabled"); priv->hw_params.tx_chains_num = diff --git a/drivers/net/wireless/intel/iwlwifi/fw/nvm.c b/drivers/net/wireless/intel/iwlwifi/fw/nvm.c index beefb89194a9..b8d88df27b18 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/nvm.c @@ -134,9 +134,9 @@ struct iwl_nvm_data *iwl_fw_get_nvm(struct iwl_fw_runtime *fwrt) !!(mac_flags & NVM_MAC_SKU_FLAGS_802_11N_ENABLED); nvm->sku_cap_11ax_enable = !!(mac_flags & NVM_MAC_SKU_FLAGS_802_11AX_ENABLED); - nvm->sku_cap_band_24GHz_enable = + nvm->sku_cap_band_24ghz_enable = !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_2_4_ENABLED); - nvm->sku_cap_band_52GHz_enable = + nvm->sku_cap_band_52ghz_enable = !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED); nvm->sku_cap_mimo_disabled = !!(mac_flags & NVM_MAC_SKU_FLAGS_MIMO_DISABLED); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c index 3199d345b427..777f5df8a0c6 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c @@ -899,8 +899,8 @@ iwl_parse_eeprom_data(struct device *dev, const struct iwl_cfg *cfg, EEPROM_SKU_CAP); data->sku_cap_11n_enable = sku & EEPROM_SKU_CAP_11N_ENABLE; data->sku_cap_amt_enable = sku & EEPROM_SKU_CAP_AMT_ENABLE; - data->sku_cap_band_24GHz_enable = sku & EEPROM_SKU_CAP_BAND_24GHZ; - data->sku_cap_band_52GHz_enable = sku & EEPROM_SKU_CAP_BAND_52GHZ; + data->sku_cap_band_24ghz_enable = sku & EEPROM_SKU_CAP_BAND_24GHZ; + data->sku_cap_band_52ghz_enable = sku & EEPROM_SKU_CAP_BAND_52GHZ; data->sku_cap_ipan_enable = sku & EEPROM_SKU_CAP_IPAN_ENABLE; if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) data->sku_cap_11n_enable = false; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h index 16bea75e82f1..8be50ed12300 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h @@ -81,8 +81,8 @@ struct iwl_nvm_data { __le16 kelvin_voltage; __le16 xtal_calib[2]; - bool sku_cap_band_24GHz_enable; - bool sku_cap_band_52GHz_enable; + bool sku_cap_band_24ghz_enable; + bool sku_cap_band_52ghz_enable; bool sku_cap_11n_enable; bool sku_cap_11ac_enable; bool sku_cap_11ax_enable; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 735b211364d2..a6246dc9f025 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -319,7 +319,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx); - if (is_5ghz && !data->sku_cap_band_52GHz_enable) + if (is_5ghz && !data->sku_cap_band_52ghz_enable) continue; /* workaround to disable wide channels in 5GHz */ @@ -745,8 +745,8 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, rx_chains &= data->valid_rx_ant; sku = iwl_get_sku(cfg, nvm_sw, phy_sku); - data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ; - data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ; + data->sku_cap_band_24ghz_enable = sku & NVM_SKU_CAP_BAND_24GHZ; + data->sku_cap_band_52ghz_enable = sku & NVM_SKU_CAP_BAND_52GHZ; data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE; if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) data->sku_cap_11n_enable = false; -- cgit v1.2.3 From 4c625c564ba2cf92fdd9cb7387d30be04139f77b Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Wed, 24 Jan 2018 16:12:49 +0200 Subject: iwlwifi: get rid of fw/nvm.c There's already an opmode common file for nvm iwl-nvm-parse.c Move the content of fw/nvm.c to iwl-nvm-parse.c and delete fw/nvm.c. Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/Makefile | 2 +- drivers/net/wireless/intel/iwlwifi/fw/nvm.c | 168 --------------------- drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 1 - drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 111 +++++++++++++- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h | 21 +-- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 +- 6 files changed, 114 insertions(+), 191 deletions(-) delete mode 100644 drivers/net/wireless/intel/iwlwifi/fw/nvm.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index e6205eae51fd..4d08d78c6b71 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -13,7 +13,7 @@ iwlwifi-$(CONFIG_IWLMVM) += cfg/7000.o cfg/8000.o cfg/9000.o cfg/22000.o iwlwifi-objs += iwl-trans.o iwlwifi-objs += fw/notif-wait.o iwlwifi-$(CONFIG_IWLMVM) += fw/paging.o fw/smem.o fw/init.o fw/dbg.o -iwlwifi-$(CONFIG_IWLMVM) += fw/common_rx.o fw/nvm.o +iwlwifi-$(CONFIG_IWLMVM) += fw/common_rx.o iwlwifi-$(CONFIG_ACPI) += fw/acpi.o iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += fw/debugfs.o diff --git a/drivers/net/wireless/intel/iwlwifi/fw/nvm.c b/drivers/net/wireless/intel/iwlwifi/fw/nvm.c deleted file mode 100644 index b8d88df27b18..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/fw/nvm.c +++ /dev/null @@ -1,168 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called COPYING. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ -#include "iwl-drv.h" -#include "runtime.h" -#include "fw/api/nvm-reg.h" -#include "fw/api/commands.h" -#include "iwl-nvm-parse.h" - -struct iwl_nvm_data *iwl_fw_get_nvm(struct iwl_fw_runtime *fwrt) -{ - struct iwl_nvm_get_info cmd = {}; - struct iwl_nvm_get_info_rsp *rsp; - struct iwl_trans *trans = fwrt->trans; - struct iwl_nvm_data *nvm; - struct iwl_host_cmd hcmd = { - .flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL, - .data = { &cmd, }, - .len = { sizeof(cmd) }, - .id = WIDE_ID(REGULATORY_AND_NVM_GROUP, NVM_GET_INFO) - }; - int ret; - bool lar_fw_supported = !iwlwifi_mod_params.lar_disable && - fw_has_capa(&fwrt->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_LAR_SUPPORT); - u32 mac_flags; - u32 sbands_flags = 0; - - ret = iwl_trans_send_cmd(trans, &hcmd); - if (ret) - return ERR_PTR(ret); - - if (WARN(iwl_rx_packet_payload_len(hcmd.resp_pkt) != sizeof(*rsp), - "Invalid payload len in NVM response from FW %d", - iwl_rx_packet_payload_len(hcmd.resp_pkt))) { - ret = -EINVAL; - goto out; - } - - rsp = (void *)hcmd.resp_pkt->data; - if (le32_to_cpu(rsp->general.flags) & NVM_GENERAL_FLAGS_EMPTY_OTP) - IWL_INFO(fwrt, "OTP is empty\n"); - - nvm = kzalloc(sizeof(*nvm) + - sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS, - GFP_KERNEL); - if (!nvm) { - ret = -ENOMEM; - goto out; - } - - iwl_set_hw_address_from_csr(trans, nvm); - /* TODO: if platform NVM has MAC address - override it here */ - - if (!is_valid_ether_addr(nvm->hw_addr)) { - IWL_ERR(fwrt, "no valid mac address was found\n"); - ret = -EINVAL; - goto err_free; - } - - IWL_INFO(trans, "base HW address: %pM\n", nvm->hw_addr); - - /* Initialize general data */ - nvm->nvm_version = le16_to_cpu(rsp->general.nvm_version); - - /* Initialize MAC sku data */ - mac_flags = le32_to_cpu(rsp->mac_sku.mac_sku_flags); - nvm->sku_cap_11ac_enable = - !!(mac_flags & NVM_MAC_SKU_FLAGS_802_11AC_ENABLED); - nvm->sku_cap_11n_enable = - !!(mac_flags & NVM_MAC_SKU_FLAGS_802_11N_ENABLED); - nvm->sku_cap_11ax_enable = - !!(mac_flags & NVM_MAC_SKU_FLAGS_802_11AX_ENABLED); - nvm->sku_cap_band_24ghz_enable = - !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_2_4_ENABLED); - nvm->sku_cap_band_52ghz_enable = - !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED); - nvm->sku_cap_mimo_disabled = - !!(mac_flags & NVM_MAC_SKU_FLAGS_MIMO_DISABLED); - - /* Initialize PHY sku data */ - nvm->valid_tx_ant = (u8)le32_to_cpu(rsp->phy_sku.tx_chains); - nvm->valid_rx_ant = (u8)le32_to_cpu(rsp->phy_sku.rx_chains); - - if (le32_to_cpu(rsp->regulatory.lar_enabled) && lar_fw_supported) { - nvm->lar_enabled = true; - sbands_flags |= IWL_NVM_SBANDS_FLAGS_LAR; - } - - iwl_init_sbands(trans->dev, trans->cfg, nvm, - rsp->regulatory.channel_profile, - nvm->valid_tx_ant & fwrt->fw->valid_tx_ant, - nvm->valid_rx_ant & fwrt->fw->valid_rx_ant, - sbands_flags); - - iwl_free_resp(&hcmd); - return nvm; - -err_free: - kfree(nvm); -out: - iwl_free_resp(&hcmd); - return ERR_PTR(ret); -} -IWL_EXPORT_SYMBOL(iwl_fw_get_nvm); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 3fb940ebd74a..d8db1dd100b0 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -170,6 +170,5 @@ void iwl_get_shared_mem_conf(struct iwl_fw_runtime *fwrt); void iwl_fwrt_handle_notification(struct iwl_fw_runtime *fwrt, struct iwl_rx_cmd_buffer *rxb); -struct iwl_nvm_data *iwl_fw_get_nvm(struct iwl_fw_runtime *fwrt); #endif /* __iwl_fw_runtime_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index a6246dc9f025..6d33c14579d9 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -80,6 +80,9 @@ #include "iwl-csr.h" #include "fw/acpi.h" #include "fw/api/nvm-reg.h" +#include "fw/api/commands.h" +#include "fw/api/cmdhdr.h" +#include "fw/img.h" /* NVM offsets (in words) definitions */ enum nvm_offsets { @@ -460,9 +463,10 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map; } -void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, - struct iwl_nvm_data *data, const __le16 *nvm_ch_flags, - u8 tx_chains, u8 rx_chains, u32 sbands_flags) +static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, + struct iwl_nvm_data *data, + const __le16 *nvm_ch_flags, u8 tx_chains, + u8 rx_chains, u32 sbands_flags) { int n_channels; int n_used = 0; @@ -495,7 +499,6 @@ void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n", n_used, n_channels); } -IWL_EXPORT_SYMBOL(iwl_init_sbands); static int iwl_get_sku(const struct iwl_cfg *cfg, const __le16 *nvm_sw, const __le16 *phy_sku) @@ -573,8 +576,8 @@ static void iwl_flip_hw_address(__le32 mac_addr0, __le32 mac_addr1, u8 *dest) dest[5] = hw_addr[0]; } -void iwl_set_hw_address_from_csr(struct iwl_trans *trans, - struct iwl_nvm_data *data) +static void iwl_set_hw_address_from_csr(struct iwl_trans *trans, + struct iwl_nvm_data *data) { __le32 mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_STRAP)); __le32 mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_STRAP)); @@ -592,7 +595,6 @@ void iwl_set_hw_address_from_csr(struct iwl_trans *trans, iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); } -IWL_EXPORT_SYMBOL(iwl_set_hw_address_from_csr); static void iwl_set_hw_address_family_8000(struct iwl_trans *trans, const struct iwl_cfg *cfg, @@ -1145,3 +1147,98 @@ out: return ret; } IWL_EXPORT_SYMBOL(iwl_read_external_nvm); + +struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, + const struct iwl_fw *fw) +{ + struct iwl_nvm_get_info cmd = {}; + struct iwl_nvm_get_info_rsp *rsp; + struct iwl_nvm_data *nvm; + struct iwl_host_cmd hcmd = { + .flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL, + .data = { &cmd, }, + .len = { sizeof(cmd) }, + .id = WIDE_ID(REGULATORY_AND_NVM_GROUP, NVM_GET_INFO) + }; + int ret; + bool lar_fw_supported = !iwlwifi_mod_params.lar_disable && + fw_has_capa(&fw->ucode_capa, + IWL_UCODE_TLV_CAPA_LAR_SUPPORT); + u32 mac_flags; + u32 sbands_flags = 0; + + ret = iwl_trans_send_cmd(trans, &hcmd); + if (ret) + return ERR_PTR(ret); + + if (WARN(iwl_rx_packet_payload_len(hcmd.resp_pkt) != sizeof(*rsp), + "Invalid payload len in NVM response from FW %d", + iwl_rx_packet_payload_len(hcmd.resp_pkt))) { + ret = -EINVAL; + goto out; + } + + rsp = (void *)hcmd.resp_pkt->data; + if (le32_to_cpu(rsp->general.flags) & NVM_GENERAL_FLAGS_EMPTY_OTP) + IWL_INFO(trans, "OTP is empty\n"); + + nvm = kzalloc(sizeof(*nvm) + + sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS, + GFP_KERNEL); + if (!nvm) { + ret = -ENOMEM; + goto out; + } + + iwl_set_hw_address_from_csr(trans, nvm); + /* TODO: if platform NVM has MAC address - override it here */ + + if (!is_valid_ether_addr(nvm->hw_addr)) { + IWL_ERR(trans, "no valid mac address was found\n"); + ret = -EINVAL; + goto err_free; + } + + IWL_INFO(trans, "base HW address: %pM\n", nvm->hw_addr); + + /* Initialize general data */ + nvm->nvm_version = le16_to_cpu(rsp->general.nvm_version); + + /* Initialize MAC sku data */ + mac_flags = le32_to_cpu(rsp->mac_sku.mac_sku_flags); + nvm->sku_cap_11ac_enable = + !!(mac_flags & NVM_MAC_SKU_FLAGS_802_11AC_ENABLED); + nvm->sku_cap_11n_enable = + !!(mac_flags & NVM_MAC_SKU_FLAGS_802_11N_ENABLED); + nvm->sku_cap_band_24ghz_enable = + !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_2_4_ENABLED); + nvm->sku_cap_band_52ghz_enable = + !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED); + nvm->sku_cap_mimo_disabled = + !!(mac_flags & NVM_MAC_SKU_FLAGS_MIMO_DISABLED); + + /* Initialize PHY sku data */ + nvm->valid_tx_ant = (u8)le32_to_cpu(rsp->phy_sku.tx_chains); + nvm->valid_rx_ant = (u8)le32_to_cpu(rsp->phy_sku.rx_chains); + + if (le32_to_cpu(rsp->regulatory.lar_enabled) && lar_fw_supported) { + nvm->lar_enabled = true; + sbands_flags |= IWL_NVM_SBANDS_FLAGS_LAR; + } + + iwl_init_sbands(trans->dev, trans->cfg, nvm, + rsp->regulatory.channel_profile, + nvm->valid_tx_ant & fw->valid_tx_ant, + nvm->valid_rx_ant & fw->valid_rx_ant, + sbands_flags); + + iwl_free_resp(&hcmd); + return nvm; + +err_free: + kfree(nvm); +out: + iwl_free_resp(&hcmd); + return ERR_PTR(ret); +} +IWL_EXPORT_SYMBOL(iwl_get_nvm); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h index 868baa508a16..60c7586f8342 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h @@ -95,19 +95,6 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, const __le16 *mac_override, const __le16 *phy_sku, u8 tx_chains, u8 rx_chains, bool lar_fw_supported); -/** - * iwl_set_hw_address_from_csr - sets HW address for 9000 devices and on - */ -void iwl_set_hw_address_from_csr(struct iwl_trans *trans, - struct iwl_nvm_data *data); - -/** - * iwl_init_sbands - parse and set all channel profiles - */ -void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, - struct iwl_nvm_data *data, const __le16 *nvm_ch_flags, - u8 tx_chains, u8 rx_chains, u32 sbands_flags); - /** * iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW * @@ -142,4 +129,12 @@ int iwl_read_external_nvm(struct iwl_trans *trans, void iwl_nvm_fixups(u32 hw_id, unsigned int section, u8 *data, unsigned int len); +/** + * iwl_get_nvm - retrieve NVM data from firmware + * + * Allocates a new iwl_nvm_data structure, fills it with + * NVM data, and returns it to caller. + */ +struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, + const struct iwl_fw *fw); #endif /* __iwl_nvm_parse_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index d5a612add59f..866c91c923be 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -415,7 +415,7 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) /* Read the NVM only at driver load time, no need to do this twice */ if (!IWL_MVM_PARSE_NVM && read_nvm) { - mvm->nvm_data = iwl_fw_get_nvm(&mvm->fwrt); + mvm->nvm_data = iwl_get_nvm(mvm->trans, mvm->fw); if (IS_ERR(mvm->nvm_data)) { ret = PTR_ERR(mvm->nvm_data); mvm->nvm_data = NULL; -- cgit v1.2.3 From bd8f3fc613919b50038c949f80b3f350a166293e Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Wed, 17 Jan 2018 15:25:28 +0200 Subject: iwlwifi: mvm: support 22000 HW opening agg before traffic When trying to open aggregations on 22000 HW before traffic had actually passed, the driver will discover it is missing a queue to aggregate on. In such a case - allocate a queue. Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 4f9d3e13d7e5..4ddd2c427b83 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -36,6 +36,7 @@ * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -2467,6 +2468,15 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, lockdep_assert_held(&mvm->mutex); + if (mvmsta->tid_data[tid].txq_id == IWL_MVM_INVALID_QUEUE && + iwl_mvm_has_new_tx_api(mvm)) { + u8 ac = tid_to_mac80211_ac[tid]; + + ret = iwl_mvm_sta_alloc_queue_tvqm(mvm, sta, ac, tid); + if (ret) + return ret; + } + spin_lock_bh(&mvmsta->lock); /* possible race condition - we entered D0i3 while starting agg */ -- cgit v1.2.3 From cea19a6ce8bf0518d156beea419d822021cc3705 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Thu, 19 Apr 2018 19:39:38 +0300 Subject: ath10k: add WMI_SERVICE_AVAILABLE_EVENT support Add WMI_SERVICE_AVAILABLE_EVENT to extend WMI_SERVICE_READY_EVENT, the 128bit service map in WMI_SERVICE_READY_EVENT is not enough for firmware to notice new WLAN service to host driver. Hereby, for thoese new WLAN service, firmware will notice host driver by WMI_SERVICE_AVAILABLE_EVENT. Signed-off-by: Alan Liu Signed-off-by: Carl Huang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-ops.h | 24 +++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 38 ++++ drivers/net/wireless/ath/ath10k/wmi-tlv.h | 346 +++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/wmi.c | 21 +- drivers/net/wireless/ath/ath10k/wmi.h | 8 + 5 files changed, 431 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index c35e45340b4f..4f7e0ba071a2 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -25,6 +25,7 @@ struct sk_buff; struct wmi_ops { void (*rx)(struct ath10k *ar, struct sk_buff *skb); void (*map_svc)(const __le32 *in, unsigned long *out, size_t len); + void (*map_svc_ext)(const __le32 *in, unsigned long *out, size_t len); int (*pull_scan)(struct ath10k *ar, struct sk_buff *skb, struct wmi_scan_ev_arg *arg); @@ -54,6 +55,9 @@ struct wmi_ops { struct wmi_wow_ev_arg *arg); int (*pull_echo_ev)(struct ath10k *ar, struct sk_buff *skb, struct wmi_echo_ev_arg *arg); + int (*pull_svc_avail)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_svc_avail_ev_arg *arg); + enum wmi_txbf_conf (*get_txbf_conf_scheme)(struct ath10k *ar); struct sk_buff *(*gen_pdev_suspend)(struct ath10k *ar, u32 suspend_opt); @@ -229,6 +233,17 @@ ath10k_wmi_map_svc(struct ath10k *ar, const __le32 *in, unsigned long *out, return 0; } +static inline int +ath10k_wmi_map_svc_ext(struct ath10k *ar, const __le32 *in, unsigned long *out, + size_t len) +{ + if (!ar->wmi.ops->map_svc_ext) + return -EOPNOTSUPP; + + ar->wmi.ops->map_svc_ext(in, out, len); + return 0; +} + static inline int ath10k_wmi_pull_scan(struct ath10k *ar, struct sk_buff *skb, struct wmi_scan_ev_arg *arg) @@ -329,6 +344,15 @@ ath10k_wmi_pull_rdy(struct ath10k *ar, struct sk_buff *skb, return ar->wmi.ops->pull_rdy(ar, skb, arg); } +static inline int +ath10k_wmi_pull_svc_avail(struct ath10k *ar, struct sk_buff *skb, + struct wmi_svc_avail_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_svc_avail) + return -EOPNOTSUPP; + return ar->wmi.ops->pull_svc_avail(ar, skb, arg); +} + static inline int ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb, struct ath10k_fw_stats *stats) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 9d1b0a459069..31866e3b74fc 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -594,6 +594,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_TLV_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; + case WMI_TLV_SERVICE_AVAILABLE_EVENTID: + ath10k_wmi_event_service_available(ar, skb); + break; case WMI_TLV_OFFLOAD_BCN_TX_STATUS_EVENTID: ath10k_wmi_tlv_event_bcn_tx_status(ar, skb); break; @@ -1117,6 +1120,39 @@ static int ath10k_wmi_tlv_op_pull_rdy_ev(struct ath10k *ar, return 0; } +static int ath10k_wmi_tlv_svc_avail_parse(struct ath10k *ar, u16 tag, u16 len, + const void *ptr, void *data) +{ + struct wmi_svc_avail_ev_arg *arg = data; + + switch (tag) { + case WMI_TLV_TAG_STRUCT_SERVICE_AVAILABLE_EVENT: + arg->service_map_ext_len = *(__le32 *)ptr; + arg->service_map_ext = ptr + sizeof(__le32); + return 0; + default: + break; + } + return -EPROTO; +} + +static int ath10k_wmi_tlv_op_pull_svc_avail(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_svc_avail_ev_arg *arg) +{ + int ret; + + ret = ath10k_wmi_tlv_iter(ar, skb->data, skb->len, + ath10k_wmi_tlv_svc_avail_parse, arg); + + if (ret) { + ath10k_warn(ar, "failed to parse svc_avail tlv: %d\n", ret); + return ret; + } + + return 0; +} + static void ath10k_wmi_tlv_pull_vdev_stats(const struct wmi_tlv_vdev_stats *src, struct ath10k_fw_stats_vdev *dst) { @@ -3740,6 +3776,7 @@ static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = { static const struct wmi_ops wmi_tlv_ops = { .rx = ath10k_wmi_tlv_op_rx, .map_svc = wmi_tlv_svc_map, + .map_svc_ext = wmi_tlv_svc_map_ext, .pull_scan = ath10k_wmi_tlv_op_pull_scan_ev, .pull_mgmt_rx = ath10k_wmi_tlv_op_pull_mgmt_rx_ev, @@ -3751,6 +3788,7 @@ static const struct wmi_ops wmi_tlv_ops = { .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, .pull_svc_rdy = ath10k_wmi_tlv_op_pull_svc_rdy_ev, .pull_rdy = ath10k_wmi_tlv_op_pull_rdy_ev, + .pull_svc_avail = ath10k_wmi_tlv_op_pull_svc_avail, .pull_fw_stats = ath10k_wmi_tlv_op_pull_fw_stats, .pull_roam_ev = ath10k_wmi_tlv_op_pull_roam_ev, .pull_wow_event = ath10k_wmi_tlv_op_pull_wow_ev, diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index fa3773ec7c68..529b91b17061 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -295,6 +295,7 @@ enum wmi_tlv_cmd_id { enum wmi_tlv_event_id { WMI_TLV_SERVICE_READY_EVENTID = 0x1, WMI_TLV_READY_EVENTID, + WMI_TLV_SERVICE_AVAILABLE_EVENTID, WMI_TLV_SCAN_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SCAN), WMI_TLV_PDEV_TPC_CONFIG_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PDEV), WMI_TLV_CHAN_INFO_EVENTID, @@ -949,6 +950,275 @@ enum wmi_tlv_tag { WMI_TLV_TAG_STRUCT_PACKET_FILTER_ENABLE, WMI_TLV_TAG_STRUCT_SAP_SET_BLACKLIST_PARAM_CMD, WMI_TLV_TAG_STRUCT_MGMT_TX_CMD, + WMI_TLV_TAG_STRUCT_MGMT_TX_COMPL_EVENT, + WMI_TLV_TAG_STRUCT_SOC_SET_ANTENNA_MODE_CMD, + WMI_TLV_TAG_STRUCT_WOW_UDP_SVC_OFLD_CMD, + WMI_TLV_TAG_STRUCT_LRO_INFO_CMD, + WMI_TLV_TAG_STRUCT_ROAM_EARLYSTOP_RSSI_THRES_PARAM, + WMI_TLV_TAG_STRUCT_SERVICE_READY_EXT_EVENT, + WMI_TLV_TAG_STRUCT_MAWC_SENSOR_REPORT_IND_CMD, + WMI_TLV_TAG_STRUCT_MAWC_ENABLE_SENSOR_EVENT, + WMI_TLV_TAG_STRUCT_ROAM_CONFIGURE_MAWC_CMD, + WMI_TLV_TAG_STRUCT_NLO_CONFIGURE_MAWC_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_CONFIGURE_MAWC_CMD, + WMI_TLV_TAG_STRUCT_PEER_ASSOC_CONF_EVENT, + WMI_TLV_TAG_STRUCT_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_AP_PS_EGAP_PARAM_CMD, + WMI_TLV_TAG_STRUCT_AP_PS_EGAP_INFO_EVENT, + WMI_TLV_TAG_STRUCT_PMF_OFFLOAD_SET_SA_QUERY_CMD, + WMI_TLV_TAG_STRUCT_TRANSFER_DATA_TO_FLASH_CMD, + WMI_TLV_TAG_STRUCT_TRANSFER_DATA_TO_FLASH_COMPLETE_EVENT, + WMI_TLV_TAG_STRUCT_SCPC_EVENT, + WMI_TLV_TAG_STRUCT_AP_PS_EGAP_INFO_CHAINMASK_LIST, + WMI_TLV_TAG_STRUCT_STA_SMPS_FORCE_MODE_COMPLETE_EVENT, + WMI_TLV_TAG_STRUCT_BPF_GET_CAPABILITY_CMD, + WMI_TLV_TAG_STRUCT_BPF_CAPABILITY_INFO_EVT, + WMI_TLV_TAG_STRUCT_BPF_GET_VDEV_STATS_CMD, + WMI_TLV_TAG_STRUCT_BPF_VDEV_STATS_INFO_EVT, + WMI_TLV_TAG_STRUCT_BPF_SET_VDEV_INSTRUCTIONS_CMD, + WMI_TLV_TAG_STRUCT_BPF_DEL_VDEV_INSTRUCTIONS_CMD, + WMI_TLV_TAG_STRUCT_VDEV_DELETE_RESP_EVENT, + WMI_TLV_TAG_STRUCT_PEER_DELETE_RESP_EVENT, + WMI_TLV_TAG_STRUCT_ROAM_DENSE_THRES_PARAM, + WMI_TLV_TAG_STRUCT_ENLO_CANDIDATE_SCORE_PARAM, + WMI_TLV_TAG_STRUCT_PEER_UPDATE_WDS_ENTRY_CMD, + WMI_TLV_TAG_STRUCT_VDEV_CONFIG_RATEMASK, + WMI_TLV_TAG_STRUCT_PDEV_FIPS_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SMART_ANT_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SMART_ANT_SET_RX_ANTENNA_CMD, + WMI_TLV_TAG_STRUCT_PEER_SMART_ANT_SET_TX_ANTENNA_CMD, + WMI_TLV_TAG_STRUCT_PEER_SMART_ANT_SET_TRAIN_ANTENNA_CMD, + WMI_TLV_TAG_STRUCT_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_ANT_SWITCH_TBL_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_CTL_TABLE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_MIMOGAIN_TABLE_CMD, + WMI_TLV_TAG_STRUCT_FWTEST_SET_PARAM_CMD, + WMI_TLV_TAG_STRUCT_PEER_ATF_REQUEST, + WMI_TLV_TAG_STRUCT_VDEV_ATF_REQUEST, + WMI_TLV_TAG_STRUCT_PDEV_GET_ANI_CCK_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_PDEV_GET_ANI_OFDM_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_INST_RSSI_STATS_RESP, + WMI_TLV_TAG_STRUCT_MED_UTIL_REPORT_EVENT, + WMI_TLV_TAG_STRUCT_PEER_STA_PS_STATECHANGE_EVENT, + WMI_TLV_TAG_STRUCT_WDS_ADDR_EVENT, + WMI_TLV_TAG_STRUCT_PEER_RATECODE_LIST_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_NFCAL_POWER_ALL_CHANNELS_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_TPC_EVENT, + WMI_TLV_TAG_STRUCT_ANI_OFDM_EVENT, + WMI_TLV_TAG_STRUCT_ANI_CCK_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_CHANNEL_HOPPING_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_FIPS_EVENT, + WMI_TLV_TAG_STRUCT_ATF_PEER_INFO, + WMI_TLV_TAG_STRUCT_PDEV_GET_TPC_CMD, + WMI_TLV_TAG_STRUCT_VDEV_FILTER_NRP_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_QBOOST_CFG_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SMART_ANT_GPIO_HANDLE, + WMI_TLV_TAG_STRUCT_PEER_SMART_ANT_SET_TX_ANTENNA_SERIES, + WMI_TLV_TAG_STRUCT_PEER_SMART_ANT_SET_TRAIN_ANTENNA_PARAM, + WMI_TLV_TAG_STRUCT_PDEV_SET_ANT_CTRL_CHAIN, + WMI_TLV_TAG_STRUCT_PEER_CCK_OFDM_RATE_INFO, + WMI_TLV_TAG_STRUCT_PEER_MCS_RATE_INFO, + WMI_TLV_TAG_STRUCT_PDEV_NFCAL_POWER_ALL_CHANNELS_NFDBR, + WMI_TLV_TAG_STRUCT_PDEV_NFCAL_POWER_ALL_CHANNELS_NFDBM, + WMI_TLV_TAG_STRUCT_PDEV_NFCAL_POWER_ALL_CHANNELS_FREQNUM, + WMI_TLV_TAG_STRUCT_MU_REPORT_TOTAL_MU, + WMI_TLV_TAG_STRUCT_VDEV_SET_DSCP_TID_MAP_CMD, + WMI_TLV_TAG_STRUCT_ROAM_SET_MBO, + WMI_TLV_TAG_STRUCT_MIB_STATS_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_NAN_DISC_IFACE_CREATED_EVENT, + WMI_TLV_TAG_STRUCT_NAN_DISC_IFACE_DELETED_EVENT, + WMI_TLV_TAG_STRUCT_NAN_STARTED_CLUSTER_EVENT, + WMI_TLV_TAG_STRUCT_NAN_JOINED_CLUSTER_EVENT, + WMI_TLV_TAG_STRUCT_NDI_GET_CAP_REQ, + WMI_TLV_TAG_STRUCT_NDP_INITIATOR_REQ, + WMI_TLV_TAG_STRUCT_NDP_RESPONDER_REQ, + WMI_TLV_TAG_STRUCT_NDP_END_REQ, + WMI_TLV_TAG_STRUCT_NDI_CAP_RSP_EVENT, + WMI_TLV_TAG_STRUCT_NDP_INITIATOR_RSP_EVENT, + WMI_TLV_TAG_STRUCT_NDP_RESPONDER_RSP_EVENT, + WMI_TLV_TAG_STRUCT_NDP_END_RSP_EVENT, + WMI_TLV_TAG_STRUCT_NDP_INDICATION_EVENT, + WMI_TLV_TAG_STRUCT_NDP_CONFIRM_EVENT, + WMI_TLV_TAG_STRUCT_NDP_END_INDICATION_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_SET_QUIET_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_PCL_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_HW_MODE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_MAC_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_ANTENNA_MODE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_HW_MODE_RESPONSE_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_HW_MODE_TRANSITION_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_SET_HW_MODE_RESPONSE_VDEV_MAC_ENTRY, + WMI_TLV_TAG_STRUCT_PDEV_SET_MAC_CONFIG_RESPONSE_EVENT, + WMI_TLV_TAG_STRUCT_COEX_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_CONFIG_ENHANCED_MCAST_FILTER, + WMI_TLV_TAG_STRUCT_CHAN_AVOID_RPT_ALLOW_CMD, + WMI_TLV_TAG_STRUCT_SET_PERIODIC_CHANNEL_STATS_CONFIG, + WMI_TLV_TAG_STRUCT_VDEV_SET_CUSTOM_AGGR_SIZE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_WAL_POWER_DEBUG_CMD, + WMI_TLV_TAG_STRUCT_MAC_PHY_CAPABILITIES, + WMI_TLV_TAG_STRUCT_HW_MODE_CAPABILITIES, + WMI_TLV_TAG_STRUCT_SOC_MAC_PHY_HW_MODE_CAPS, + WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES_EXT, + WMI_TLV_TAG_STRUCT_SOC_HAL_REG_CAPABILITIES, + WMI_TLV_TAG_STRUCT_VDEV_WISA_CMD, + WMI_TLV_TAG_STRUCT_TX_POWER_LEVEL_STATS_EVT, + WMI_TLV_TAG_STRUCT_SCAN_ADAPTIVE_DWELL_PARAMETERS_TLV, + WMI_TLV_TAG_STRUCT_SCAN_ADAPTIVE_DWELL_CONFIG, + WMI_TLV_TAG_STRUCT_WOW_SET_ACTION_WAKE_UP_CMD, + WMI_TLV_TAG_STRUCT_NDP_END_RSP_PER_NDI, + WMI_TLV_TAG_STRUCT_PEER_BWF_REQUEST, + WMI_TLV_TAG_STRUCT_BWF_PEER_INFO, + WMI_TLV_TAG_STRUCT_DBGLOG_TIME_STAMP_SYNC_CMD, + WMI_TLV_TAG_STRUCT_RMC_SET_LEADER_CMD, + WMI_TLV_TAG_STRUCT_RMC_MANUAL_LEADER_EVENT, + WMI_TLV_TAG_STRUCT_PER_CHAIN_RSSI_STATS, + WMI_TLV_TAG_STRUCT_RSSI_STATS, + WMI_TLV_TAG_STRUCT_P2P_LO_START_CMD, + WMI_TLV_TAG_STRUCT_P2P_LO_STOP_CMD, + WMI_TLV_TAG_STRUCT_P2P_LO_STOPPED_EVENT, + WMI_TLV_TAG_STRUCT_PEER_REORDER_QUEUE_SETUP_CMD, + WMI_TLV_TAG_STRUCT_PEER_REORDER_QUEUE_REMOVE_CMD, + WMI_TLV_TAG_STRUCT_SET_MULTIPLE_MCAST_FILTER_CMD, + WMI_TLV_TAG_STRUCT_MGMT_TX_COMPL_BUNDLE_EVENT, + WMI_TLV_TAG_STRUCT_READ_DATA_FROM_FLASH_CMD, + WMI_TLV_TAG_STRUCT_READ_DATA_FROM_FLASH_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_SET_REORDER_TIMEOUT_VAL_CMD, + WMI_TLV_TAG_STRUCT_PEER_SET_RX_BLOCKSIZE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_WAKEUP_CONFIG_CMDID, + WMI_TLV_TAG_STRUCT_TLV_BUF_LEN_PARAM, + WMI_TLV_TAG_STRUCT_SERVICE_AVAILABLE_EVENT, + WMI_TLV_TAG_STRUCT_PEER_ANTDIV_INFO_REQ_CMD, + WMI_TLV_TAG_STRUCT_PEER_ANTDIV_INFO_EVENT, + WMI_TLV_TAG_STRUCT_PEER_ANTDIV_INFO, + WMI_TLV_TAG_STRUCT_PDEV_GET_ANTDIV_STATUS_CMD, + WMI_TLV_TAG_STRUCT_PDEV_ANTDIV_STATUS_EVENT, + WMI_TLV_TAG_STRUCT_MNT_FILTER_CMD, + WMI_TLV_TAG_STRUCT_GET_CHIP_POWER_STATS_CMD, + WMI_TLV_TAG_STRUCT_PDEV_CHIP_POWER_STATS_EVENT, + WMI_TLV_TAG_STRUCT_COEX_GET_ANTENNA_ISOLATION_CMD, + WMI_TLV_TAG_STRUCT_COEX_REPORT_ISOLATION_EVENT, + WMI_TLV_TAG_STRUCT_CHAN_CCA_STATS, + WMI_TLV_TAG_STRUCT_PEER_SIGNAL_STATS, + WMI_TLV_TAG_STRUCT_TX_STATS, + WMI_TLV_TAG_STRUCT_PEER_AC_TX_STATS, + WMI_TLV_TAG_STRUCT_RX_STATS, + WMI_TLV_TAG_STRUCT_PEER_AC_RX_STATS, + WMI_TLV_TAG_STRUCT_REPORT_STATS_EVENT, + WMI_TLV_TAG_STRUCT_CHAN_CCA_STATS_THRESH, + WMI_TLV_TAG_STRUCT_PEER_SIGNAL_STATS_THRESH, + WMI_TLV_TAG_STRUCT_TX_STATS_THRESH, + WMI_TLV_TAG_STRUCT_RX_STATS_THRESH, + WMI_TLV_TAG_STRUCT_PDEV_SET_STATS_THRESHOLD_CMD, + WMI_TLV_TAG_STRUCT_REQUEST_WLAN_STATS_CMD, + WMI_TLV_TAG_STRUCT_RX_AGGR_FAILURE_EVENT, + WMI_TLV_TAG_STRUCT_RX_AGGR_FAILURE_INFO, + WMI_TLV_TAG_STRUCT_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMD, + WMI_TLV_TAG_STRUCT_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_BAND_TO_MAC, + WMI_TLV_TAG_STRUCT_TBTT_OFFSET_INFO, + WMI_TLV_TAG_STRUCT_TBTT_OFFSET_EXT_EVENT, + WMI_TLV_TAG_STRUCT_SAR_LIMITS_CMD, + WMI_TLV_TAG_STRUCT_SAR_LIMIT_CMD_ROW, + WMI_TLV_TAG_STRUCT_PDEV_DFS_PHYERR_OFFLOAD_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_DFS_PHYERR_OFFLOAD_DISABLE_CMD, + WMI_TLV_TAG_STRUCT_VDEV_ADFS_CH_CFG_CMD, + WMI_TLV_TAG_STRUCT_VDEV_ADFS_OCAC_ABORT_CMD, + WMI_TLV_TAG_STRUCT_PDEV_DFS_RADAR_DETECTION_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_ADFS_OCAC_COMPLETE_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_DFS_CAC_COMPLETE_EVENT, + WMI_TLV_TAG_STRUCT_VENDOR_OUI, + WMI_TLV_TAG_STRUCT_REQUEST_RCPI_CMD, + WMI_TLV_TAG_STRUCT_UPDATE_RCPI_EVENT, + WMI_TLV_TAG_STRUCT_REQUEST_PEER_STATS_INFO_CMD, + WMI_TLV_TAG_STRUCT_PEER_STATS_INFO, + WMI_TLV_TAG_STRUCT_PEER_STATS_INFO_EVENT, + WMI_TLV_TAG_STRUCT_PKGID_EVENT, + WMI_TLV_TAG_STRUCT_CONNECTED_NLO_RSSI_PARAMS, + WMI_TLV_TAG_STRUCT_SET_CURRENT_COUNTRY_CMD, + WMI_TLV_TAG_STRUCT_REGULATORY_RULE_STRUCT, + WMI_TLV_TAG_STRUCT_REG_CHAN_LIST_CC_EVENT, + WMI_TLV_TAG_STRUCT_11D_SCAN_START_CMD, + WMI_TLV_TAG_STRUCT_11D_SCAN_STOP_CMD, + WMI_TLV_TAG_STRUCT_11D_NEW_COUNTRY_EVENT, + WMI_TLV_TAG_STRUCT_REQUEST_RADIO_CHAN_STATS_CMD, + WMI_TLV_TAG_STRUCT_RADIO_CHAN_STATS, + WMI_TLV_TAG_STRUCT_RADIO_CHAN_STATS_EVENT, + WMI_TLV_TAG_STRUCT_ROAM_PER_CONFIG, + WMI_TLV_TAG_STRUCT_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_CMD, + WMI_TLV_TAG_STRUCT_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_STATUS_EVENT, + WMI_TLV_TAG_STRUCT_BPF_SET_VDEV_ACTIVE_MODE_CMD, + WMI_TLV_TAG_STRUCT_HW_DATA_FILTER_CMD, + WMI_TLV_TAG_STRUCT_CONNECTED_NLO_BSS_BAND_RSSI_PREF, + WMI_TLV_TAG_STRUCT_PEER_OPER_MODE_CHANGE_EVENT, + WMI_TLV_TAG_STRUCT_CHIP_POWER_SAVE_FAILURE_DETECTED, + WMI_TLV_TAG_STRUCT_PDEV_MULTIPLE_VDEV_RESTART_REQUEST_CMD, + WMI_TLV_TAG_STRUCT_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_UPDATE_PKT_ROUTING_CMD, + WMI_TLV_TAG_STRUCT_PDEV_CHECK_CAL_VERSION_CMD, + WMI_TLV_TAG_STRUCT_PDEV_CHECK_CAL_VERSION_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_SET_DIVERSITY_GAIN_CMD, + WMI_TLV_TAG_STRUCT_MAC_PHY_CHAINMASK_COMBO, + WMI_TLV_TAG_STRUCT_MAC_PHY_CHAINMASK_CAPABILITY, + WMI_TLV_TAG_STRUCT_VDEV_SET_ARP_STATS_CMD, + WMI_TLV_TAG_STRUCT_VDEV_GET_ARP_STATS_CMD, + WMI_TLV_TAG_STRUCT_VDEV_GET_ARP_STATS_EVENT, + WMI_TLV_TAG_STRUCT_IFACE_OFFLOAD_STATS, + WMI_TLV_TAG_STRUCT_REQUEST_STATS_CMD_SUB_STRUCT_PARAM, + WMI_TLV_TAG_STRUCT_RSSI_CTL_EXT, + WMI_TLV_TAG_STRUCT_SINGLE_PHYERR_EXT_RX_HDR, + WMI_TLV_TAG_STRUCT_COEX_BT_ACTIVITY_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_GET_TX_POWER_CMD, + WMI_TLV_TAG_STRUCT_VDEV_TX_POWER_EVENT, + WMI_TLV_TAG_STRUCT_OFFCHAN_DATA_TX_COMPL_EVENT, + WMI_TLV_TAG_STRUCT_OFFCHAN_DATA_TX_SEND_CMD, + WMI_TLV_TAG_STRUCT_TX_SEND_PARAMS, + WMI_TLV_TAG_STRUCT_HE_RATE_SET, + WMI_TLV_TAG_STRUCT_CONGESTION_STATS, + WMI_TLV_TAG_STRUCT_SET_INIT_COUNTRY_CMD, + WMI_TLV_TAG_STRUCT_SCAN_DBS_DUTY_CYCLE, + WMI_TLV_TAG_STRUCT_SCAN_DBS_DUTY_CYCLE_PARAM_TLV, + WMI_TLV_TAG_STRUCT_PDEV_DIV_GET_RSSI_ANTID, + WMI_TLV_TAG_STRUCT_THERM_THROT_CONFIG_REQUEST, + WMI_TLV_TAG_STRUCT_THERM_THROT_LEVEL_CONFIG_INFO, + WMI_TLV_TAG_STRUCT_THERM_THROT_STATS_EVENT, + WMI_TLV_TAG_STRUCT_THERM_THROT_LEVEL_STATS_INFO, + WMI_TLV_TAG_STRUCT_PDEV_DIV_RSSI_ANTID_EVENT, + WMI_TLV_TAG_STRUCT_OEM_DMA_RING_CAPABILITIES, + WMI_TLV_TAG_STRUCT_OEM_DMA_RING_CFG_REQ, + WMI_TLV_TAG_STRUCT_OEM_DMA_RING_CFG_RSP, + WMI_TLV_TAG_STRUCT_OEM_INDIRECT_DATA, + WMI_TLV_TAG_STRUCT_OEM_DMA_BUF_RELEASE, + WMI_TLV_TAG_STRUCT_OEM_DMA_BUF_RELEASE_ENTRY, + WMI_TLV_TAG_STRUCT_PDEV_BSS_CHAN_INFO_REQUEST, + WMI_TLV_TAG_STRUCT_PDEV_BSS_CHAN_INFO_EVENT, + WMI_TLV_TAG_STRUCT_ROAM_LCA_DISALLOW_CONFIG_TLV_PARAM, + WMI_TLV_TAG_STRUCT_VDEV_LIMIT_OFFCHAN_CMD, + WMI_TLV_TAG_STRUCT_ROAM_RSSI_REJECTION_OCE_CONFIG_PARAM, + WMI_TLV_TAG_STRUCT_UNIT_TEST_EVENT, + WMI_TLV_TAG_STRUCT_ROAM_FILS_OFFLOAD_TLV_PARAM, + WMI_TLV_TAG_STRUCT_PDEV_UPDATE_PMK_CACHE_CMD, + WMI_TLV_TAG_STRUCT_PMK_CACHE, + WMI_TLV_TAG_STRUCT_PDEV_UPDATE_FILS_HLP_PKT_CMD, + WMI_TLV_TAG_STRUCT_ROAM_FILS_SYNCH_TLV_PARAM, + WMI_TLV_TAG_STRUCT_GTK_OFFLOAD_EXTENDED_TLV_PARAM, + WMI_TLV_TAG_STRUCT_ROAM_BG_SCAN_ROAMING_PARAM, + WMI_TLV_TAG_STRUCT_OIC_PING_OFFLOAD_PARAMS_CMD, + WMI_TLV_TAG_STRUCT_OIC_PING_OFFLOAD_SET_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_OIC_PING_HANDOFF_EVENT, + WMI_TLV_TAG_STRUCT_DHCP_LEASE_RENEW_OFFLOAD_CMD, + WMI_TLV_TAG_STRUCT_DHCP_LEASE_RENEW_EVENT, + WMI_TLV_TAG_STRUCT_BTM_CONFIG, + WMI_TLV_TAG_STRUCT_DEBUG_MESG_FW_DATA_STALL_PARAM, + WMI_TLV_TAG_STRUCT_WLM_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_PDEV_UPDATE_CTLTABLE_REQUEST, + WMI_TLV_TAG_STRUCT_PDEV_UPDATE_CTLTABLE_EVENT, + WMI_TLV_TAG_STRUCT_ROAM_CND_SCORING_PARAM, + WMI_TLV_TAG_STRUCT_PDEV_CONFIG_VENDOR_OUI_ACTION, + WMI_TLV_TAG_STRUCT_VENDOR_OUI_EXT, + WMI_TLV_TAG_STRUCT_ROAM_SYNCH_FRAME_EVENT, + WMI_TLV_TAG_STRUCT_FD_SEND_FROM_HOST_CMD, + WMI_TLV_TAG_STRUCT_ENABLE_FILS_CMD, + WMI_TLV_TAG_STRUCT_HOST_SWFDA_EVENT, WMI_TLV_TAG_MAX }; @@ -1068,16 +1338,74 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_WLAN_STATS_REPORT, WMI_TLV_SERVICE_TX_MSDU_ID_NEW_PARTITION_SUPPORT, WMI_TLV_SERVICE_DFS_PHYERR_OFFLOAD, + WMI_TLV_SERVICE_RCPI_SUPPORT, + WMI_TLV_SERVICE_FW_MEM_DUMP_SUPPORT, + WMI_TLV_SERVICE_PEER_STATS_INFO, + WMI_TLV_SERVICE_REGULATORY_DB, + WMI_TLV_SERVICE_11D_OFFLOAD, + WMI_TLV_SERVICE_HW_DATA_FILTERING, + WMI_TLV_SERVICE_MULTIPLE_VDEV_RESTART, + WMI_TLV_SERVICE_PKT_ROUTING, + WMI_TLV_SERVICE_CHECK_CAL_VERSION, + WMI_TLV_SERVICE_OFFCHAN_TX_WMI, + WMI_TLV_SERVICE_8SS_TX_BFEE, + WMI_TLV_SERVICE_EXTENDED_NSS_SUPPORT, + WMI_TLV_SERVICE_ACK_TIMEOUT, + WMI_TLV_SERVICE_PDEV_BSS_CHANNEL_INFO_64, + WMI_TLV_MAX_SERVICE = 128, + +/* NOTE: + * The above service flags are delivered in the wmi_service_bitmap field + * of the WMI_TLV_SERVICE_READY_EVENT message. + * The below service flags are delivered in a WMI_TLV_SERVICE_AVAILABLE_EVENT + * message rather than in the WMI_TLV_SERVICE_READY_EVENT message's + * wmi_service_bitmap field. + * The WMI_TLV_SERVICE_AVAILABLE_EVENT message immediately precedes the + * WMI_TLV_SERVICE_READY_EVENT message. + */ + + WMI_TLV_SERVICE_CHAN_LOAD_INFO = 128, + WMI_TLV_SERVICE_TX_PPDU_INFO_STATS_SUPPORT, + WMI_TLV_SERVICE_VDEV_LIMIT_OFFCHAN_SUPPORT, + WMI_TLV_SERVICE_FILS_SUPPORT, + WMI_TLV_SERVICE_WLAN_OIC_PING_OFFLOAD, + WMI_TLV_SERVICE_WLAN_DHCP_RENEW, + WMI_TLV_SERVICE_MAWC_SUPPORT, + WMI_TLV_SERVICE_VDEV_LATENCY_CONFIG, + WMI_TLV_SERVICE_PDEV_UPDATE_CTLTABLE_SUPPORT, + WMI_TLV_SERVICE_PKTLOG_SUPPORT_OVER_HTT, + WMI_TLV_SERVICE_VDEV_MULTI_GROUP_KEY_SUPPORT, + WMI_TLV_SERVICE_SCAN_PHYMODE_SUPPORT, + WMI_TLV_SERVICE_THERM_THROT, + WMI_TLV_SERVICE_BCN_OFFLOAD_START_STOP_SUPPORT, + WMI_TLV_SERVICE_WOW_WAKEUP_BY_TIMER_PATTERN, + WMI_TLV_SERVICE_PEER_MAP_UNMAP_V2_SUPPORT = 143, + WMI_TLV_SERVICE_OFFCHAN_DATA_TID_SUPPORT = 144, + WMI_TLV_SERVICE_RX_PROMISC_ENABLE_SUPPORT = 145, + WMI_TLV_SERVICE_SUPPORT_DIRECT_DMA = 146, + WMI_TLV_SERVICE_AP_OBSS_DETECTION_OFFLOAD = 147, + WMI_TLV_SERVICE_11K_NEIGHBOUR_REPORT_SUPPORT = 148, + WMI_TLV_SERVICE_LISTEN_INTERVAL_OFFLOAD_SUPPORT = 149, + WMI_TLV_SERVICE_BSS_COLOR_OFFLOAD = 150, + WMI_TLV_SERVICE_RUNTIME_DPD_RECAL = 151, + WMI_TLV_SERVICE_STA_TWT = 152, + WMI_TLV_SERVICE_AP_TWT = 153, + WMI_TLV_SERVICE_GMAC_OFFLOAD_SUPPORT = 154, + WMI_TLV_SERVICE_SPOOF_MAC_SUPPORT = 155, + + WMI_TLV_MAX_EXT_SERVICE = 256, }; -#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \ - ((svc_id) < (len) && \ - __le32_to_cpu((wmi_svc_bmap)[(svc_id) / (sizeof(u32))]) & \ - BIT((svc_id) % (sizeof(u32)))) +#define WMI_TLV_EXT_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \ + ((svc_id) < (WMI_TLV_MAX_EXT_SERVICE) && \ + (svc_id) >= (len) && \ + __le32_to_cpu((wmi_svc_bmap)[((svc_id) - (len)) / 32]) & \ + BIT(((((svc_id) - (len)) % 32) & 0x1f))) #define SVCMAP(x, y, len) \ do { \ - if (WMI_SERVICE_IS_ENABLED((in), (x), (len))) \ + if ((WMI_SERVICE_IS_ENABLED((in), (x), (len))) || \ + (WMI_TLV_EXT_SERVICE_IS_ENABLED((in), (x), (len)))) \ __set_bit(y, out); \ } while (0) @@ -1228,6 +1556,14 @@ wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len) WMI_SERVICE_MGMT_TX_WMI, len); } +static inline void +wmi_tlv_svc_map_ext(const __le32 *in, unsigned long *out, size_t len) +{ + SVCMAP(WMI_TLV_SERVICE_SPOOF_MAC_SUPPORT, + WMI_SERVICE_SPOOF_MAC_SUPPORT, + WMI_TLV_MAX_SERVICE); +} + #undef SVCMAP struct wmi_tlv { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index e12dd28fcf5d..fa07ef69122b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5059,7 +5059,6 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work) return; } - memset(&ar->wmi.svc_map, 0, sizeof(ar->wmi.svc_map)); ath10k_wmi_map_svc(ar, arg.service_map, ar->wmi.svc_map, arg.service_map_len); @@ -5269,6 +5268,21 @@ int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb) return 0; } +void ath10k_wmi_event_service_available(struct ath10k *ar, struct sk_buff *skb) +{ + int ret; + struct wmi_svc_avail_ev_arg arg = {}; + + ret = ath10k_wmi_pull_svc_avail(ar, skb, &arg); + if (ret) { + ath10k_warn(ar, "failed to parse servive available event: %d\n", + ret); + } + + ath10k_wmi_map_svc_ext(ar, arg.service_map_ext, ar->wmi.svc_map, + __le32_to_cpu(arg.service_map_ext_len)); +} + static int ath10k_wmi_event_temperature(struct ath10k *ar, struct sk_buff *skb) { const struct wmi_pdev_temperature_event *ev; @@ -5465,6 +5479,9 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_event_ready(ar, skb); ath10k_wmi_queue_set_coverage_class_work(ar); break; + case WMI_SERVICE_AVAILABLE_EVENTID: + ath10k_wmi_event_service_available(ar, skb); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; @@ -5880,6 +5897,8 @@ int ath10k_wmi_connect(struct ath10k *ar) struct ath10k_htc_svc_conn_req conn_req; struct ath10k_htc_svc_conn_resp conn_resp; + memset(&ar->wmi.svc_map, 0, sizeof(ar->wmi.svc_map)); + memset(&conn_req, 0, sizeof(conn_req)); memset(&conn_resp, 0, sizeof(conn_resp)); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 3cc129d812a4..7e2f24fdcf1c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -202,6 +202,7 @@ enum wmi_service { WMI_SERVICE_HOST_DFS_CHECK_SUPPORT, WMI_SERVICE_TPC_STATS_FINAL, WMI_SERVICE_RESET_CHIP, + WMI_SERVICE_SPOOF_MAC_SUPPORT, /* keep last */ WMI_SERVICE_MAX, @@ -1190,6 +1191,7 @@ enum wmi_cmd_id { enum wmi_event_id { WMI_SERVICE_READY_EVENTID = 0x1, WMI_READY_EVENTID, + WMI_SERVICE_AVAILABLE_EVENTID, /* Scan specific events */ WMI_SCAN_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_SCAN), @@ -6639,6 +6641,11 @@ struct wmi_svc_rdy_ev_arg { const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS]; }; +struct wmi_svc_avail_ev_arg { + __le32 service_map_ext_len; + const __le32 *service_map_ext; +}; + struct wmi_rdy_ev_arg { __le32 sw_version; __le32 abi_version; @@ -7059,6 +7066,7 @@ void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb); void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb); int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_service_available(struct ath10k *ar, struct sk_buff *skb); int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, const void *phyerr_buf, int left_len, struct wmi_phyerr_ev_arg *arg); void ath10k_wmi_main_op_fw_stats_fill(struct ath10k *ar, -- cgit v1.2.3 From 60e1d0fb290197fe505dff6e4e3b7e4d258dbf60 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Thu, 19 Apr 2018 19:39:40 +0300 Subject: ath10k: support MAC address randomization in scan The ath10k reports the random_mac_addr capability to upper layer based on the service bit firmware reported. Driver sets the spoofed flag in scan_ctrl_flag to firmware if upper layer has enabled this feature in scan request. Test with QCA6174 hw3.0 and firmware-6.bin_WLAN.RM.4.4.1-00102-QCARMSWP-1, but QCA9377 is also affected. Signed-off-by: Carl Huang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 17 +++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-ops.h | 22 ++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 25 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.h | 11 +++++++++++ drivers/net/wireless/ath/ath10k/wmi.c | 5 +++++ drivers/net/wireless/ath/ath10k/wmi.h | 9 +++++++++ 6 files changed, 89 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index fc3320f94f45..c71cf5b81385 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -5717,6 +5717,12 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, arg.scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; } + if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { + arg.scan_ctrl_flags |= WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ; + ether_addr_copy(arg.mac_addr.addr, req->mac_addr); + ether_addr_copy(arg.mac_mask.addr, req->mac_addr_mask); + } + if (req->n_channels) { arg.n_channels = req->n_channels; for (i = 0; i < arg.n_channels; i++) @@ -8433,6 +8439,17 @@ int ath10k_mac_register(struct ath10k *ar) goto err_dfs_detector_exit; } + if (test_bit(WMI_SERVICE_SPOOF_MAC_SUPPORT, ar->wmi.svc_map)) { + ret = ath10k_wmi_scan_prob_req_oui(ar, ar->mac_addr); + if (ret) { + ath10k_err(ar, "failed to set prob req oui: %i\n", ret); + goto err_dfs_detector_exit; + } + + ar->hw->wiphy->features |= + NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; + } + ar->hw->wiphy->cipher_suites = cipher_suites; /* QCA988x and QCA6174 family chips do not support CCMP-256, GCMP-128 diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 4f7e0ba071a2..e37d16b31afe 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -119,6 +119,8 @@ struct wmi_ops { u32 value); struct sk_buff *(*gen_scan_chan_list)(struct ath10k *ar, const struct wmi_scan_chan_list_arg *arg); + struct sk_buff *(*gen_scan_prob_req_oui)(struct ath10k *ar, + u32 prob_req_oui); struct sk_buff *(*gen_beacon_dma)(struct ath10k *ar, u32 vdev_id, const void *bcn, size_t bcn_len, u32 bcn_paddr, bool dtim_zero, @@ -914,6 +916,26 @@ ath10k_wmi_scan_chan_list(struct ath10k *ar, return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid); } +static inline int +ath10k_wmi_scan_prob_req_oui(struct ath10k *ar, const u8 mac_addr[ETH_ALEN]) +{ + struct sk_buff *skb; + u32 prob_req_oui; + + prob_req_oui = (((u32)mac_addr[0]) << 16) | + (((u32)mac_addr[1]) << 8) | mac_addr[2]; + + if (!ar->wmi.ops->gen_scan_prob_req_oui) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_scan_prob_req_oui(ar, prob_req_oui); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->scan_prob_req_oui_cmdid); +} + static inline int ath10k_wmi_peer_assoc(struct ath10k *ar, const struct wmi_peer_assoc_complete_arg *arg) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 31866e3b74fc..01f4eb201330 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1636,6 +1636,8 @@ ath10k_wmi_tlv_op_gen_start_scan(struct ath10k *ar, cmd->num_bssids = __cpu_to_le32(arg->n_bssids); cmd->ie_len = __cpu_to_le32(arg->ie_len); cmd->num_probes = __cpu_to_le32(3); + ether_addr_copy(cmd->mac_addr.addr, arg->mac_addr.addr); + ether_addr_copy(cmd->mac_mask.addr, arg->mac_mask.addr); /* FIXME: There are some scan flag inconsistencies across firmwares, * e.g. WMI-TLV inverts the logic behind the following flag. @@ -2482,6 +2484,27 @@ ath10k_wmi_tlv_op_gen_scan_chan_list(struct ath10k *ar, return skb; } +static struct sk_buff * +ath10k_wmi_tlv_op_gen_scan_prob_req_oui(struct ath10k *ar, u32 prob_req_oui) +{ + struct wmi_scan_prob_req_oui_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_SCAN_PROB_REQ_OUI_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->prob_req_oui = __cpu_to_le32(prob_req_oui); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv scan prob req oui\n"); + return skb; +} + static struct sk_buff * ath10k_wmi_tlv_op_gen_beacon_dma(struct ath10k *ar, u32 vdev_id, const void *bcn, size_t bcn_len, @@ -3452,6 +3475,7 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = { .stop_scan_cmdid = WMI_TLV_STOP_SCAN_CMDID, .scan_chan_list_cmdid = WMI_TLV_SCAN_CHAN_LIST_CMDID, .scan_sch_prio_tbl_cmdid = WMI_TLV_SCAN_SCH_PRIO_TBL_CMDID, + .scan_prob_req_oui_cmdid = WMI_TLV_SCAN_PROB_REQ_OUI_CMDID, .pdev_set_regdomain_cmdid = WMI_TLV_PDEV_SET_REGDOMAIN_CMDID, .pdev_set_channel_cmdid = WMI_TLV_PDEV_SET_CHANNEL_CMDID, .pdev_set_param_cmdid = WMI_TLV_PDEV_SET_PARAM_CMDID, @@ -3820,6 +3844,7 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_set_sta_ps = ath10k_wmi_tlv_op_gen_set_sta_ps, .gen_set_ap_ps = ath10k_wmi_tlv_op_gen_set_ap_ps, .gen_scan_chan_list = ath10k_wmi_tlv_op_gen_scan_chan_list, + .gen_scan_prob_req_oui = ath10k_wmi_tlv_op_gen_scan_prob_req_oui, .gen_beacon_dma = ath10k_wmi_tlv_op_gen_beacon_dma, .gen_pdev_set_wmm = ath10k_wmi_tlv_op_gen_pdev_set_wmm, .gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats, diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 529b91b17061..954c50bb3f66 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1706,6 +1706,15 @@ struct wmi_tlv_scan_chan_list_cmd { __le32 num_scan_chans; } __packed; +struct wmi_scan_prob_req_oui_cmd { +/* OUI to be used in Probe Request frame when random MAC address is + * requested part of scan parameters. This is applied to both FW internal + * scans and host initiated scans. Host can request for random MAC address + * with WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ flag. + */ + __le32 prob_req_oui; +} __packed; + struct wmi_tlv_start_scan_cmd { struct wmi_start_scan_common common; __le32 burst_duration_ms; @@ -1714,6 +1723,8 @@ struct wmi_tlv_start_scan_cmd { __le32 num_ssids; __le32 ie_len; __le32 num_probes; + struct wmi_mac_addr mac_addr; + struct wmi_mac_addr mac_mask; } __packed; struct wmi_tlv_vdev_start_cmd { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index fa07ef69122b..df2e92a6c9bd 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -42,6 +42,7 @@ static struct wmi_cmd_map wmi_cmd_map = { .stop_scan_cmdid = WMI_STOP_SCAN_CMDID, .scan_chan_list_cmdid = WMI_SCAN_CHAN_LIST_CMDID, .scan_sch_prio_tbl_cmdid = WMI_SCAN_SCH_PRIO_TBL_CMDID, + .scan_prob_req_oui_cmdid = WMI_CMD_UNSUPPORTED, .pdev_set_regdomain_cmdid = WMI_PDEV_SET_REGDOMAIN_CMDID, .pdev_set_channel_cmdid = WMI_PDEV_SET_CHANNEL_CMDID, .pdev_set_param_cmdid = WMI_PDEV_SET_PARAM_CMDID, @@ -207,6 +208,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = { .stop_scan_cmdid = WMI_10X_STOP_SCAN_CMDID, .scan_chan_list_cmdid = WMI_10X_SCAN_CHAN_LIST_CMDID, .scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED, + .scan_prob_req_oui_cmdid = WMI_CMD_UNSUPPORTED, .pdev_set_regdomain_cmdid = WMI_10X_PDEV_SET_REGDOMAIN_CMDID, .pdev_set_channel_cmdid = WMI_10X_PDEV_SET_CHANNEL_CMDID, .pdev_set_param_cmdid = WMI_10X_PDEV_SET_PARAM_CMDID, @@ -374,6 +376,7 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = { .stop_scan_cmdid = WMI_10_2_STOP_SCAN_CMDID, .scan_chan_list_cmdid = WMI_10_2_SCAN_CHAN_LIST_CMDID, .scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED, + .scan_prob_req_oui_cmdid = WMI_CMD_UNSUPPORTED, .pdev_set_regdomain_cmdid = WMI_10_2_PDEV_SET_REGDOMAIN_CMDID, .pdev_set_channel_cmdid = WMI_10_2_PDEV_SET_CHANNEL_CMDID, .pdev_set_param_cmdid = WMI_10_2_PDEV_SET_PARAM_CMDID, @@ -541,6 +544,7 @@ static struct wmi_cmd_map wmi_10_4_cmd_map = { .stop_scan_cmdid = WMI_10_4_STOP_SCAN_CMDID, .scan_chan_list_cmdid = WMI_10_4_SCAN_CHAN_LIST_CMDID, .scan_sch_prio_tbl_cmdid = WMI_10_4_SCAN_SCH_PRIO_TBL_CMDID, + .scan_prob_req_oui_cmdid = WMI_CMD_UNSUPPORTED, .pdev_set_regdomain_cmdid = WMI_10_4_PDEV_SET_REGDOMAIN_CMDID, .pdev_set_channel_cmdid = WMI_10_4_PDEV_SET_CHANNEL_CMDID, .pdev_set_param_cmdid = WMI_10_4_PDEV_SET_PARAM_CMDID, @@ -1338,6 +1342,7 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = { .stop_scan_cmdid = WMI_10_2_STOP_SCAN_CMDID, .scan_chan_list_cmdid = WMI_10_2_SCAN_CHAN_LIST_CMDID, .scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED, + .scan_prob_req_oui_cmdid = WMI_CMD_UNSUPPORTED, .pdev_set_regdomain_cmdid = WMI_10_2_PDEV_SET_REGDOMAIN_CMDID, .pdev_set_channel_cmdid = WMI_10_2_PDEV_SET_CHANNEL_CMDID, .pdev_set_param_cmdid = WMI_10_2_PDEV_SET_PARAM_CMDID, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 7e2f24fdcf1c..2705973e39c6 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -791,6 +791,7 @@ struct wmi_cmd_map { u32 stop_scan_cmdid; u32 scan_chan_list_cmdid; u32 scan_sch_prio_tbl_cmdid; + u32 scan_prob_req_oui_cmdid; u32 pdev_set_regdomain_cmdid; u32 pdev_set_channel_cmdid; u32 pdev_set_param_cmdid; @@ -3168,6 +3169,8 @@ struct wmi_start_scan_arg { u16 channels[64]; struct wmi_ssid_arg ssids[WLAN_SCAN_PARAMS_MAX_SSID]; struct wmi_bssid_arg bssids[WLAN_SCAN_PARAMS_MAX_BSSID]; + struct wmi_mac_addr mac_addr; + struct wmi_mac_addr mac_mask; }; /* scan control flags */ @@ -3191,6 +3194,12 @@ struct wmi_start_scan_arg { */ #define WMI_SCAN_CONTINUE_ON_ERROR 0x80 +/* Use random MAC address for TA for Probe Request frame and add + * OUI specified by WMI_SCAN_PROB_REQ_OUI_CMDID to the Probe Request frame. + * if OUI is not set by WMI_SCAN_PROB_REQ_OUI_CMDID then the flag is ignored. + */ +#define WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ 0x1000 + /* WMI_SCAN_CLASS_MASK must be the same value as IEEE80211_SCAN_CLASS_MASK */ #define WMI_SCAN_CLASS_MASK 0xFF000000 -- cgit v1.2.3 From fa3440fa2fa1531fb2aafb6d51f2bc5ac70a6247 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 19 Apr 2018 19:40:07 +0300 Subject: ath10k: convert wow pattern from 802.3 to 802.11 When trying to set wow wakeup patterns it fails with this command: iw phyxx wowlan enable patterns offset xx+ IP address xx.xx.xx.xx The reason is that the wow pattern from upper layer is in 802.3 format for this case, it need to convert it to 802.11 format. The input offset parameter is used for 802.3, but the actual offset firmware need depends on rx_decap_mode, so that it needs to be recalculated. Pattern of 802.3 packet is not same with 802.11 packet. If the rx_decap_mode is ATH10K_HW_TXRX_NATIVE_WIFI, then firmware will receive data packet with 802.11 format from hardware. Tested with QCA6174 hw3.0 with firmware WLAN.RM.4.4.1-00099-QCARMSWPZ-1, but this will also affect QCA9377. This has always failed, so it's not a regression with new firmware releases. Signed-off-by: Wen Gong Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.h | 4 + drivers/net/wireless/ath/ath10k/wow.c | 138 ++++++++++++++++++++++++++++++++-- 2 files changed, 137 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 2705973e39c6..16a39244a34f 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -6835,6 +6835,10 @@ struct wmi_wow_ev_arg { #define WOW_MIN_PATTERN_SIZE 1 #define WOW_MAX_PATTERN_SIZE 148 #define WOW_MAX_PKT_OFFSET 128 +#define WOW_HDR_LEN (sizeof(struct ieee80211_hdr_3addr) + \ + sizeof(struct rfc1042_hdr)) +#define WOW_MAX_REDUCE (WOW_HDR_LEN - sizeof(struct ethhdr) - \ + offsetof(struct ieee80211_hdr_3addr, addr1)) enum wmi_tdls_state { WMI_TDLS_DISABLE, diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c index c4cbccb29b31..a6b179f88d36 100644 --- a/drivers/net/wireless/ath/ath10k/wow.c +++ b/drivers/net/wireless/ath/ath10k/wow.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2015-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -76,6 +77,109 @@ static int ath10k_wow_cleanup(struct ath10k *ar) return 0; } +/** + * Convert a 802.3 format to a 802.11 format. + * +------------+-----------+--------+----------------+ + * 802.3: |dest mac(6B)|src mac(6B)|type(2B)| body... | + * +------------+-----------+--------+----------------+ + * |__ |_______ |____________ |________ + * | | | | + * +--+------------+----+-----------+---------------+-----------+ + * 802.11: |4B|dest mac(6B)| 6B |src mac(6B)| 8B |type(2B)| body... | + * +--+------------+----+-----------+---------------+-----------+ + */ +static void ath10k_wow_convert_8023_to_80211 + (struct cfg80211_pkt_pattern *new, + const struct cfg80211_pkt_pattern *old) +{ + u8 hdr_8023_pattern[ETH_HLEN] = {}; + u8 hdr_8023_bit_mask[ETH_HLEN] = {}; + u8 hdr_80211_pattern[WOW_HDR_LEN] = {}; + u8 hdr_80211_bit_mask[WOW_HDR_LEN] = {}; + + int total_len = old->pkt_offset + old->pattern_len; + int hdr_80211_end_offset; + + struct ieee80211_hdr_3addr *new_hdr_pattern = + (struct ieee80211_hdr_3addr *)hdr_80211_pattern; + struct ieee80211_hdr_3addr *new_hdr_mask = + (struct ieee80211_hdr_3addr *)hdr_80211_bit_mask; + struct ethhdr *old_hdr_pattern = (struct ethhdr *)hdr_8023_pattern; + struct ethhdr *old_hdr_mask = (struct ethhdr *)hdr_8023_bit_mask; + int hdr_len = sizeof(*new_hdr_pattern); + + struct rfc1042_hdr *new_rfc_pattern = + (struct rfc1042_hdr *)(hdr_80211_pattern + hdr_len); + struct rfc1042_hdr *new_rfc_mask = + (struct rfc1042_hdr *)(hdr_80211_bit_mask + hdr_len); + int rfc_len = sizeof(*new_rfc_pattern); + + memcpy(hdr_8023_pattern + old->pkt_offset, + old->pattern, ETH_HLEN - old->pkt_offset); + memcpy(hdr_8023_bit_mask + old->pkt_offset, + old->mask, ETH_HLEN - old->pkt_offset); + + /* Copy destination address */ + memcpy(new_hdr_pattern->addr1, old_hdr_pattern->h_dest, ETH_ALEN); + memcpy(new_hdr_mask->addr1, old_hdr_mask->h_dest, ETH_ALEN); + + /* Copy source address */ + memcpy(new_hdr_pattern->addr3, old_hdr_pattern->h_source, ETH_ALEN); + memcpy(new_hdr_mask->addr3, old_hdr_mask->h_source, ETH_ALEN); + + /* Copy logic link type */ + memcpy(&new_rfc_pattern->snap_type, + &old_hdr_pattern->h_proto, + sizeof(old_hdr_pattern->h_proto)); + memcpy(&new_rfc_mask->snap_type, + &old_hdr_mask->h_proto, + sizeof(old_hdr_mask->h_proto)); + + /* Caculate new pkt_offset */ + if (old->pkt_offset < ETH_ALEN) + new->pkt_offset = old->pkt_offset + + offsetof(struct ieee80211_hdr_3addr, addr1); + else if (old->pkt_offset < offsetof(struct ethhdr, h_proto)) + new->pkt_offset = old->pkt_offset + + offsetof(struct ieee80211_hdr_3addr, addr3) - + offsetof(struct ethhdr, h_source); + else + new->pkt_offset = old->pkt_offset + hdr_len + rfc_len - ETH_HLEN; + + /* Caculate new hdr end offset */ + if (total_len > ETH_HLEN) + hdr_80211_end_offset = hdr_len + rfc_len; + else if (total_len > offsetof(struct ethhdr, h_proto)) + hdr_80211_end_offset = hdr_len + rfc_len + total_len - ETH_HLEN; + else if (total_len > ETH_ALEN) + hdr_80211_end_offset = total_len - ETH_ALEN + + offsetof(struct ieee80211_hdr_3addr, addr3); + else + hdr_80211_end_offset = total_len + + offsetof(struct ieee80211_hdr_3addr, addr1); + + new->pattern_len = hdr_80211_end_offset - new->pkt_offset; + + memcpy((u8 *)new->pattern, + hdr_80211_pattern + new->pkt_offset, + new->pattern_len); + memcpy((u8 *)new->mask, + hdr_80211_bit_mask + new->pkt_offset, + new->pattern_len); + + if (total_len > ETH_HLEN) { + /* Copy frame body */ + memcpy((u8 *)new->pattern + new->pattern_len, + (void *)old->pattern + ETH_HLEN - old->pkt_offset, + total_len - ETH_HLEN); + memcpy((u8 *)new->mask + new->pattern_len, + (void *)old->mask + ETH_HLEN - old->pkt_offset, + total_len - ETH_HLEN); + + new->pattern_len += total_len - ETH_HLEN; + } +} + static int ath10k_vif_wow_set_wakeups(struct ath10k_vif *arvif, struct cfg80211_wowlan *wowlan) { @@ -116,22 +220,40 @@ static int ath10k_vif_wow_set_wakeups(struct ath10k_vif *arvif, for (i = 0; i < wowlan->n_patterns; i++) { u8 bitmask[WOW_MAX_PATTERN_SIZE] = {}; + u8 ath_pattern[WOW_MAX_PATTERN_SIZE] = {}; + u8 ath_bitmask[WOW_MAX_PATTERN_SIZE] = {}; + struct cfg80211_pkt_pattern new_pattern = {}; + struct cfg80211_pkt_pattern old_pattern = patterns[i]; int j; + new_pattern.pattern = ath_pattern; + new_pattern.mask = ath_bitmask; if (patterns[i].pattern_len > WOW_MAX_PATTERN_SIZE) continue; - /* convert bytemask to bitmask */ for (j = 0; j < patterns[i].pattern_len; j++) if (patterns[i].mask[j / 8] & BIT(j % 8)) bitmask[j] = 0xff; + old_pattern.mask = bitmask; + new_pattern = old_pattern; + + if (ar->wmi.rx_decap_mode == ATH10K_HW_TXRX_NATIVE_WIFI) { + if (patterns[i].pkt_offset < ETH_HLEN) + ath10k_wow_convert_8023_to_80211(&new_pattern, + &old_pattern); + else + new_pattern.pkt_offset += WOW_HDR_LEN - ETH_HLEN; + } + + if (WARN_ON(new_pattern.pattern_len > WOW_MAX_PATTERN_SIZE)) + return -EINVAL; ret = ath10k_wmi_wow_add_pattern(ar, arvif->vdev_id, pattern_id, - patterns[i].pattern, - bitmask, - patterns[i].pattern_len, - patterns[i].pkt_offset); + new_pattern.pattern, + new_pattern.mask, + new_pattern.pattern_len, + new_pattern.pkt_offset); if (ret) { ath10k_warn(ar, "failed to add pattern %i to vdev %i: %d\n", pattern_id, @@ -345,6 +467,12 @@ int ath10k_wow_init(struct ath10k *ar) return -EINVAL; ar->wow.wowlan_support = ath10k_wowlan_support; + + if (ar->wmi.rx_decap_mode == ATH10K_HW_TXRX_NATIVE_WIFI) { + ar->wow.wowlan_support.pattern_max_len -= WOW_MAX_REDUCE; + ar->wow.wowlan_support.max_pkt_offset -= WOW_MAX_REDUCE; + } + ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns; ar->hw->wiphy->wowlan = &ar->wow.wowlan_support; -- cgit v1.2.3 From 0fc8bb50bbfc82d113218c803e1965838dcdbc89 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 19 Apr 2018 19:40:11 +0300 Subject: wcn36xx: pass correct BSS index when deleting BSS keys The firmware message to delete BSS keys expects a BSS index to be passed. This field is currently hard-coded to 0. Fix this by passing in the index we received from the firmware when the BSS was configured. The encryption type in that message also needs to be set to what was used when the key was set, so the assignment of vif_priv->encrypt_type is now done after the firmware command was sent. This reportedly fixes the following error in AP mode: wcn36xx: ERROR hal_remove_bsskey response failed err=6 Also, AFAIU, when a BSS is deleted, the firmware apparently drops all the keys associated with it. Trying to remove the key explicitly afterwards will hence lead to the following message: wcn36xx: ERROR hal_remove_bsskey response failed err=16 This is now suppressed with an extra check for the BSS index validity. Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/main.c | 10 +++++++--- drivers/net/wireless/ath/wcn36xx/smd.c | 6 ++++-- drivers/net/wireless/ath/wcn36xx/smd.h | 2 ++ 3 files changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 32bbd6e2fd09..749aef3e2b85 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -549,6 +549,7 @@ static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } else { wcn36xx_smd_set_bsskey(wcn, vif_priv->encrypt_type, + vif_priv->bss_index, key_conf->keyidx, key_conf->keylen, key); @@ -566,10 +567,13 @@ static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, break; case DISABLE_KEY: if (!(IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags)) { + if (vif_priv->bss_index != WCN36XX_HAL_BSS_INVALID_IDX) + wcn36xx_smd_remove_bsskey(wcn, + vif_priv->encrypt_type, + vif_priv->bss_index, + key_conf->keyidx); + vif_priv->encrypt_type = WCN36XX_HAL_ED_NONE; - wcn36xx_smd_remove_bsskey(wcn, - vif_priv->encrypt_type, - key_conf->keyidx); } else { sta_priv->is_data_encrypted = false; /* do not remove key if disassociated */ diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 9827a1e1124b..297a785d0785 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -1636,6 +1636,7 @@ out: int wcn36xx_smd_set_bsskey(struct wcn36xx *wcn, enum ani_ed_type enc_type, + u8 bssidx, u8 keyidx, u8 keylen, u8 *key) @@ -1645,7 +1646,7 @@ int wcn36xx_smd_set_bsskey(struct wcn36xx *wcn, mutex_lock(&wcn->hal_mutex); INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_BSSKEY_REQ); - msg_body.bss_idx = 0; + msg_body.bss_idx = bssidx; msg_body.enc_type = enc_type; msg_body.num_keys = 1; msg_body.keys[0].id = keyidx; @@ -1706,6 +1707,7 @@ out: int wcn36xx_smd_remove_bsskey(struct wcn36xx *wcn, enum ani_ed_type enc_type, + u8 bssidx, u8 keyidx) { struct wcn36xx_hal_remove_bss_key_req_msg msg_body; @@ -1713,7 +1715,7 @@ int wcn36xx_smd_remove_bsskey(struct wcn36xx *wcn, mutex_lock(&wcn->hal_mutex); INIT_HAL_MSG(msg_body, WCN36XX_HAL_RMV_BSSKEY_REQ); - msg_body.bss_idx = 0; + msg_body.bss_idx = bssidx; msg_body.enc_type = enc_type; msg_body.key_id = keyidx; diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h index 8076edf40ac8..61bb8d43138c 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.h +++ b/drivers/net/wireless/ath/wcn36xx/smd.h @@ -97,6 +97,7 @@ int wcn36xx_smd_set_stakey(struct wcn36xx *wcn, u8 sta_index); int wcn36xx_smd_set_bsskey(struct wcn36xx *wcn, enum ani_ed_type enc_type, + u8 bssidx, u8 keyidx, u8 keylen, u8 *key); @@ -106,6 +107,7 @@ int wcn36xx_smd_remove_stakey(struct wcn36xx *wcn, u8 sta_index); int wcn36xx_smd_remove_bsskey(struct wcn36xx *wcn, enum ani_ed_type enc_type, + u8 bssidx, u8 keyidx); int wcn36xx_smd_enter_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif); int wcn36xx_smd_exit_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif); -- cgit v1.2.3 From 20529b33aa12224e4399b4486e5ab617cf8f3e5e Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Tue, 17 Apr 2018 14:54:26 +0530 Subject: ath10k: enable hw checksum for wcn3990 By default ath10k driver enables the support for HW_CHECKSUM (NETIF_F_HW_CSUM). Since the TCP/UDP checksum calculation is not enabled in the wcn3990 firmware the checksum is incorrect in the TCP/UDP packets and all patckets are dropped. But due note that wcn3990 support in ath10k is still incomplete so this isn't a critical fix (yet). Enable hw checksum calculations in wcn3990 hardware by setting the proper flags in msdu descriptor tso flags. Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.h | 13 +++++++++++++ drivers/net/wireless/ath/ath10k/htt_tx.c | 7 +++++-- 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 4e5fe539eb77..5d3ff80f3a1f 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -128,6 +128,19 @@ struct htt_msdu_ext_desc_64 { | HTT_MSDU_EXT_DESC_FLAG_TCP_IPV4_CSUM_ENABLE \ | HTT_MSDU_EXT_DESC_FLAG_TCP_IPV6_CSUM_ENABLE) +#define HTT_MSDU_EXT_DESC_FLAG_IPV4_CSUM_ENABLE_64 BIT(16) +#define HTT_MSDU_EXT_DESC_FLAG_UDP_IPV4_CSUM_ENABLE_64 BIT(17) +#define HTT_MSDU_EXT_DESC_FLAG_UDP_IPV6_CSUM_ENABLE_64 BIT(18) +#define HTT_MSDU_EXT_DESC_FLAG_TCP_IPV4_CSUM_ENABLE_64 BIT(19) +#define HTT_MSDU_EXT_DESC_FLAG_TCP_IPV6_CSUM_ENABLE_64 BIT(20) +#define HTT_MSDU_EXT_DESC_FLAG_PARTIAL_CSUM_ENABLE_64 BIT(21) + +#define HTT_MSDU_CHECKSUM_ENABLE_64 (HTT_MSDU_EXT_DESC_FLAG_IPV4_CSUM_ENABLE_64 \ + | HTT_MSDU_EXT_DESC_FLAG_UDP_IPV4_CSUM_ENABLE_64 \ + | HTT_MSDU_EXT_DESC_FLAG_UDP_IPV6_CSUM_ENABLE_64 \ + | HTT_MSDU_EXT_DESC_FLAG_TCP_IPV4_CSUM_ENABLE_64 \ + | HTT_MSDU_EXT_DESC_FLAG_TCP_IPV6_CSUM_ENABLE_64) + enum htt_data_tx_desc_flags0 { HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT = 1 << 0, HTT_DATA_TX_DESC_FLAGS0_NO_AGGR = 1 << 1, diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index a086958c39b6..5d8b97a0ccaa 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -1475,8 +1475,11 @@ static int ath10k_htt_tx_64(struct ath10k_htt *htt, !test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; - if (ar->hw_params.continuous_frag_desc) - ext_desc->flags |= HTT_MSDU_CHECKSUM_ENABLE; + if (ar->hw_params.continuous_frag_desc) { + memset(ext_desc->tso_flag, 0, sizeof(ext_desc->tso_flag)); + ext_desc->tso_flag[3] |= + __cpu_to_le32(HTT_MSDU_CHECKSUM_ENABLE_64); + } } /* Prevent firmware from sending up tx inspection requests. There's -- cgit v1.2.3 From b2e40d7ab8e2d36b455113df96dcbab0407e35c0 Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Tue, 17 Apr 2018 17:36:58 +0530 Subject: ath10k: add hw params for shadow register support wcn3990 supports shadow register for ce write. Add a hw param for shadow register support. Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 14 ++++++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 4 ++++ 2 files changed, 18 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 64674d8ce457..a8bb21173d2c 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -90,6 +90,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, + .shadow_reg_support = false, }, { .id = QCA988X_HW_2_0_VERSION, @@ -120,6 +121,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA9887_HW_1_0_VERSION, @@ -150,6 +152,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -179,6 +182,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -208,6 +212,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA6174_HW_3_0_VERSION, @@ -237,6 +242,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA6174_HW_3_2_VERSION, @@ -269,6 +275,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA99X0_HW_2_0_DEV_VERSION, @@ -304,6 +311,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA9984_HW_1_0_DEV_VERSION, @@ -344,6 +352,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA9888_HW_2_0_DEV_VERSION, @@ -383,6 +392,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA9377_HW_1_0_DEV_VERSION, @@ -412,6 +422,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA9377_HW_1_1_DEV_VERSION, @@ -443,6 +454,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = QCA4019_HW_1_0_DEV_VERSION, @@ -479,6 +491,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, + .shadow_reg_support = false, }, { .id = WCN3990_HW_1_0_DEV_VERSION, @@ -500,6 +513,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = true, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL_DUAL_MAC, .per_ce_irq = true, + .shadow_reg_support = true, }, }; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index b025a1bf2fde..dcefde76956c 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -571,6 +572,9 @@ struct ath10k_hw_params { /* target supporting per ce IRQ */ bool per_ce_irq; + + /* target supporting shadow register for ce write */ + bool shadow_reg_support; }; struct htt_rx_desc; -- cgit v1.2.3 From b7ba83f7c414e583fdf82a1b1b95d2376cdb4b45 Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Tue, 17 Apr 2018 17:36:59 +0530 Subject: ath10k: add support for shadow register for WNC3990 WCN3990 needs shadow register write operation support for copy engine for regular operation in powersave mode. Add support for copy engine shadow register write in datapath tx for WCN3990 Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 143 ++++++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/ce.h | 4 + 2 files changed, 145 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 3a15923bdd26..020405b6d408 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -58,6 +59,74 @@ * the buffer is sent/received. */ +static inline u32 shadow_sr_wr_ind_addr(struct ath10k *ar, + struct ath10k_ce_pipe *ce_state) +{ + u32 ce_id = ce_state->id; + u32 addr = 0; + + switch (ce_id) { + case 0: + addr = 0x00032000; + break; + case 3: + addr = 0x0003200C; + break; + case 4: + addr = 0x00032010; + break; + case 5: + addr = 0x00032014; + break; + case 7: + addr = 0x0003201C; + break; + default: + ath10k_warn(ar, "invalid CE id: %d", ce_id); + break; + } + return addr; +} + +static inline u32 shadow_dst_wr_ind_addr(struct ath10k *ar, + struct ath10k_ce_pipe *ce_state) +{ + u32 ce_id = ce_state->id; + u32 addr = 0; + + switch (ce_id) { + case 1: + addr = 0x00032034; + break; + case 2: + addr = 0x00032038; + break; + case 5: + addr = 0x00032044; + break; + case 7: + addr = 0x0003204C; + break; + case 8: + addr = 0x00032050; + break; + case 9: + addr = 0x00032054; + break; + case 10: + addr = 0x00032058; + break; + case 11: + addr = 0x0003205C; + break; + default: + ath10k_warn(ar, "invalid CE id: %d", ce_id); + break; + } + + return addr; +} + static inline unsigned int ath10k_set_ring_byte(unsigned int offset, struct ath10k_hw_ce_regs_addr_map *addr_map) @@ -123,6 +192,22 @@ static inline u32 ath10k_ce_src_ring_read_index_get(struct ath10k *ar, ar->hw_ce_regs->current_srri_addr); } +static inline void +ath10k_ce_shadow_src_ring_write_index_set(struct ath10k *ar, + struct ath10k_ce_pipe *ce_state, + unsigned int value) +{ + ath10k_ce_write32(ar, shadow_sr_wr_ind_addr(ar, ce_state), value); +} + +static inline void +ath10k_ce_shadow_dest_ring_write_index_set(struct ath10k *ar, + struct ath10k_ce_pipe *ce_state, + unsigned int value) +{ + ath10k_ce_write32(ar, shadow_dst_wr_ind_addr(ar, ce_state), value); +} + static inline void ath10k_ce_src_ring_base_addr_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int addr) @@ -376,8 +461,14 @@ static int _ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, write_index = CE_RING_IDX_INCR(nentries_mask, write_index); /* WORKAROUND */ - if (!(flags & CE_SEND_FLAG_GATHER)) - ath10k_ce_src_ring_write_index_set(ar, ctrl_addr, write_index); + if (!(flags & CE_SEND_FLAG_GATHER)) { + if (ar->hw_params.shadow_reg_support) + ath10k_ce_shadow_src_ring_write_index_set(ar, ce_state, + write_index); + else + ath10k_ce_src_ring_write_index_set(ar, ctrl_addr, + write_index); + } src_ring->write_index = write_index; exit: @@ -1251,6 +1342,22 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar, return 0; } +static int ath10k_ce_alloc_shadow_base(struct ath10k *ar, + struct ath10k_ce_ring *src_ring, + u32 nentries) +{ + src_ring->shadow_base_unaligned = kcalloc(nentries, + sizeof(struct ce_desc), + GFP_KERNEL); + if (!src_ring->shadow_base_unaligned) + return -ENOMEM; + + src_ring->shadow_base = (struct ce_desc *) + PTR_ALIGN(src_ring->shadow_base_unaligned, + CE_DESC_RING_ALIGN); + return 0; +} + static struct ath10k_ce_ring * ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id, const struct ce_attr *attr) @@ -1258,6 +1365,7 @@ ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id, struct ath10k_ce_ring *src_ring; u32 nentries = attr->src_nentries; dma_addr_t base_addr; + int ret; nentries = roundup_pow_of_two(nentries); @@ -1294,6 +1402,19 @@ ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id, ALIGN(src_ring->base_addr_ce_space_unaligned, CE_DESC_RING_ALIGN); + if (ar->hw_params.shadow_reg_support) { + ret = ath10k_ce_alloc_shadow_base(ar, src_ring, nentries); + if (ret) { + dma_free_coherent(ar->dev, + (nentries * sizeof(struct ce_desc) + + CE_DESC_RING_ALIGN), + src_ring->base_addr_owner_space_unaligned, + base_addr); + kfree(src_ring); + return ERR_PTR(ret); + } + } + return src_ring; } @@ -1304,6 +1425,7 @@ ath10k_ce_alloc_src_ring_64(struct ath10k *ar, unsigned int ce_id, struct ath10k_ce_ring *src_ring; u32 nentries = attr->src_nentries; dma_addr_t base_addr; + int ret; nentries = roundup_pow_of_two(nentries); @@ -1339,6 +1461,19 @@ ath10k_ce_alloc_src_ring_64(struct ath10k *ar, unsigned int ce_id, ALIGN(src_ring->base_addr_ce_space_unaligned, CE_DESC_RING_ALIGN); + if (ar->hw_params.shadow_reg_support) { + ret = ath10k_ce_alloc_shadow_base(ar, src_ring, nentries); + if (ret) { + dma_free_coherent(ar->dev, + (nentries * sizeof(struct ce_desc) + + CE_DESC_RING_ALIGN), + src_ring->base_addr_owner_space_unaligned, + base_addr); + kfree(src_ring); + return ERR_PTR(ret); + } + } + return src_ring; } @@ -1505,6 +1640,8 @@ static void _ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id]; if (ce_state->src_ring) { + if (ar->hw_params.shadow_reg_support) + kfree(ce_state->src_ring->shadow_base_unaligned); dma_free_coherent(ar->dev, (ce_state->src_ring->nentries * sizeof(struct ce_desc) + @@ -1534,6 +1671,8 @@ static void _ath10k_ce_free_pipe_64(struct ath10k *ar, int ce_id) struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id]; if (ce_state->src_ring) { + if (ar->hw_params.shadow_reg_support) + kfree(ce_state->src_ring->shadow_base_unaligned); dma_free_coherent(ar->dev, (ce_state->src_ring->nentries * sizeof(struct ce_desc_64) + diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index d8f9da334529..9aea89133209 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -113,6 +114,9 @@ struct ath10k_ce_ring { /* CE address space */ u32 base_addr_ce_space; + char *shadow_base_unaligned; + struct ce_desc *shadow_base; + /* keep last */ void *per_transfer_context[0]; }; -- cgit v1.2.3 From 4945af5b264fbdbdb5a9021b8a6a179d0c7a33b2 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 17 Apr 2018 17:37:00 +0530 Subject: ath10k: enable SRRI/DRRI support on ddr for WCN3990 SRRI/DRRI are not mapped in the HW Shadow block and can lead to un-clocked access if common subsystem in the target is powered down due to idle mode. To mitigate this problem SRRI/DRRI can be read from DDR instead of doing an actual hardware read. Host allocates non cached memory on ddr and configures the physical address of this memory to the CE hardware. The hardware updates the RRI on this particular location. Read SRRI/DRRI from DDR location instead of direct target read. Enable retention restore on ddr using hw params to enable in specific targets. Signed-off-by: Govind Singh Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 102 +++++++++++++++++++++++++++++++-- drivers/net/wireless/ath/ath10k/ce.h | 10 ++++ drivers/net/wireless/ath/ath10k/core.c | 14 +++++ drivers/net/wireless/ath/ath10k/hw.c | 9 ++- drivers/net/wireless/ath/ath10k/hw.h | 13 ++++- drivers/net/wireless/ath/ath10k/snoc.c | 3 + 6 files changed, 142 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 020405b6d408..3b96a43fbda4 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -185,11 +185,30 @@ static inline u32 ath10k_ce_src_ring_write_index_get(struct ath10k *ar, ar->hw_ce_regs->sr_wr_index_addr); } +static inline u32 ath10k_ce_src_ring_read_index_from_ddr(struct ath10k *ar, + u32 ce_id) +{ + struct ath10k_ce *ce = ath10k_ce_priv(ar); + + return ce->vaddr_rri[ce_id] & CE_DDR_RRI_MASK; +} + static inline u32 ath10k_ce_src_ring_read_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_ce_read32(ar, ce_ctrl_addr + - ar->hw_ce_regs->current_srri_addr); + struct ath10k_ce *ce = ath10k_ce_priv(ar); + u32 ce_id = COPY_ENGINE_ID(ce_ctrl_addr); + struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id]; + u32 index; + + if (ar->hw_params.rri_on_ddr && + (ce_state->attr_flags & CE_ATTR_DIS_INTR)) + index = ath10k_ce_src_ring_read_index_from_ddr(ar, ce_id); + else + index = ath10k_ce_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->current_srri_addr); + + return index; } static inline void @@ -266,11 +285,31 @@ static inline void ath10k_ce_dest_ring_byte_swap_set(struct ath10k *ar, ath10k_set_ring_byte(n, ctrl_regs->dst_ring)); } +static inline + u32 ath10k_ce_dest_ring_read_index_from_ddr(struct ath10k *ar, u32 ce_id) +{ + struct ath10k_ce *ce = ath10k_ce_priv(ar); + + return (ce->vaddr_rri[ce_id] >> CE_DDR_DRRI_SHIFT) & + CE_DDR_RRI_MASK; +} + static inline u32 ath10k_ce_dest_ring_read_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_ce_read32(ar, ce_ctrl_addr + - ar->hw_ce_regs->current_drri_addr); + struct ath10k_ce *ce = ath10k_ce_priv(ar); + u32 ce_id = COPY_ENGINE_ID(ce_ctrl_addr); + struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id]; + u32 index; + + if (ar->hw_params.rri_on_ddr && + (ce_state->attr_flags & CE_ATTR_DIS_INTR)) + index = ath10k_ce_dest_ring_read_index_from_ddr(ar, ce_id); + else + index = ath10k_ce_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->current_drri_addr); + + return index; } static inline void ath10k_ce_dest_ring_base_addr_set(struct ath10k *ar, @@ -486,7 +525,7 @@ static int _ath10k_ce_send_nolock_64(struct ath10k_ce_pipe *ce_state, struct ath10k_ce_ring *src_ring = ce_state->src_ring; struct ce_desc_64 *desc, sdesc; unsigned int nentries_mask = src_ring->nentries_mask; - unsigned int sw_index = src_ring->sw_index; + unsigned int sw_index; unsigned int write_index = src_ring->write_index; u32 ctrl_addr = ce_state->ctrl_addr; __le32 *addr; @@ -500,6 +539,11 @@ static int _ath10k_ce_send_nolock_64(struct ath10k_ce_pipe *ce_state, ath10k_warn(ar, "%s: send more we can (nbytes: %d, max: %d)\n", __func__, nbytes, ce_state->src_sz_max); + if (ar->hw_params.rri_on_ddr) + sw_index = ath10k_ce_src_ring_read_index_from_ddr(ar, ce_state->id); + else + sw_index = src_ring->sw_index; + if (unlikely(CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) <= 0)) { ret = -ENOSR; @@ -1016,7 +1060,10 @@ int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, src_ring->hw_index = read_index; } - read_index = src_ring->hw_index; + if (ar->hw_params.rri_on_ddr) + read_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); + else + read_index = src_ring->hw_index; if (read_index == sw_index) return -EIO; @@ -1841,3 +1888,46 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, return 0; } EXPORT_SYMBOL(ath10k_ce_alloc_pipe); + +void ath10k_ce_alloc_rri(struct ath10k *ar) +{ + int i; + u32 value; + u32 ctrl1_regs; + u32 ce_base_addr; + struct ath10k_ce *ce = ath10k_ce_priv(ar); + + ce->vaddr_rri = dma_alloc_coherent(ar->dev, + (CE_COUNT * sizeof(u32)), + &ce->paddr_rri, GFP_KERNEL); + + if (!ce->vaddr_rri) + return; + + ath10k_ce_write32(ar, ar->hw_ce_regs->ce_rri_low, + lower_32_bits(ce->paddr_rri)); + ath10k_ce_write32(ar, ar->hw_ce_regs->ce_rri_high, + (upper_32_bits(ce->paddr_rri) & + CE_DESC_FLAGS_GET_MASK)); + + for (i = 0; i < CE_COUNT; i++) { + ctrl1_regs = ar->hw_ce_regs->ctrl1_regs->addr; + ce_base_addr = ath10k_ce_base_address(ar, i); + value = ath10k_ce_read32(ar, ce_base_addr + ctrl1_regs); + value |= ar->hw_ce_regs->upd->mask; + ath10k_ce_write32(ar, ce_base_addr + ctrl1_regs, value); + } + + memset(ce->vaddr_rri, 0, CE_COUNT * sizeof(u32)); +} +EXPORT_SYMBOL(ath10k_ce_alloc_rri); + +void ath10k_ce_free_rri(struct ath10k *ar) +{ + struct ath10k_ce *ce = ath10k_ce_priv(ar); + + dma_free_coherent(ar->dev, (CE_COUNT * sizeof(u32)), + ce->vaddr_rri, + ce->paddr_rri); +} +EXPORT_SYMBOL(ath10k_ce_free_rri); diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 9aea89133209..dbeffaef6024 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -49,6 +49,9 @@ struct ath10k_ce_pipe; #define CE_DESC_FLAGS_META_DATA_MASK ar->hw_values->ce_desc_meta_data_mask #define CE_DESC_FLAGS_META_DATA_LSB ar->hw_values->ce_desc_meta_data_lsb +#define CE_DDR_RRI_MASK GENMASK(15, 0) +#define CE_DDR_DRRI_SHIFT 16 + struct ce_desc { __le32 addr; __le16 nbytes; @@ -157,6 +160,8 @@ struct ath10k_ce { spinlock_t ce_lock; const struct ath10k_bus_ops *bus_ops; struct ath10k_ce_pipe ce_states[CE_COUNT_MAX]; + u32 *vaddr_rri; + dma_addr_t paddr_rri; }; /*==================Send====================*/ @@ -265,6 +270,8 @@ int ath10k_ce_disable_interrupts(struct ath10k *ar); void ath10k_ce_enable_interrupts(struct ath10k *ar); void ath10k_ce_dump_registers(struct ath10k *ar, struct ath10k_fw_crash_data *crash_data); +void ath10k_ce_alloc_rri(struct ath10k *ar); +void ath10k_ce_free_rri(struct ath10k *ar); /* ce_attr.flags values */ /* Use NonSnooping PCIe accesses? */ @@ -331,6 +338,9 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) return CE0_BASE_ADDRESS + (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS) * ce_id; } +#define COPY_ENGINE_ID(COPY_ENGINE_BASE_ADDRESS) (((COPY_ENGINE_BASE_ADDRESS) \ + - CE0_BASE_ADDRESS) / (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS)) + #define CE_SRC_RING_TO_DESC(baddr, idx) \ (&(((struct ce_desc *)baddr)[idx])) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index a8bb21173d2c..4cf54a7ef09a 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -91,6 +91,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA988X_HW_2_0_VERSION, @@ -122,6 +123,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA9887_HW_1_0_VERSION, @@ -153,6 +155,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -183,6 +186,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA6174_HW_2_1_VERSION, @@ -213,6 +217,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA6174_HW_3_0_VERSION, @@ -243,6 +248,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA6174_HW_3_2_VERSION, @@ -276,6 +282,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA99X0_HW_2_0_DEV_VERSION, @@ -312,6 +319,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA9984_HW_1_0_DEV_VERSION, @@ -353,6 +361,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA9888_HW_2_0_DEV_VERSION, @@ -393,6 +402,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA9377_HW_1_0_DEV_VERSION, @@ -423,6 +433,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA9377_HW_1_1_DEV_VERSION, @@ -455,6 +466,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = QCA4019_HW_1_0_DEV_VERSION, @@ -492,6 +504,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, .per_ce_irq = false, .shadow_reg_support = false, + .rri_on_ddr = false, }, { .id = WCN3990_HW_1_0_DEV_VERSION, @@ -514,6 +527,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL_DUAL_MAC, .per_ce_irq = true, .shadow_reg_support = true, + .rri_on_ddr = true, }, }; diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 497ac33e0fbf..677535b3d207 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -310,6 +310,12 @@ static struct ath10k_hw_ce_dst_src_wm_regs wcn3990_wm_dst_ring = { .wm_high = &wcn3990_dst_wm_high, }; +static struct ath10k_hw_ce_ctrl1_upd wcn3990_ctrl1_upd = { + .shift = 19, + .mask = 0x00080000, + .enable = 0x00000000, +}; + const struct ath10k_hw_ce_regs wcn3990_ce_regs = { .sr_base_addr = 0x00000000, .sr_size_addr = 0x00000008, @@ -320,8 +326,6 @@ const struct ath10k_hw_ce_regs wcn3990_ce_regs = { .dst_wr_index_addr = 0x00000040, .current_srri_addr = 0x00000044, .current_drri_addr = 0x00000048, - .ddr_addr_for_rri_low = 0x00000004, - .ddr_addr_for_rri_high = 0x00000008, .ce_rri_low = 0x0024C004, .ce_rri_high = 0x0024C008, .host_ie_addr = 0x0000002c, @@ -331,6 +335,7 @@ const struct ath10k_hw_ce_regs wcn3990_ce_regs = { .misc_regs = &wcn3990_misc_reg, .wm_srcr = &wcn3990_wm_src_ring, .wm_dstr = &wcn3990_wm_dst_ring, + .upd = &wcn3990_ctrl1_upd, }; const struct ath10k_hw_values wcn3990_values = { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index dcefde76956c..b8bdabe73073 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -336,6 +336,12 @@ struct ath10k_hw_ce_dst_src_wm_regs { struct ath10k_hw_ce_regs_addr_map *wm_low; struct ath10k_hw_ce_regs_addr_map *wm_high; }; +struct ath10k_hw_ce_ctrl1_upd { + u32 shift; + u32 mask; + u32 enable; +}; + struct ath10k_hw_ce_regs { u32 sr_base_addr; u32 sr_size_addr; @@ -358,7 +364,9 @@ struct ath10k_hw_ce_regs { struct ath10k_hw_ce_cmd_halt *cmd_halt; struct ath10k_hw_ce_host_ie *host_ie; struct ath10k_hw_ce_dst_src_wm_regs *wm_srcr; - struct ath10k_hw_ce_dst_src_wm_regs *wm_dstr; }; + struct ath10k_hw_ce_dst_src_wm_regs *wm_dstr; + struct ath10k_hw_ce_ctrl1_upd *upd; +}; struct ath10k_hw_values { u32 rtc_state_val_on; @@ -575,6 +583,9 @@ struct ath10k_hw_params { /* target supporting shadow register for ce write */ bool shadow_reg_support; + + /* target supporting retention restore on ddr */ + bool rri_on_ddr; }; struct htt_rx_desc; diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 2e490ff124f1..47a4d2a5bd4c 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -767,6 +767,7 @@ static void ath10k_snoc_hif_power_down(struct ath10k *ar) ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n"); ath10k_snoc_wlan_disable(ar); + ath10k_ce_free_rri(ar); } static int ath10k_snoc_hif_power_up(struct ath10k *ar) @@ -782,6 +783,8 @@ static int ath10k_snoc_hif_power_up(struct ath10k *ar) return ret; } + ath10k_ce_alloc_rri(ar); + ret = ath10k_snoc_init_pipes(ar); if (ret) { ath10k_err(ar, "failed to initialize CE: %d\n", ret); -- cgit v1.2.3 From d5cded16fdc02a31f9f73d899329896218c594aa Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 17 Apr 2018 17:37:01 +0530 Subject: ath10k: enable sta idle power save Enable sta power save in fw for the targets that supports idle power save. The idle ps enable command will be ignored by the firmware which does not support this feature. Signed-off-by: Govind Singh Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c71cf5b81385..3d7119ad7c7a 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4679,6 +4679,13 @@ static int ath10k_start(struct ieee80211_hw *hw) } } + param = ar->wmi.pdev_param->idle_ps_config; + ret = ath10k_wmi_pdev_set_param(ar, param, 1); + if (ret && ret != -EOPNOTSUPP) { + ath10k_warn(ar, "failed to enable idle_ps_config: %d\n", ret); + goto err_core_stop; + } + __ath10k_set_antenna(ar, ar->cfg_tx_chainmask, ar->cfg_rx_chainmask); /* -- cgit v1.2.3 From 14ca3c98aa12842615a36812f29dc39b60811c93 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 17 Apr 2018 15:23:33 +0200 Subject: wcn36xx: abort scan request when 'dequeued' indicator is sent When the firmware sends a WCN36XX_HAL_SCAN_IND_DEQUEUED indication, the request is apparently no longer valid. Attempts to stop the hardware scan request subsequently will lead to the following error message, and the hardware is no longer able to communicate with any AP: [ 57.917186] wcn36xx: ERROR hal_stop_scan_offload response failed err=5 Interpreting this indicator message as scan abortion fixes this. While at it, add a newline to a debug print. Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/smd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 297a785d0785..b7964f79d837 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -2140,10 +2140,11 @@ static int wcn36xx_smd_hw_scan_ind(struct wcn36xx *wcn, void *buf, size_t len) return -EIO; } - wcn36xx_dbg(WCN36XX_DBG_HAL, "scan indication (type %x)", rsp->type); + wcn36xx_dbg(WCN36XX_DBG_HAL, "scan indication (type %x)\n", rsp->type); switch (rsp->type) { case WCN36XX_HAL_SCAN_IND_FAILED: + case WCN36XX_HAL_SCAN_IND_DEQUEUED: scan_info.aborted = true; /* fall through */ case WCN36XX_HAL_SCAN_IND_COMPLETED: @@ -2156,7 +2157,6 @@ static int wcn36xx_smd_hw_scan_ind(struct wcn36xx *wcn, void *buf, size_t len) break; case WCN36XX_HAL_SCAN_IND_STARTED: case WCN36XX_HAL_SCAN_IND_FOREIGN_CHANNEL: - case WCN36XX_HAL_SCAN_IND_DEQUEUED: case WCN36XX_HAL_SCAN_IND_PREEMPTED: case WCN36XX_HAL_SCAN_IND_RESTARTED: break; -- cgit v1.2.3 From 80c764d32122eceb26754d9ffa9718c124c8072e Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 17 Apr 2018 15:23:34 +0200 Subject: wcn36xx: cancel pending scan request when interface goes down When the network interface goes down while a scan request is still pending that can't be stopped due to firmware hickups, wcn->scan_req remains set, even though the hardware is deinitialized. This results in -EBUSY for all scan requests after the interface was brought up again. Fix this by explicitly completing pending scan requests in wcn36xx_stop(). Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/main.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 749aef3e2b85..08b6939d3f57 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -353,6 +353,19 @@ static void wcn36xx_stop(struct ieee80211_hw *hw) wcn36xx_dbg(WCN36XX_DBG_MAC, "mac stop\n"); + cancel_work_sync(&wcn->scan_work); + + mutex_lock(&wcn->scan_lock); + if (wcn->scan_req) { + struct cfg80211_scan_info scan_info = { + .aborted = true, + }; + + ieee80211_scan_completed(wcn->hw, &scan_info); + } + wcn->scan_req = NULL; + mutex_unlock(&wcn->scan_lock); + wcn36xx_debugfs_exit(wcn); wcn36xx_smd_stop(wcn); wcn36xx_dxe_deinit(wcn); -- cgit v1.2.3 From 89722f5767ac71b66e3077b6a158495eb316a43c Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 17 Apr 2018 15:23:35 +0200 Subject: wcn36xx: handle scan cancellation when firmware support is missing For firmwares that don't have the SCAN_OFFLOAD feature bit set, do not call into wcn36xx_smd_stop_hw_scan(). Instead, stop the asynchronous work and call into ieee80211_scan_completed() immediately. Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/main.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 08b6939d3f57..e3b91b3b38ef 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -687,10 +687,18 @@ static void wcn36xx_cancel_hw_scan(struct ieee80211_hw *hw, wcn->scan_aborted = true; mutex_unlock(&wcn->scan_lock); - /* ieee80211_scan_completed will be called on FW scan indication */ - wcn36xx_smd_stop_hw_scan(wcn); + if (get_feat_caps(wcn->fw_feat_caps, SCAN_OFFLOAD)) { + /* ieee80211_scan_completed will be called on FW scan + * indication */ + wcn36xx_smd_stop_hw_scan(wcn); + } else { + struct cfg80211_scan_info scan_info = { + .aborted = true, + }; - cancel_work_sync(&wcn->scan_work); + cancel_work_sync(&wcn->scan_work); + ieee80211_scan_completed(wcn->hw, &scan_info); + } } static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta, -- cgit v1.2.3 From 5a425c8b78e5a3d4850035c737f4f453f528320a Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 17 Apr 2018 15:23:36 +0200 Subject: wcn36xx: send bss_type in scan requests Pass the bss_type of the currently configured BSS in the message for the scan request. Therefore, that setting needs to be kept in struct wcn36xx_vif. This seems to be only interesting when scanning for a specific SSID and doesn't matter for regular wildcard scans. Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/smd.c | 5 ++++- drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index b7964f79d837..9c8ce5e0454f 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -620,6 +620,7 @@ out: int wcn36xx_smd_start_hw_scan(struct wcn36xx *wcn, struct ieee80211_vif *vif, struct cfg80211_scan_request *req) { + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); struct wcn36xx_hal_start_scan_offload_req_msg msg_body; int ret, i; @@ -631,6 +632,7 @@ int wcn36xx_smd_start_hw_scan(struct wcn36xx *wcn, struct ieee80211_vif *vif, msg_body.max_ch_time = 100; msg_body.scan_hidden = 1; memcpy(msg_body.mac, vif->addr, ETH_ALEN); + msg_body.bss_type = vif_priv->bss_type; msg_body.p2p_search = vif->p2p; msg_body.num_ssid = min_t(u8, req->n_ssids, ARRAY_SIZE(msg_body.ssids)); @@ -1399,9 +1401,10 @@ int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif, bss->spectrum_mgt_enable = 0; bss->tx_mgmt_power = 0; bss->max_tx_power = WCN36XX_MAX_POWER(wcn); - bss->action = update; + vif_priv->bss_type = bss->bss_type; + wcn36xx_dbg(WCN36XX_DBG_HAL, "hal config bss bssid %pM self_mac_addr %pM bss_type %d oper_mode %d nw_type %d\n", bss->bssid, bss->self_mac_addr, bss->bss_type, diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index 5854adf43f3a..22e05cb4eb98 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -123,6 +123,7 @@ struct wcn36xx_vif { bool is_joining; bool sta_assoc; struct wcn36xx_hal_mac_ssid ssid; + enum wcn36xx_hal_bss_type bss_type; /* Power management */ enum wcn36xx_power_state pw_state; -- cgit v1.2.3 From 4836ec42b07433fc8bdaf36a18f74f7a89659bb4 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 17 Apr 2018 15:23:37 +0200 Subject: wcn36xx: pass information elements in scan requests When the wifi driver core passes IE elements in the scan request, append them to the firmware message. The driver currently tells the core that it is capable of attaching up to WCN36XX_MAX_SCAN_IE_LEN octets, but doesn't actually pass them to the the hardware. Note that this patch doesn't fix a bug that was observed. The change is merely done for the sake of completeness as the hardware supports appending IEs in scans. Tests show that network scans work fine with this patch applied. Some defines were moved around to avoid cyclic include dependencies. Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/hal.h | 8 +++++++- drivers/net/wireless/ath/wcn36xx/smd.c | 11 +++++++++++ drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 6 ------ 3 files changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h index 182963522941..2aed6c233508 100644 --- a/drivers/net/wireless/ath/wcn36xx/hal.h +++ b/drivers/net/wireless/ath/wcn36xx/hal.h @@ -88,6 +88,12 @@ /* version string max length (including NULL) */ #define WCN36XX_HAL_VERSION_LENGTH 64 +/* How many frames until we start a-mpdu TX session */ +#define WCN36XX_AMPDU_START_THRESH 20 + +#define WCN36XX_MAX_SCAN_SSIDS 9 +#define WCN36XX_MAX_SCAN_IE_LEN 500 + /* message types for messages exchanged between WDI and HAL */ enum wcn36xx_hal_host_msg_type { /* Init/De-Init */ @@ -1170,7 +1176,7 @@ struct wcn36xx_hal_start_scan_offload_req_msg { /* IE field */ u16 ie_len; - u8 ie[0]; + u8 ie[WCN36XX_MAX_SCAN_IE_LEN]; } __packed; struct wcn36xx_hal_start_scan_offload_rsp_msg { diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 9c8ce5e0454f..ea74f2b92df5 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -624,6 +624,9 @@ int wcn36xx_smd_start_hw_scan(struct wcn36xx *wcn, struct ieee80211_vif *vif, struct wcn36xx_hal_start_scan_offload_req_msg msg_body; int ret, i; + if (req->ie_len > WCN36XX_MAX_SCAN_IE_LEN) + return -EINVAL; + mutex_lock(&wcn->hal_mutex); INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_SCAN_OFFLOAD_REQ); @@ -648,6 +651,14 @@ int wcn36xx_smd_start_hw_scan(struct wcn36xx *wcn, struct ieee80211_vif *vif, for (i = 0; i < msg_body.num_channel; i++) msg_body.channels[i] = req->channels[i]->hw_value; + msg_body.header.len -= WCN36XX_MAX_SCAN_IE_LEN; + + if (req->ie_len > 0) { + msg_body.ie_len = req->ie_len; + msg_body.header.len += req->ie_len; + memcpy(msg_body.ie, req->ie, req->ie_len); + } + PREPARE_HAL_BUF(wcn->hal_buf, msg_body); wcn36xx_dbg(WCN36XX_DBG_HAL, diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index 22e05cb4eb98..9343989d1169 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -32,12 +32,6 @@ #define WLAN_NV_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin" #define WCN36XX_AGGR_BUFFER_SIZE 64 -/* How many frames until we start a-mpdu TX session */ -#define WCN36XX_AMPDU_START_THRESH 20 - -#define WCN36XX_MAX_SCAN_SSIDS 9 -#define WCN36XX_MAX_SCAN_IE_LEN 500 - extern unsigned int wcn36xx_dbg_mask; enum wcn36xx_debug_mask { -- cgit v1.2.3 From fbb93020b89bc0270a9ca3c2479bbbbc548d9ee5 Mon Sep 17 00:00:00 2001 From: Dmitry Lebed Date: Mon, 26 Mar 2018 16:36:33 +0300 Subject: qtnfmac: add DFS offload support DFS offload support implemented: - DFS_OFFLOAD feature is advertised depending on HW capabilities - CAC_STARTED event forwarding from HW implemented - start_radar_detection() callback now returning -ENOTSUPP if DFS_OFFLOAD is enabled Signed-off-by: Dmitry Lebed Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 9 +++++++++ drivers/net/wireless/quantenna/qtnfmac/event.c | 11 +++++++++++ drivers/net/wireless/quantenna/qtnfmac/qlink.h | 7 +++++-- 3 files changed, 25 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index 0398bece5782..5122dc798064 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -813,6 +813,9 @@ static int qtnf_start_radar_detection(struct wiphy *wiphy, struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev); int ret; + if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD)) + return -ENOTSUPP; + ret = qtnf_cmd_start_cac(vif, chandef, cac_time_ms); if (ret) pr_err("%s: failed to start CAC ret=%d\n", ndev->name, ret); @@ -909,6 +912,9 @@ struct wiphy *qtnf_wiphy_allocate(struct qtnf_bus *bus) { struct wiphy *wiphy; + if (bus->hw_info.hw_capab & QLINK_HW_CAPAB_DFS_OFFLOAD) + qtn_cfg80211_ops.start_radar_detection = NULL; + wiphy = wiphy_new(&qtn_cfg80211_ops, sizeof(struct qtnf_wmac)); if (!wiphy) return NULL; @@ -982,6 +988,9 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_HAS_CHANNEL_SWITCH; + if (hw_info->hw_capab & QLINK_HW_CAPAB_DFS_OFFLOAD) + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD); + wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2; diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.c b/drivers/net/wireless/quantenna/qtnfmac/event.c index bcd415f96412..cb2a6c12f870 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/event.c +++ b/drivers/net/wireless/quantenna/qtnfmac/event.c @@ -443,6 +443,17 @@ static int qtnf_event_handle_radar(struct qtnf_vif *vif, cfg80211_cac_event(vif->netdev, &chandef, NL80211_RADAR_CAC_ABORTED, GFP_KERNEL); break; + case QLINK_RADAR_CAC_STARTED: + if (vif->wdev.cac_started) + break; + + if (!wiphy_ext_feature_isset(wiphy, + NL80211_EXT_FEATURE_DFS_OFFLOAD)) + break; + + cfg80211_cac_event(vif->netdev, &chandef, + NL80211_RADAR_CAC_STARTED, GFP_KERNEL); + break; default: pr_warn("%s: unhandled radar event %u\n", vif->netdev->name, ev->event); diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h index 9bf3ae4d1b3b..9ab27e158023 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h @@ -68,10 +68,12 @@ struct qlink_msg_header { * @QLINK_HW_CAPAB_STA_INACT_TIMEOUT: device implements a logic to kick-out * associated STAs due to inactivity. Inactivity timeout period is taken * from QLINK_CMD_START_AP parameters. + * @QLINK_HW_CAPAB_DFS_OFFLOAD: device implements DFS offload functionality */ enum qlink_hw_capab { - QLINK_HW_CAPAB_REG_UPDATE = BIT(0), - QLINK_HW_CAPAB_STA_INACT_TIMEOUT = BIT(1), + QLINK_HW_CAPAB_REG_UPDATE = BIT(0), + QLINK_HW_CAPAB_STA_INACT_TIMEOUT = BIT(1), + QLINK_HW_CAPAB_DFS_OFFLOAD = BIT(2), }; enum qlink_iface_type { @@ -1031,6 +1033,7 @@ enum qlink_radar_event { QLINK_RADAR_CAC_ABORTED, QLINK_RADAR_NOP_FINISHED, QLINK_RADAR_PRE_CAC_EXPIRED, + QLINK_RADAR_CAC_STARTED, }; /** -- cgit v1.2.3 From 0fb1abc3a0b8f83b312b3c00e98643a17df69e87 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 29 Mar 2018 16:38:18 +0100 Subject: cw1200: fix spelling mistake: "Mailformed" -> "Malformed" Trivial fix to spelling mistake in wiphy_warn warning message text Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/st/cw1200/txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/st/cw1200/txrx.c b/drivers/net/wireless/st/cw1200/txrx.c index e9050b41157a..f7b1b0062db3 100644 --- a/drivers/net/wireless/st/cw1200/txrx.c +++ b/drivers/net/wireless/st/cw1200/txrx.c @@ -1069,7 +1069,7 @@ void cw1200_rx_cb(struct cw1200_common *priv, } if (skb->len < sizeof(struct ieee80211_pspoll)) { - wiphy_warn(priv->hw->wiphy, "Mailformed SDU rx'ed. Size is lesser than IEEE header.\n"); + wiphy_warn(priv->hw->wiphy, "Malformed SDU rx'ed. Size is lesser than IEEE header.\n"); goto drop; } -- cgit v1.2.3 From 5dc3638735f1c8a6ccd7f6ea361546567deb5f0f Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Thu, 29 Mar 2018 19:44:49 +0530 Subject: rsi: move xtend_desc structure from rsi_main.h to rsi_mgmt.h All descriptor structures are in rsi_mgmt.h except this extended descriptor structure. Hence moving it to rsi_mgmt.h and also renaming to rsi_xtend_desc. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_hal.c | 12 ++++++------ drivers/net/wireless/rsi/rsi_main.h | 6 ------ drivers/net/wireless/rsi/rsi_mgmt.h | 6 ++++++ 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index de608ae365a4..ce6a86deea65 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -55,7 +55,7 @@ static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb) struct rsi_mgmt_desc *mgmt_desc; struct skb_info *tx_params; struct ieee80211_bss_conf *bss = NULL; - struct xtended_desc *xtend_desc = NULL; + struct rsi_xtended_desc *xtend_desc = NULL; u8 header_size; u32 dword_align_bytes = 0; @@ -69,7 +69,7 @@ static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb) vif = tx_params->vif; /* Update header size */ - header_size = FRAME_DESC_SZ + sizeof(struct xtended_desc); + header_size = FRAME_DESC_SZ + sizeof(struct rsi_xtended_desc); if (header_size > skb_headroom(skb)) { rsi_dbg(ERR_ZONE, "%s: Failed to add extended descriptor\n", @@ -92,7 +92,7 @@ static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb) wh = (struct ieee80211_hdr *)&skb->data[header_size]; mgmt_desc = (struct rsi_mgmt_desc *)skb->data; - xtend_desc = (struct xtended_desc *)&skb->data[FRAME_DESC_SZ]; + xtend_desc = (struct rsi_xtended_desc *)&skb->data[FRAME_DESC_SZ]; rsi_set_len_qno(&mgmt_desc->len_qno, (skb->len - FRAME_DESC_SZ), RSI_WIFI_MGMT_Q); @@ -158,7 +158,7 @@ static int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb) struct skb_info *tx_params; struct ieee80211_bss_conf *bss; struct rsi_data_desc *data_desc; - struct xtended_desc *xtend_desc; + struct rsi_xtended_desc *xtend_desc; u8 ieee80211_size = MIN_802_11_HDR_LEN; u8 header_size; u8 vap_id = 0; @@ -170,7 +170,7 @@ static int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb) bss = &vif->bss_conf; tx_params = (struct skb_info *)info->driver_data; - header_size = FRAME_DESC_SZ + sizeof(struct xtended_desc); + header_size = FRAME_DESC_SZ + sizeof(struct rsi_xtended_desc); if (header_size > skb_headroom(skb)) { rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__); return -ENOSPC; @@ -188,7 +188,7 @@ static int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb) data_desc = (struct rsi_data_desc *)skb->data; memset(data_desc, 0, header_size); - xtend_desc = (struct xtended_desc *)&skb->data[FRAME_DESC_SZ]; + xtend_desc = (struct rsi_xtended_desc *)&skb->data[FRAME_DESC_SZ]; wh = (struct ieee80211_hdr *)&skb->data[header_size]; seq_num = IEEE80211_SEQ_TO_SN(le16_to_cpu(wh->seq_ctrl)); diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index ef4fa323694b..b81cdbf05e5b 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -190,12 +190,6 @@ struct cqm_info { u32 rssi_hyst; }; -struct xtended_desc { - u8 confirm_frame_type; - u8 retry_cnt; - u16 reserved; -}; - enum rsi_dfs_regions { RSI_REGION_FCC = 0, RSI_REGION_ETSI, diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index cf6567ae5bbe..6726e84a6773 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -301,6 +301,12 @@ struct rsi_mac_frame { #define ENCAP_MGMT_PKT BIT(7) #define DESC_IMMEDIATE_WAKEUP BIT(15) +struct rsi_xtended_desc { + u8 confirm_frame_type; + u8 retry_cnt; + u16 reserved; +}; + struct rsi_cmd_desc_dword0 { __le16 len_qno; u8 frame_type; -- cgit v1.2.3 From 1be05eb5e4dc8e3812ae72bdd55e6fa4de3ee948 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Thu, 29 Mar 2018 19:44:50 +0530 Subject: rsi: move descriptor preparation to core Descriptors preparation is moved to core instead of HAL to avoid synchronization issues in sending TX frames Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_core.c | 11 +++++++++ drivers/net/wireless/rsi/rsi_91x_hal.c | 43 +++++++++++++++++---------------- drivers/net/wireless/rsi/rsi_hal.h | 2 ++ 3 files changed, 35 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index 5dafd2e1306c..f5d17568685b 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -413,6 +413,11 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) (ieee80211_is_qos_nullfunc(wh->frame_control))) { q_num = MGMT_SOFT_Q; skb->priority = q_num; + + if (rsi_prepare_mgmt_desc(common, skb)) { + rsi_dbg(ERR_ZONE, "Failed to prepare desc\n"); + goto xmit_fail; + } } else { if (ieee80211_is_data_qos(wh->frame_control)) { tid = (skb->data[24] & IEEE80211_QOS_TID); @@ -433,6 +438,8 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) if (!rsta) goto xmit_fail; tx_params->sta_id = rsta->sta_id; + } else { + tx_params->sta_id = 0; } if (rsta) { @@ -443,6 +450,10 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) tid, 0); } } + if (rsi_prepare_data_desc(common, skb)) { + rsi_dbg(ERR_ZONE, "Failed to prepare data desc\n"); + goto xmit_fail; + } } if ((q_num < MGMT_SOFT_Q) && diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index ce6a86deea65..43d7d6c7ccb8 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -45,7 +45,7 @@ int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb) return status; } -static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb) +int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb) { struct rsi_hw *adapter = common->priv; struct ieee80211_hdr *wh = NULL; @@ -113,17 +113,6 @@ static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb) if (conf_is_ht40(conf)) mgmt_desc->bbp_info = cpu_to_le16(FULL40M_ENABLE); - if (ieee80211_is_probe_req(wh->frame_control)) { - if (!bss->assoc) { - rsi_dbg(INFO_ZONE, - "%s: blocking mgmt queue\n", __func__); - mgmt_desc->misc_flags = RSI_DESC_REQUIRE_CFM_TO_HOST; - xtend_desc->confirm_frame_type = PROBEREQ_CONFIRM; - common->mgmt_q_block = true; - rsi_dbg(INFO_ZONE, "Mgmt queue blocked\n"); - } - } - if (ieee80211_is_probe_resp(wh->frame_control)) { mgmt_desc->misc_flags |= (RSI_ADD_DELTA_TSF_VAP_ID | RSI_FETCH_RETRY_CNT_FRM_HST); @@ -149,7 +138,7 @@ static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb) } /* This function prepares descriptor for given data packet */ -static int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb) +int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb) { struct rsi_hw *adapter = common->priv; struct ieee80211_vif *vif; @@ -301,10 +290,6 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) (!bss->assoc)) goto err; - status = rsi_prepare_data_desc(common, skb); - if (status) - goto err; - status = rsi_send_pkt_to_bus(common, skb); if (status) rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n", __func__); @@ -327,12 +312,18 @@ int rsi_send_mgmt_pkt(struct rsi_common *common, struct sk_buff *skb) { struct rsi_hw *adapter = common->priv; + struct ieee80211_bss_conf *bss; + struct ieee80211_hdr *wh; struct ieee80211_tx_info *info; struct skb_info *tx_params; + struct rsi_mgmt_desc *mgmt_desc; + struct rsi_xtended_desc *xtend_desc; int status = -E2BIG; + u8 header_size; info = IEEE80211_SKB_CB(skb); tx_params = (struct skb_info *)info->driver_data; + header_size = tx_params->internal_hdr_size; if (tx_params->flags & INTERNAL_MGMT_PKT) { status = adapter->host_intf_ops->write_pkt(common->priv, @@ -346,15 +337,25 @@ int rsi_send_mgmt_pkt(struct rsi_common *common, return status; } - if (FRAME_DESC_SZ > skb_headroom(skb)) - goto err; + bss = &info->control.vif->bss_conf; + wh = (struct ieee80211_hdr *)&skb->data[header_size]; + mgmt_desc = (struct rsi_mgmt_desc *)skb->data; + xtend_desc = (struct rsi_xtended_desc *)&skb->data[FRAME_DESC_SZ]; + + /* Indicate to firmware to give cfm for probe */ + if (ieee80211_is_probe_req(wh->frame_control) && !bss->assoc) { + rsi_dbg(INFO_ZONE, + "%s: blocking mgmt queue\n", __func__); + mgmt_desc->misc_flags = RSI_DESC_REQUIRE_CFM_TO_HOST; + xtend_desc->confirm_frame_type = PROBEREQ_CONFIRM; + common->mgmt_q_block = true; + rsi_dbg(INFO_ZONE, "Mgmt queue blocked\n"); + } - rsi_prepare_mgmt_desc(common, skb); status = rsi_send_pkt_to_bus(common, skb); if (status) rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__); -err: rsi_indicate_tx_status(common->priv, skb, status); return status; } diff --git a/drivers/net/wireless/rsi/rsi_hal.h b/drivers/net/wireless/rsi/rsi_hal.h index 786dccd0b732..d6c2baa56e9f 100644 --- a/drivers/net/wireless/rsi/rsi_hal.h +++ b/drivers/net/wireless/rsi/rsi_hal.h @@ -167,6 +167,8 @@ struct rsi_bt_desc { } __packed; int rsi_hal_device_init(struct rsi_hw *adapter); +int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb); +int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb); int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb); int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb); int rsi_send_bt_pkt(struct rsi_common *common, struct sk_buff *skb); -- cgit v1.2.3 From 62dc108d5f7c4443ce88e1d6157e8547edbc07b3 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Thu, 29 Mar 2018 19:44:51 +0530 Subject: rsi: enable 80MHz clock by default 80MHz clock for device should be enabled by default in TX command frame radio capabilities. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index c21fca750fd4..9207da09a4f7 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -325,8 +325,8 @@ static int rsi_load_radio_caps(struct rsi_common *common) radio_caps->channel_num = common->channel; radio_caps->rf_model = RSI_RF_TYPE; + radio_caps->radio_cfg_info = RSI_LMAC_CLOCK_80MHZ; if (common->channel_width == BW_40MHZ) { - radio_caps->radio_cfg_info = RSI_LMAC_CLOCK_80MHZ; radio_caps->radio_cfg_info |= RSI_ENABLE_40MHZ; if (common->fsm_state == FSM_MAC_INIT_DONE) { -- cgit v1.2.3 From 4fd6c4762f372852d65ad737ab35996395295dce Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Thu, 29 Mar 2018 19:44:52 +0530 Subject: rsi: roaming enhancements To support roaming below changes are done: * Station notify frame is send to firmware after sending assoc request. This will avoid dropping of first EAPOL frame due to delay in creation of station control block in firmware. * Data queues are unblocked after sending station notify in open mode, after configuring key in WEP mode, and after receiving EAPOL4 confirm in WPA mode. * Initial EAPOL frames priority is chaged to MGMT, rekey EAPOL frames priority changed to VO. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_core.c | 16 +++++++++++++++ drivers/net/wireless/rsi/rsi_91x_hal.c | 18 ++++++++++++++++ drivers/net/wireless/rsi/rsi_91x_mac80211.c | 18 +++++++++++++--- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 32 +++++++++++++++++------------ drivers/net/wireless/rsi/rsi_main.h | 1 + drivers/net/wireless/rsi/rsi_mgmt.h | 10 ++++++++- 6 files changed, 78 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index f5d17568685b..3ca468b9f2b8 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -411,6 +411,18 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) if ((ieee80211_is_mgmt(wh->frame_control)) || (ieee80211_is_ctl(wh->frame_control)) || (ieee80211_is_qos_nullfunc(wh->frame_control))) { + if (ieee80211_is_assoc_req(wh->frame_control) || + ieee80211_is_reassoc_req(wh->frame_control)) { + struct ieee80211_bss_conf *bss = &vif->bss_conf; + + common->eapol4_confirm = false; + rsi_hal_send_sta_notify_frame(common, + RSI_IFTYPE_STATION, + STA_CONNECTED, bss->bssid, + bss->qos, bss->aid, 0, + vif); + } + q_num = MGMT_SOFT_Q; skb->priority = q_num; @@ -450,6 +462,10 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) tid, 0); } } + if (skb->protocol == cpu_to_be16(ETH_P_PAE)) { + q_num = MGMT_SOFT_Q; + skb->priority = q_num; + } if (rsi_prepare_data_desc(common, skb)) { rsi_dbg(ERR_ZONE, "Failed to prepare data desc\n"); goto xmit_fail; diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 43d7d6c7ccb8..b7c54037f369 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -232,6 +232,18 @@ int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb) data_desc->misc_flags |= RSI_FETCH_RETRY_CNT_FRM_HST; #define EAPOL_RETRY_CNT 15 xtend_desc->retry_cnt = EAPOL_RETRY_CNT; + + if (common->eapol4_confirm) + skb->priority = VO_Q; + else + rsi_set_len_qno(&data_desc->len_qno, + (skb->len - FRAME_DESC_SZ), + RSI_WIFI_MGMT_Q); + if ((skb->len - header_size) == EAPOL4_PACKET_LEN) { + data_desc->misc_flags |= + RSI_DESC_REQUIRE_CFM_TO_HOST; + xtend_desc->confirm_frame_type = EAPOL4_CONFIRM; + } } data_desc->mac_flags = cpu_to_le16(seq_num & 0xfff); @@ -271,8 +283,11 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) struct rsi_hw *adapter = common->priv; struct ieee80211_vif *vif; struct ieee80211_tx_info *info; + struct skb_info *tx_params; struct ieee80211_bss_conf *bss; + struct ieee80211_hdr *wh; int status = -EINVAL; + u8 header_size; if (!skb) return 0; @@ -284,6 +299,9 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) goto err; vif = info->control.vif; bss = &vif->bss_conf; + tx_params = (struct skb_info *)info->driver_data; + header_size = tx_params->internal_hdr_size; + wh = (struct ieee80211_hdr *)&skb->data[header_size]; if (((vif->type == NL80211_IFTYPE_STATION) || (vif->type == NL80211_IFTYPE_P2P_CLIENT)) && diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 32f5cb46fd4f..5edc3a9d8eeb 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -737,7 +737,8 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, bss_conf->bssid, bss_conf->qos, bss_conf->aid, - NULL, 0, vif); + NULL, 0, + bss_conf->assoc_capability, vif); adapter->ps_info.dtim_interval_duration = bss->dtim_period; adapter->ps_info.listen_interval = conf->listen_interval; @@ -914,6 +915,17 @@ static int rsi_hal_key_config(struct ieee80211_hw *hw, key->cipher, sta_id, vif); + if (status) + return status; + + if (vif->type == NL80211_IFTYPE_STATION && key->key && + (key->cipher == WLAN_CIPHER_SUITE_WEP104 || + key->cipher == WLAN_CIPHER_SUITE_WEP40)) { + if (!rsi_send_block_unblock_frame(adapter->priv, false)) + adapter->priv->hw_data_qs_blocked = false; + } + + return 0; } /** @@ -1391,7 +1403,7 @@ static int rsi_mac80211_sta_add(struct ieee80211_hw *hw, rsi_dbg(INFO_ZONE, "Indicate bss status to device\n"); rsi_inform_bss_status(common, RSI_OPMODE_AP, 1, sta->addr, sta->wme, sta->aid, - sta, sta_idx, vif); + sta, sta_idx, 0, vif); if (common->key) { struct ieee80211_key_conf *key = common->key; @@ -1469,7 +1481,7 @@ static int rsi_mac80211_sta_remove(struct ieee80211_hw *hw, rsi_inform_bss_status(common, RSI_OPMODE_AP, 0, sta->addr, sta->wme, sta->aid, sta, sta_idx, - vif); + 0, vif); rsta->sta = NULL; rsta->sta_id = -1; for (cnt = 0; cnt < IEEE80211_NUM_TIDS; cnt++) diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 9207da09a4f7..0757adcb3f4a 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -454,14 +454,10 @@ static int rsi_mgmt_pkt_to_core(struct rsi_common *common, * * Return: status: 0 on success, corresponding negative error code on failure. */ -static int rsi_hal_send_sta_notify_frame(struct rsi_common *common, - enum opmode opmode, - u8 notify_event, - const unsigned char *bssid, - u8 qos_enable, - u16 aid, - u16 sta_id, - struct ieee80211_vif *vif) +int rsi_hal_send_sta_notify_frame(struct rsi_common *common, enum opmode opmode, + u8 notify_event, const unsigned char *bssid, + u8 qos_enable, u16 aid, u16 sta_id, + struct ieee80211_vif *vif) { struct sk_buff *skb = NULL; struct rsi_peer_notify *peer_notify; @@ -1328,6 +1324,7 @@ void rsi_inform_bss_status(struct rsi_common *common, u16 aid, struct ieee80211_sta *sta, u16 sta_id, + u16 assoc_cap, struct ieee80211_vif *vif) { if (status) { @@ -1342,10 +1339,10 @@ void rsi_inform_bss_status(struct rsi_common *common, vif); if (common->min_rate == 0xffff) rsi_send_auto_rate_request(common, sta, sta_id, vif); - if (opmode == RSI_OPMODE_STA) { - if (!rsi_send_block_unblock_frame(common, false)) - common->hw_data_qs_blocked = false; - } + if (opmode == RSI_OPMODE_STA && + !(assoc_cap & WLAN_CAPABILITY_PRIVACY) && + !rsi_send_block_unblock_frame(common, false)) + common->hw_data_qs_blocked = false; } else { if (opmode == RSI_OPMODE_STA) common->hw_data_qs_blocked = true; @@ -1850,10 +1847,19 @@ int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg) __func__); return rsi_handle_card_ready(common, msg); case TX_STATUS_IND: - if (msg[15] == PROBEREQ_CONFIRM) { + switch (msg[RSI_TX_STATUS_TYPE]) { + case PROBEREQ_CONFIRM: common->mgmt_q_block = false; rsi_dbg(FSM_ZONE, "%s: Probe confirm received\n", __func__); + break; + case EAPOL4_CONFIRM: + if (msg[RSI_TX_STATUS]) { + common->eapol4_confirm = true; + if (!rsi_send_block_unblock_frame(common, + false)) + common->hw_data_qs_blocked = false; + } } break; case BEACON_EVENT_IND: diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index b81cdbf05e5b..a084f224bb03 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -287,6 +287,7 @@ struct rsi_common { struct timer_list roc_timer; struct ieee80211_vif *roc_vif; + bool eapol4_confirm; void *bt_adapter; }; diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index 6726e84a6773..5f946f31723f 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -33,6 +33,7 @@ #define WMM_SHORT_SLOT_TIME 9 #define SIFS_DURATION 16 +#define EAPOL4_PACKET_LEN 0x85 #define KEY_TYPE_CLEAR 0 #define RSI_PAIRWISE_KEY 1 #define RSI_GROUP_KEY 2 @@ -62,9 +63,12 @@ #define RX_DOT11_MGMT 0x02 #define TX_STATUS_IND 0x04 #define BEACON_EVENT_IND 0x08 +#define EAPOL4_CONFIRM 1 #define PROBEREQ_CONFIRM 2 #define CARD_READY_IND 0x00 #define SLEEP_NOTIFY_IND 0x06 +#define RSI_TX_STATUS_TYPE 15 +#define RSI_TX_STATUS 12 #define RSI_DELETE_PEER 0x0 #define RSI_ADD_PEER 0x1 @@ -660,10 +664,14 @@ int rsi_set_channel(struct rsi_common *common, struct ieee80211_channel *channel); int rsi_send_vap_dynamic_update(struct rsi_common *common); int rsi_send_block_unblock_frame(struct rsi_common *common, bool event); +int rsi_hal_send_sta_notify_frame(struct rsi_common *common, enum opmode opmode, + u8 notify_event, const unsigned char *bssid, + u8 qos_enable, u16 aid, u16 sta_id, + struct ieee80211_vif *vif); void rsi_inform_bss_status(struct rsi_common *common, enum opmode opmode, u8 status, const u8 *addr, u8 qos_enable, u16 aid, struct ieee80211_sta *sta, u16 sta_id, - struct ieee80211_vif *vif); + u16 assoc_cap, struct ieee80211_vif *vif); void rsi_indicate_pkt_to_os(struct rsi_common *common, struct sk_buff *skb); int rsi_mac80211_attach(struct rsi_common *common); void rsi_indicate_tx_status(struct rsi_hw *common, struct sk_buff *skb, -- cgit v1.2.3 From 350fcdb834576162ab55519ed86572c00ea786a7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 6 Apr 2018 11:37:17 +0300 Subject: rsi: remove unecessary PTR_ALIGN()s The issue here is that we allocate "data" and then set "data = PTR_ALIGN(data, 8);" and then we free the aligned pointer instead of the original pointer. kmalloc() pointers are already ARCH_SLAB_MINALIGN aligned which is 8 or more on everything except certain Xtensa variants. We decided that if the Xtensa people ever notice a bug here then we'll tell them the bug is on their side. ;) Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_sdio.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index d76e69c0beaa..8ef00582c6ea 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -660,8 +660,6 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr, if (!data) return -ENOMEM; - data = PTR_ALIGN(data, 8); - ms_addr = (addr >> 16); status = rsi_sdio_master_access_msword(adapter, ms_addr); if (status < 0) { @@ -724,8 +722,6 @@ static int rsi_sdio_master_reg_write(struct rsi_hw *adapter, if (!data_aligned) return -ENOMEM; - data_aligned = PTR_ALIGN(data_aligned, 8); - if (size == 2) { *data_aligned = ((data << 16) | (data & 0xFFFF)); } else if (size == 1) { -- cgit v1.2.3 From 16d3bb7b2f37b917b3c55e83d230a199f5c51864 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 10 Apr 2018 20:34:11 +0530 Subject: rsi: disable fw watchdog timer during reset Firmware's watchdog timer should be disabled as a part of reset sequence. This change fixes a firmware hang issue observed during stress tests. Signed-off-by: Amitkumar Karwar Signed-off-by: Siva Rebbagondla Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_usb.c | 7 +++++++ drivers/net/wireless/rsi/rsi_hal.h | 1 + drivers/net/wireless/rsi/rsi_usb.h | 1 + 3 files changed, 9 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index 7b8bae313aa9..b065438f51b2 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -687,6 +687,13 @@ static int rsi_reset_card(struct rsi_hw *adapter) */ msleep(100); + if (rsi_usb_master_reg_write(adapter, SWBL_REGOUT, + RSI_FW_WDT_DISABLE_REQ, + RSI_COMMON_REG_SIZE) < 0) { + rsi_dbg(ERR_ZONE, "Disabling firmware watchdog timer failed\n"); + goto fail; + } + ret = usb_ulp_read_write(adapter, RSI_WATCH_DOG_TIMER_1, RSI_ULP_WRITE_2, 32); if (ret < 0) diff --git a/drivers/net/wireless/rsi/rsi_hal.h b/drivers/net/wireless/rsi/rsi_hal.h index d6c2baa56e9f..327638cdd30b 100644 --- a/drivers/net/wireless/rsi/rsi_hal.h +++ b/drivers/net/wireless/rsi/rsi_hal.h @@ -115,6 +115,7 @@ #define FW_FLASH_OFFSET 0x820 #define LMAC_VER_OFFSET (FW_FLASH_OFFSET + 0x200) #define MAX_DWORD_ALIGN_BYTES 64 +#define RSI_COMMON_REG_SIZE 2 struct bl_header { __le32 flags; diff --git a/drivers/net/wireless/rsi/rsi_usb.h b/drivers/net/wireless/rsi/rsi_usb.h index a88d59295a98..b6fe79f0a513 100644 --- a/drivers/net/wireless/rsi/rsi_usb.h +++ b/drivers/net/wireless/rsi/rsi_usb.h @@ -26,6 +26,7 @@ #define RSI_USB_READY_MAGIC_NUM 0xab #define FW_STATUS_REG 0x41050012 #define RSI_TA_HOLD_REG 0x22000844 +#define RSI_FW_WDT_DISABLE_REQ 0x69 #define USB_VENDOR_REGISTER_READ 0x15 #define USB_VENDOR_REGISTER_WRITE 0x16 -- cgit v1.2.3 From 8c1475bdfc3ae3b5ee46d7c026be5e4409e05ea2 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 10 Apr 2018 20:34:12 +0530 Subject: rsi: device bootup parameter configuration Some device configuration flags need to be enabled while sending 'bootup params' internal frame to firmware. This patch takes care of it. Signed-off-by: Amitkumar Karwar Signed-off-by: Siva Rebbagondla Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_boot_params.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_boot_params.h b/drivers/net/wireless/rsi/rsi_boot_params.h index 238ee96434ec..ad903b22440e 100644 --- a/drivers/net/wireless/rsi/rsi_boot_params.h +++ b/drivers/net/wireless/rsi/rsi_boot_params.h @@ -46,7 +46,8 @@ (((TA_PLL_M_VAL_20 + 1) * 40) / \ ((TA_PLL_N_VAL_20 + 1) * (TA_PLL_P_VAL_20 + 1))) #define VALID_20 \ - (WIFI_PLL960_CONFIGS | WIFI_AFEPLL_CONFIGS | WIFI_SWITCH_CLK_CONFIGS) + (WIFI_TAPLL_CONFIGS | WIFI_PLL960_CONFIGS | WIFI_AFEPLL_CONFIGS | \ + WIFI_SWITCH_CLK_CONFIGS | BOOTUP_MODE_INFO | CRYSTAL_GOOD_TIME) #define UMAC_CLK_40BW \ (((TA_PLL_M_VAL_40 + 1) * 40) / \ ((TA_PLL_N_VAL_40 + 1) * (TA_PLL_P_VAL_40 + 1))) -- cgit v1.2.3 From cbbfdd6c700f7c840df73199fac0c77a31b6d944 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 10 Apr 2018 20:34:13 +0530 Subject: rsi: use appropriate interface for power save configuration Power save request should be sent on station interface. Virtual interface which is connected should be preferred. This patch resolves device not entering power save problem in certain situations Signed-off-by: Amitkumar Karwar Signed-off-by: Siva Rebbagondla Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 5edc3a9d8eeb..77aa3bb357a0 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -614,7 +614,7 @@ static int rsi_mac80211_config(struct ieee80211_hw *hw, /* Power save parameters */ if (changed & IEEE80211_CONF_CHANGE_PS) { - struct ieee80211_vif *vif; + struct ieee80211_vif *vif, *sta_vif = NULL; unsigned long flags; int i, set_ps = 1; @@ -628,13 +628,17 @@ static int rsi_mac80211_config(struct ieee80211_hw *hw, set_ps = 0; break; } + if ((vif->type == NL80211_IFTYPE_STATION || + vif->type == NL80211_IFTYPE_P2P_CLIENT) && + (!sta_vif || vif->bss_conf.assoc)) + sta_vif = vif; } - if (set_ps) { + if (set_ps && sta_vif) { spin_lock_irqsave(&adapter->ps_lock, flags); if (conf->flags & IEEE80211_CONF_PS) - rsi_enable_ps(adapter, vif); + rsi_enable_ps(adapter, sta_vif); else - rsi_disable_ps(adapter, vif); + rsi_disable_ps(adapter, sta_vif); spin_unlock_irqrestore(&adapter->ps_lock, flags); } } -- cgit v1.2.3 From a55e50f0672ec16c944b7e4f1168476661ea25a0 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 10 Apr 2018 20:34:14 +0530 Subject: rsi: increase max supported aggregation subframes Maximum number of supported aggregation subframes has been increased to 8. This is the optimal number for the driver. Signed-off-by: Amitkumar Karwar Signed-off-by: Siva Rebbagondla Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 3 ++- drivers/net/wireless/rsi/rsi_mgmt.h | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 77aa3bb357a0..2a777435a735 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -1955,7 +1955,8 @@ int rsi_mac80211_attach(struct rsi_common *common) hw->uapsd_queues = RSI_IEEE80211_UAPSD_QUEUES; hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL; - hw->max_tx_aggregation_subframes = 6; + hw->max_tx_aggregation_subframes = RSI_MAX_TX_AGGR_FRMS; + hw->max_rx_aggregation_subframes = RSI_MAX_RX_AGGR_FRMS; rsi_register_rates_channels(adapter, NL80211_BAND_2GHZ); rsi_register_rates_channels(adapter, NL80211_BAND_5GHZ); hw->rate_control_algorithm = "AARF"; diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index 5f946f31723f..14620935c925 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -225,6 +225,9 @@ #define RSI_WOW_DISCONNECT BIT(5) #endif +#define RSI_MAX_TX_AGGR_FRMS 8 +#define RSI_MAX_RX_AGGR_FRMS 8 + enum opmode { RSI_OPMODE_UNSUPPORTED = -1, RSI_OPMODE_AP = 0, -- cgit v1.2.3 From 3334306a086e6784ad32f395e5dcc9272ca0ce6e Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 10 Apr 2018 20:34:15 +0530 Subject: rsi: parse TID from data frame correctly Currently TID is extracted by checking at specific offset in data frame. This approach doesn't work for some of the frames. This patch uses mac80211 API and do it correctly Signed-off-by: Amitkumar Karwar Signed-off-by: Siva Rebbagondla Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index 3ca468b9f2b8..1f1b97220d43 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -432,7 +432,9 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) } } else { if (ieee80211_is_data_qos(wh->frame_control)) { - tid = (skb->data[24] & IEEE80211_QOS_TID); + u8 *qos = ieee80211_get_qos_ctl(wh); + + tid = *qos & IEEE80211_QOS_CTL_TID_MASK; skb->priority = TID_TO_WME_AC(tid); } else { tid = IEEE80211_NONQOS_TID; -- cgit v1.2.3 From 1e9c410f26a2ec3201b0f10141275afcbdaf6b69 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 10 Apr 2018 20:34:16 +0530 Subject: rsi: enable power save by default for coex Power save is by default enabled for WLAN and BT coex mode. Signed-off-by: Amitkumar Karwar Signed-off-by: Siva Rebbagondla Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 2a777435a735..bb497bd63563 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -2008,6 +2008,9 @@ int rsi_mac80211_attach(struct rsi_common *common) wiphy->iface_combinations = rsi_iface_combinations; wiphy->n_iface_combinations = ARRAY_SIZE(rsi_iface_combinations); + if (common->coex_mode > 1) + wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; + status = ieee80211_register_hw(hw); if (status) return status; -- cgit v1.2.3 From f0b147b8f1d27c9fa543704b21c67a7a3723c7d2 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 10 Apr 2018 20:34:17 +0530 Subject: rsi: advertise 5GHz support based on device capability Currently 5GHz gets advertised even for the device which supports only 2.4Ghz band. This patch fixes the issue Signed-off-by: Amitkumar Karwar Signed-off-by: Siva Rebbagondla Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index bb497bd63563..766d874cc6e2 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -1957,8 +1957,6 @@ int rsi_mac80211_attach(struct rsi_common *common) hw->max_tx_aggregation_subframes = RSI_MAX_TX_AGGR_FRMS; hw->max_rx_aggregation_subframes = RSI_MAX_RX_AGGR_FRMS; - rsi_register_rates_channels(adapter, NL80211_BAND_2GHZ); - rsi_register_rates_channels(adapter, NL80211_BAND_5GHZ); hw->rate_control_algorithm = "AARF"; SET_IEEE80211_PERM_ADDR(hw, common->mac_addr); @@ -1979,10 +1977,15 @@ int rsi_mac80211_attach(struct rsi_common *common) wiphy->available_antennas_rx = 1; wiphy->available_antennas_tx = 1; + + rsi_register_rates_channels(adapter, NL80211_BAND_2GHZ); wiphy->bands[NL80211_BAND_2GHZ] = &adapter->sbands[NL80211_BAND_2GHZ]; - wiphy->bands[NL80211_BAND_5GHZ] = - &adapter->sbands[NL80211_BAND_5GHZ]; + if (common->num_supp_bands > 1) { + rsi_register_rates_channels(adapter, NL80211_BAND_5GHZ); + wiphy->bands[NL80211_BAND_5GHZ] = + &adapter->sbands[NL80211_BAND_5GHZ]; + } /* AP Parameters */ wiphy->max_ap_assoc_sta = rsi_max_ap_stas[common->oper_mode - 1]; -- cgit v1.2.3 From f700546682a62a87a9615121a37ee7452dab4b76 Mon Sep 17 00:00:00 2001 From: Siva Rebbagondla Date: Wed, 11 Apr 2018 12:13:31 +0530 Subject: rsi: fix nommu_map_sg overflow kernel panic Following overflow kernel panic is observed on some platforms while loading the driver. It is fixed if dynamically allocated memory is passed to SDIO instead of static one [ 927.513963] nommu_map_sg: overflow 17d54064ba7c+20 of device mask ffffffff [ 927.517712] Modules linked in: rsi_sdio(+) cmac bnep arc4 rsi_91x mac80211 cfg80211 btrsi rfcomm bluetooth ecdh_generic snd_soc_sst_bytcr_rt5660 [ 927.517861] CPU: 0 PID: 1624 Comm: insmod Tainted: G W 4.15.0-1000 #1 [ 927.517870] RIP: 0010:sdhci_send_command+0x5f0/0xa90 [sdhci] [ 927.517873] RSP: 0000:ffffac3fc064b6d8 EFLAGS: 00010086 [ 927.517895] Call Trace: [ 927.517908] ? __schedule+0x3cd/0x890 [ 927.517915] ? mod_timer+0x17b/0x3c0 [ 927.517922] sdhci_request+0x7c/0xf0 [sdhci] [ 927.517928] __mmc_start_request+0x5a/0x170 [ 927.517932] mmc_start_request+0x74/0x90 [ 927.517936] mmc_wait_for_req+0x87/0xe0 [ 927.517940] mmc_io_rw_extended+0x2fd/0x330 [ 927.517946] ? mmc_wait_data_done+0x30/0x30 [ 927.517951] sdio_io_rw_ext_helper+0x160/0x210 [ 927.517956] sdio_writesb+0x1d/0x20 [ 927.517966] rsi_sdio_write_register_multiple+0x68/0x110 [rsi_sdio] [ 927.517976] rsi_hal_device_init+0x357/0x910 [rsi_91x] [ 927.517983] ? rsi_hal_device_init+0x357/0x910 [rsi_91x] [ 927.517990] rsi_probe+0x2c6/0x450 [rsi_sdio] [ 927.517995] sdio_bus_probe+0xfc/0x110 [ 927.518000] driver_probe_device+0x2b3/0x490 [ 927.518005] __driver_attach+0xdf/0xf0 [ 927.518008] ? driver_probe_device+0x490/0x490 [ 927.518014] bus_for_each_dev+0x6c/0xc0 [ 927.518018] driver_attach+0x1e/0x20 [ 927.518021] bus_add_driver+0x1f4/0x270 [ 927.518028] ? rsi_sdio_ack_intr+0x50/0x50 [rsi_sdio] [ 927.518031] driver_register+0x60/0xe0 [ 927.518038] ? rsi_sdio_ack_intr+0x50/0x50 [rsi_sdio] [ 927.518041] sdio_register_driver+0x20/0x30 [ 927.518047] rsi_module_init+0x16/0x40 [rsi_sdio] Signed-off-by: Siva Rebbagondla Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_hal.c | 35 ++++++++++++++++++++------------- drivers/net/wireless/rsi/rsi_91x_sdio.c | 21 +++++++++++++------- drivers/net/wireless/rsi/rsi_sdio.h | 2 +- 3 files changed, 36 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index b7c54037f369..0761e61591bd 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -635,28 +635,32 @@ static int bl_write_header(struct rsi_hw *adapter, u8 *flash_content, u32 content_size) { struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; - struct bl_header bl_hdr; + struct bl_header *bl_hdr; u32 write_addr, write_len; int status; - bl_hdr.flags = 0; - bl_hdr.image_no = cpu_to_le32(adapter->priv->coex_mode); - bl_hdr.check_sum = cpu_to_le32( - *(u32 *)&flash_content[CHECK_SUM_OFFSET]); - bl_hdr.flash_start_address = cpu_to_le32( - *(u32 *)&flash_content[ADDR_OFFSET]); - bl_hdr.flash_len = cpu_to_le32(*(u32 *)&flash_content[LEN_OFFSET]); + bl_hdr = kzalloc(sizeof(*bl_hdr), GFP_KERNEL); + if (!bl_hdr) + return -ENOMEM; + + bl_hdr->flags = 0; + bl_hdr->image_no = cpu_to_le32(adapter->priv->coex_mode); + bl_hdr->check_sum = + cpu_to_le32(*(u32 *)&flash_content[CHECK_SUM_OFFSET]); + bl_hdr->flash_start_address = + cpu_to_le32(*(u32 *)&flash_content[ADDR_OFFSET]); + bl_hdr->flash_len = cpu_to_le32(*(u32 *)&flash_content[LEN_OFFSET]); write_len = sizeof(struct bl_header); if (adapter->rsi_host_intf == RSI_HOST_INTF_USB) { write_addr = PING_BUFFER_ADDRESS; status = hif_ops->write_reg_multiple(adapter, write_addr, - (u8 *)&bl_hdr, write_len); + (u8 *)bl_hdr, write_len); if (status < 0) { rsi_dbg(ERR_ZONE, "%s: Failed to load Version/CRC structure\n", __func__); - return status; + goto fail; } } else { write_addr = PING_BUFFER_ADDRESS >> 16; @@ -665,20 +669,23 @@ static int bl_write_header(struct rsi_hw *adapter, u8 *flash_content, rsi_dbg(ERR_ZONE, "%s: Unable to set ms word to common reg\n", __func__); - return status; + goto fail; } write_addr = RSI_SD_REQUEST_MASTER | (PING_BUFFER_ADDRESS & 0xFFFF); status = hif_ops->write_reg_multiple(adapter, write_addr, - (u8 *)&bl_hdr, write_len); + (u8 *)bl_hdr, write_len); if (status < 0) { rsi_dbg(ERR_ZONE, "%s: Failed to load Version/CRC structure\n", __func__); - return status; + goto fail; } } - return 0; + status = 0; +fail: + kfree(bl_hdr); + return status; } static u32 read_flash_capacity(struct rsi_hw *adapter) diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 8ef00582c6ea..f7f282098696 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -1038,17 +1038,21 @@ static void ulp_read_write(struct rsi_hw *adapter, u16 addr, u32 data, /*This function resets and re-initializes the chip.*/ static void rsi_reset_chip(struct rsi_hw *adapter) { - __le32 data; + u8 *data; u8 sdio_interrupt_status = 0; u8 request = 1; int ret; + data = kzalloc(sizeof(u32), GFP_KERNEL); + if (!data) + return; + rsi_dbg(INFO_ZONE, "Writing disable to wakeup register\n"); ret = rsi_sdio_write_register(adapter, 0, SDIO_WAKEUP_REG, &request); if (ret < 0) { rsi_dbg(ERR_ZONE, "%s: Failed to write SDIO wakeup register\n", __func__); - return; + goto err; } msleep(20); ret = rsi_sdio_read_register(adapter, RSI_FN1_INT_REGISTER, @@ -1056,7 +1060,7 @@ static void rsi_reset_chip(struct rsi_hw *adapter) if (ret < 0) { rsi_dbg(ERR_ZONE, "%s: Failed to Read Intr Status Register\n", __func__); - return; + goto err; } rsi_dbg(INFO_ZONE, "%s: Intr Status Register value = %d\n", __func__, sdio_interrupt_status); @@ -1066,17 +1070,17 @@ static void rsi_reset_chip(struct rsi_hw *adapter) rsi_dbg(ERR_ZONE, "%s: Unable to set ms word to common reg\n", __func__); - return; + goto err; } - data = TA_HOLD_THREAD_VALUE; + put_unaligned_le32(TA_HOLD_THREAD_VALUE, data); if (rsi_sdio_write_register_multiple(adapter, TA_HOLD_THREAD_REG | RSI_SD_REQUEST_MASTER, - (u8 *)&data, 4)) { + data, 4)) { rsi_dbg(ERR_ZONE, "%s: Unable to hold Thread-Arch processor threads\n", __func__); - return; + goto err; } /* This msleep will ensure Thread-Arch processor to go to hold @@ -1097,6 +1101,9 @@ static void rsi_reset_chip(struct rsi_hw *adapter) * read write operations to complete for chip reset. */ msleep(500); +err: + kfree(data); + return; } /** diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h index ead8e7c4df3a..353dbdf31e75 100644 --- a/drivers/net/wireless/rsi/rsi_sdio.h +++ b/drivers/net/wireless/rsi/rsi_sdio.h @@ -87,7 +87,7 @@ enum sdio_interrupt_type { #define TA_SOFT_RST_CLR 0 #define TA_SOFT_RST_SET BIT(0) #define TA_PC_ZERO 0 -#define TA_HOLD_THREAD_VALUE cpu_to_le32(0xF) +#define TA_HOLD_THREAD_VALUE 0xF #define TA_RELEASE_THREAD_VALUE cpu_to_le32(0xF) #define TA_BASE_ADDR 0x2200 #define MISC_CFG_BASE_ADDR 0x4105 -- cgit v1.2.3 From 78e450719c702784e42af6da912d3692fd3da0cb Mon Sep 17 00:00:00 2001 From: Siva Rebbagondla Date: Wed, 11 Apr 2018 12:13:32 +0530 Subject: rsi: Fix 'invalid vdd' warning in mmc While performing cleanup, driver is messing with card->ocr value by not masking rocr against ocr_avail. Below panic is observed with some of the SDIO host controllers due to this. Issue is resolved by reverting incorrect modifications to vdd. [ 927.423821] mmc1: Invalid vdd 0x1f [ 927.423925] Modules linked in: rsi_sdio(+) cmac bnep arc4 rsi_91x mac80211 cfg80211 btrsi rfcomm bluetooth ecdh_generic [ 927.424073] CPU: 0 PID: 1624 Comm: insmod Tainted: G W 4.15.0-1000-caracalla #1 [ 927.424075] Hardware name: Dell Inc. Edge Gateway 3003/ , BIOS 01.00.06 01/22/2018 [ 927.424082] RIP: 0010:sdhci_set_power_noreg+0xdd/0x190[sdhci] [ 927.424085] RSP: 0018:ffffac3fc064b930 EFLAGS: 00010282 [ 927.424107] Call Trace: [ 927.424118] sdhci_set_power+0x5a/0x60 [sdhci] [ 927.424125] sdhci_set_ios+0x360/0x3b0 [sdhci] [ 927.424133] mmc_set_initial_state+0x92/0x120 [ 927.424137] mmc_power_up.part.34+0x33/0x1d0 [ 927.424141] mmc_power_up+0x17/0x20 [ 927.424147] mmc_sdio_runtime_resume+0x2d/0x50 [ 927.424151] mmc_runtime_resume+0x17/0x20 [ 927.424156] __rpm_callback+0xc4/0x200 [ 927.424161] ? idr_alloc_cyclic+0x57/0xd0 [ 927.424165] ? mmc_runtime_suspend+0x20/0x20 [ 927.424169] rpm_callback+0x24/0x80 [ 927.424172] ? mmc_runtime_suspend+0x20/0x20 [ 927.424176] rpm_resume+0x4b3/0x6c0 [ 927.424181] __pm_runtime_resume+0x4e/0x80 [ 927.424188] driver_probe_device+0x41/0x490 [ 927.424192] __driver_attach+0xdf/0xf0 [ 927.424196] ? driver_probe_device+0x490/0x490 [ 927.424201] bus_for_each_dev+0x6c/0xc0 [ 927.424205] driver_attach+0x1e/0x20 [ 927.424209] bus_add_driver+0x1f4/0x270 [ 927.424217] ? rsi_sdio_ack_intr+0x50/0x50 [rsi_sdio] [ 927.424221] driver_register+0x60/0xe0 [ 927.424227] ? rsi_sdio_ack_intr+0x50/0x50 [rsi_sdio] [ 927.424231] sdio_register_driver+0x20/0x30 [ 927.424237] rsi_module_init+0x16/0x40 [rsi_sdio] Signed-off-by: Siva Rebbagondla Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_sdio.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index f7f282098696..416981d99229 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -170,7 +170,6 @@ static void rsi_reset_card(struct sdio_func *pfunction) int err; struct mmc_card *card = pfunction->card; struct mmc_host *host = card->host; - s32 bit = (fls(host->ocr_avail) - 1); u8 cmd52_resp; u32 clock, resp, i; u16 rca; @@ -190,7 +189,6 @@ static void rsi_reset_card(struct sdio_func *pfunction) msleep(20); /* Initialize the SDIO card */ - host->ios.vdd = bit; host->ios.chip_select = MMC_CS_DONTCARE; host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; host->ios.power_mode = MMC_POWER_UP; -- cgit v1.2.3 From 8cf304a85378b54b8a86bf2ed130da56dd59b251 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 9 Apr 2018 15:51:31 +0800 Subject: rtlwifi: btcoex: remove identical statements within if-else branches Since the statements are identical, we can safely remove the statements. The commit 42e74946f016 ("rtlwifi: btcoexist: Fix if == else warnings in halbtc8821a1ant.c") had fixed the statements, but the commit c6821613e653 ("rtlwifi: btcoex: follow linux coding style") that converted coding style and upgraded btcoex didn't include the fix. Reported-by: Gustavo A. R. Silva Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 202597cf8915..b5d65872db84 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -1584,11 +1584,7 @@ static void btc8821a1ant_act_bt_sco_hid_only_busy(struct btc_coexist *btcoexist, /* tdma and coex table */ btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); - if (BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == - wifi_status) - btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); - else - btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); } static void btc8821a1ant_act_wifi_con_bt_acl_busy(struct btc_coexist *btcoexist, @@ -1991,16 +1987,9 @@ static void btc8821a1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) wifi_rssi_state = btc8821a1ant_wifi_rssi_state(btcoexist, 1, 2, 30, 0); - if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || - (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - btc8821a1ant_limited_tx(btcoexist, - NORMAL_EXEC, 1, 1, - 0, 1); - } else { - btc8821a1ant_limited_tx(btcoexist, - NORMAL_EXEC, 1, 1, - 0, 1); - } + btc8821a1ant_limited_tx(btcoexist, + NORMAL_EXEC, 1, 1, + 0, 1); } else { btc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); -- cgit v1.2.3 From 5156b054bcdab19dc2681fb606011378e9dd37e2 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 30 Mar 2018 16:12:23 -0500 Subject: mt7601u: phy: mark expected switch fall-through In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. Signed-off-by: Gustavo A. R. Silva Acked-by: Jakub Kicinski Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt7601u/phy.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt7601u/phy.c b/drivers/net/wireless/mediatek/mt7601u/phy.c index ca09a5d4305e..9a90f1f09fb0 100644 --- a/drivers/net/wireless/mediatek/mt7601u/phy.c +++ b/drivers/net/wireless/mediatek/mt7601u/phy.c @@ -795,6 +795,7 @@ mt7601u_phy_rf_pa_mode_val(struct mt7601u_dev *dev, int phy_mode, int tx_rate) switch (phy_mode) { case MT_PHY_TYPE_OFDM: tx_rate += 4; + /* fall through */ case MT_PHY_TYPE_CCK: reg = dev->rf_pa_mode[0]; break; -- cgit v1.2.3 From 2cb161094ef940f191cf60cd512783269572b4a7 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 3 Apr 2018 16:45:31 +0200 Subject: mt76x2: fix tssi initialization for 5GHz band Fix mcu initial configuration for tssi calibration on 5GHz band Fixes: 7bc04215a66b ("mt76: add driver code for MT76x2e") Signed-off-by: Lorenzo Bianconi Acked-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x2_phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c index fcc37eb7ce0b..f28c55746cea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c @@ -180,7 +180,7 @@ mt76x2_phy_tssi_init_cal(struct mt76x2_dev *dev) if (mt76x2_channel_silent(dev)) return false; - if (chan->band == NL80211_BAND_2GHZ) + if (chan->band == NL80211_BAND_5GHZ) flag |= BIT(0); if (mt76x2_ext_pa_enabled(dev, chan->band)) -- cgit v1.2.3 From 00dfae9a0ab7594b77d39725ebff677900695d70 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 3 Apr 2018 17:01:43 +0200 Subject: mt76x2: make mt76x2_mac_reset routine static Add static qualifier to mt76x2_mac_reset routine and remove the prototype from mt76x2_mac.h since it is used just in mt76x2_init.c Signed-off-by: Lorenzo Bianconi Acked-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x2_init.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2_mac.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index 934c331d995e..359b105235b3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -228,7 +228,7 @@ mt76x2_init_beacon_offsets(struct mt76x2_dev *dev) mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]); } -int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard) +static int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard) { static const u8 null_addr[ETH_ALEN] = {}; const u8 *macaddr = dev->mt76.macaddr; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h index 8a8a25e32d5f..c048cd06df6b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.h @@ -157,7 +157,6 @@ mt76x2_skb_tx_info(struct sk_buff *skb) return (void *) info->status.status_driver_data; } -int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard); int mt76x2_mac_start(struct mt76x2_dev *dev); void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force); void mt76x2_mac_resume(struct mt76x2_dev *dev); -- cgit v1.2.3 From 11b2a25f02b700027aa89ff27c807ec756df01f6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 3 Apr 2018 21:52:48 +0200 Subject: mt76: stop tx queues from the driver callback instead of common code Allows the driver to control whether to send a BlockAckReq after waking up. MT76x2 needs this set to true, for MT7603 (to be submitted later) it needs to be false. Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mac80211.c | 6 ++---- drivers/net/wireless/mediatek/mt76/mt76x2_main.c | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 4f30cdcd2b53..962ed8234065 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -541,12 +541,10 @@ mt76_check_ps(struct mt76_dev *dev, struct sk_buff *skb) if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps) return; - if (ps) { + if (ps) set_bit(MT_WCID_FLAG_PS, &wcid->flags); - mt76_stop_tx_queues(dev, sta, true); - } else { + else clear_bit(MT_WCID_FLAG_PS, &wcid->flags); - } ieee80211_sta_ps_transition(sta, ps); dev->drv->sta_ps(dev, sta, ps); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index 73c127f92613..81c58f865c64 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -321,6 +321,7 @@ mt76x2_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); int idx = msta->wcid.idx; + mt76_stop_tx_queues(&dev->mt76, sta, true); mt76x2_mac_wcid_set_drop(dev, idx, ps); } -- cgit v1.2.3 From 49149d3f1c6bfb314db1f386cf5067e5151ee0aa Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 3 Apr 2018 21:52:49 +0200 Subject: mt76: add missing VHT maximum A-MPDU length capability Signficantly improves throughput with some clients Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mac80211.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 962ed8234065..ec531ce50d01 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -213,7 +213,8 @@ mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband, vht_cap->vht_supported = true; vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC | IEEE80211_VHT_CAP_RXSTBC_1 | - IEEE80211_VHT_CAP_SHORT_GI_80; + IEEE80211_VHT_CAP_SHORT_GI_80 | + (3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT); return 0; } -- cgit v1.2.3 From 9f67c277a80f37a6594ae4ea3b78157773e1a23b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 3 Apr 2018 21:52:50 +0200 Subject: mt76: toggle driver station powersave bit before notifying mac80211 Avoids race conditions from mac80211 enqueueing tx packets before the tx-drop bit is cleared Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mac80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index ec531ce50d01..eb49e0a6758c 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -547,8 +547,8 @@ mt76_check_ps(struct mt76_dev *dev, struct sk_buff *skb) else clear_bit(MT_WCID_FLAG_PS, &wcid->flags); - ieee80211_sta_ps_transition(sta, ps); dev->drv->sta_ps(dev, sta, ps); + ieee80211_sta_ps_transition(sta, ps); } void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, -- cgit v1.2.3 From 80f28994f7d9c01e2af3d8584874cfc1904a7553 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 3 Apr 2018 21:52:51 +0200 Subject: mt76: rework tx power handling There were a number of issues in the existing tx power handling code: 1. The EEPROM target power for chain 0 refers to the actual output power after the channel and bandwidth delta have been added to the initial channel gain. This means the delta values should not be added/subtracted for the rate power calculation 2. When power is reduced significantly, the initial channel gain underflows very quickly, while the per-rate power offsets are high. This miscalculation causes effective tx power to be increased when it should actually be lowered. Fix this by trying to adjust the channel gain to the lowest power from the rate table. In case of under- or overflow, compensate by adding an appropriate delta to the rate power values. This makes power configuration more accurate on a wider range of configurable values Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x2_phy.c | 67 ++++++++++++++++--------- 1 file changed, 42 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c index f28c55746cea..a4280a9f6956 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c @@ -73,16 +73,6 @@ int mt76x2_phy_get_rssi(struct mt76x2_dev *dev, s8 rssi, int chain) return rssi; } -static u8 -mt76x2_txpower_check(int value) -{ - if (value < 0) - return 0; - if (value > 0x2f) - return 0x2f; - return value; -} - static void mt76x2_add_rate_power_offset(struct mt76_rate_power *r, int offset) { @@ -102,6 +92,26 @@ mt76x2_limit_rate_power(struct mt76_rate_power *r, int limit) r->all[i] = limit; } +static int +mt76x2_get_min_rate_power(struct mt76_rate_power *r) +{ + int i; + s8 ret = 0; + + for (i = 0; i < sizeof(r->all); i++) { + if (!r->all[i]) + continue; + + if (ret) + ret = min(ret, r->all[i]); + else + ret = r->all[i]; + } + + return ret; +} + + void mt76x2_phy_set_txpower(struct mt76x2_dev *dev) { enum nl80211_chan_width width = dev->mt76.chandef.width; @@ -109,6 +119,7 @@ void mt76x2_phy_set_txpower(struct mt76x2_dev *dev) struct mt76x2_tx_power_info txp; int txp_0, txp_1, delta = 0; struct mt76_rate_power t = {}; + int base_power, gain; mt76x2_get_power_info(dev, &txp, chan); @@ -117,26 +128,32 @@ void mt76x2_phy_set_txpower(struct mt76x2_dev *dev) else if (width == NL80211_CHAN_WIDTH_80) delta = txp.delta_bw80; - if (txp.target_power > dev->txpower_conf) - delta -= txp.target_power - dev->txpower_conf; - mt76x2_get_rate_power(dev, &t, chan); - mt76x2_add_rate_power_offset(&t, txp.chain[0].target_power + - txp.chain[0].delta); + mt76x2_add_rate_power_offset(&t, txp.chain[0].target_power); mt76x2_limit_rate_power(&t, dev->txpower_conf); dev->txpower_cur = mt76x2_get_max_rate_power(&t); - mt76x2_add_rate_power_offset(&t, -(txp.chain[0].target_power + - txp.chain[0].delta + delta)); - dev->target_power = txp.chain[0].target_power; - dev->target_power_delta[0] = txp.chain[0].delta + delta; - dev->target_power_delta[1] = txp.chain[1].delta + delta; - dev->rate_power = t; - txp_0 = mt76x2_txpower_check(txp.chain[0].target_power + - txp.chain[0].delta + delta); + base_power = mt76x2_get_min_rate_power(&t); + delta += base_power - txp.chain[0].target_power; + txp_0 = txp.chain[0].target_power + txp.chain[0].delta + delta; + txp_1 = txp.chain[1].target_power + txp.chain[1].delta + delta; + + gain = min(txp_0, txp_1); + if (gain < 0) { + base_power -= gain; + txp_0 -= gain; + txp_1 -= gain; + } else if (gain > 0x2f) { + base_power -= gain - 0x2f; + txp_0 = 0x2f; + txp_1 = 0x2f; + } - txp_1 = mt76x2_txpower_check(txp.chain[1].target_power + - txp.chain[1].delta + delta); + mt76x2_add_rate_power_offset(&t, -base_power); + dev->target_power = txp.chain[0].target_power; + dev->target_power_delta[0] = txp_0 - txp.chain[0].target_power; + dev->target_power_delta[1] = txp_1 - txp.chain[0].target_power; + dev->rate_power = t; mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_0, txp_0); mt76_rmw_field(dev, MT_TX_ALC_CFG_0, MT_TX_ALC_CFG_0_CH_INIT_1, txp_1); -- cgit v1.2.3 From 07073a2768ac8ef1360f715a68c3f7b7d1f23850 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 3 Apr 2018 21:52:52 +0200 Subject: mt76: fix potential sleep in atomic context Use cancel_delayed_work instead of cancel_delayed_work_sync Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/agg-rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c index fcb208d1f276..cbac42cb536c 100644 --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c @@ -273,7 +273,7 @@ static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid) spin_unlock_bh(&tid->lock); - cancel_delayed_work_sync(&tid->reorder_work); + cancel_delayed_work(&tid->reorder_work); } void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno) -- cgit v1.2.3 From 18efed59fabc0d0f6dd9888b5f0e8102c8332685 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 3 Apr 2018 21:52:53 +0200 Subject: mt76: set RX_FLAG_DUP_VALIDATED for A-MPDU reordered packets Required for fast-rx and allows mac80211 to skip an unnnecessary check. Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/agg-rx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c index cbac42cb536c..6657ec8928de 100644 --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c @@ -169,6 +169,7 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames) if (!tid) return; + status->flag |= RX_FLAG_DUP_VALIDATED; spin_lock_bh(&tid->lock); if (tid->stopped) -- cgit v1.2.3 From 1af83148a4fc31858383e8ee867f5b9f9c2432cd Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 3 Apr 2018 21:52:54 +0200 Subject: mt76: check qos ack policy before reordering packets Do not attempt to reorder packets not part of a BA session Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/agg-rx.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c index 6657ec8928de..dbf4057d2d3e 100644 --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c @@ -147,12 +147,13 @@ mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames) void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames) { struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct mt76_wcid *wcid = status->wcid; struct ieee80211_sta *sta; struct mt76_rx_tid *tid; bool sn_less; u16 seqno, head, size; - u8 idx; + u8 ackp, idx; __skb_queue_tail(frames, skb); @@ -165,6 +166,12 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames) return; } + /* not part of a BA session */ + ackp = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_ACK_POLICY_MASK; + if (ackp != IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK && + ackp != IEEE80211_QOS_CTL_ACK_POLICY_NORMAL) + return; + tid = rcu_dereference(wcid->aggr[status->tid]); if (!tid) return; -- cgit v1.2.3 From cf7b411dcea8849e1802bd1ac35249b33050afed Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 3 Apr 2018 22:30:19 +0200 Subject: mt76x2: remove unnecessary MT_TX_ALC_CFG_4 configuration Remove unnecessary MT_TX_ALC_CFG_4 configuration since the register value will be properly set according to the usage of an external power amplifier Signed-off-by: Lorenzo Bianconi Acked-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x2_phy.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c index a4280a9f6956..79c698ada818 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c @@ -274,7 +274,6 @@ mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev, enum nl80211_band band) mt76_wr(dev, MT_TX_ALC_CFG_2, 0x1b0f0400); mt76_wr(dev, MT_TX_ALC_CFG_3, 0x1b0f0476); } - mt76_wr(dev, MT_TX_ALC_CFG_4, 0); if (mt76x2_ext_pa_enabled(dev, band)) pa_mode_adj = 0x04000000; -- cgit v1.2.3 From bcb0f68ae2eda3f4e124aa25bd0f5ae7afaba33c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 4 Apr 2018 10:23:46 +0200 Subject: mt76x2: fix tx_alc_enabled check Fix mt76x2_temp_tx_alc_enabled routine since in order to enable tx_alc temperature compensation it necessary to take into account BIT(15) of MT_EE_TX_POWER_EXT_PA_5G eeprom info Fixes: 7bc04215a66b ("mt76: add driver code for MT76x2e") Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c | 6 +----- drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h | 6 ++++++ 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c index 5bb50027c1e8..95d5f7d888f0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.c @@ -609,17 +609,13 @@ int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t) memset(t, 0, sizeof(*t)); - val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1); - if (!(val & MT_EE_NIC_CONF_1_TEMP_TX_ALC)) + if (!mt76x2_temp_tx_alc_enabled(dev)) return -EINVAL; if (!mt76x2_ext_pa_enabled(dev, band)) return -EINVAL; val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G) >> 8; - if (!(val & BIT(7))) - return -EINVAL; - t->temp_25_ref = val & 0x7f; if (band == NL80211_BAND_5GHZ) { slope = mt76x2_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_5G); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h index d79122728dca..aa0b0c040375 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_eeprom.h @@ -159,6 +159,12 @@ void mt76x2_read_rx_gain(struct mt76x2_dev *dev); static inline bool mt76x2_temp_tx_alc_enabled(struct mt76x2_dev *dev) { + u16 val; + + val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G); + if (!(val & BIT(15))) + return false; + return mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) & MT_EE_NIC_CONF_1_TEMP_TX_ALC; } -- cgit v1.2.3 From b9e5d4feb4fc0ec0823e5da3bdea1c01d38f448e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 4 Apr 2018 10:38:32 +0200 Subject: mt76x2: set default values in TX_ALC_CFG_{1, 2} for tempetaure compensation Initialize default values for temperature compensation in TX_ALC_CFG_{1,2} if tssi has been enabled Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x2_phy.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c index 79c698ada818..038d1fe6c726 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c @@ -677,6 +677,14 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev, memcpy(dev->cal.agc_gain_cur, dev->cal.agc_gain_init, sizeof(dev->cal.agc_gain_cur)); + /* init default values for temp compensation */ + if (mt76x2_tssi_enabled(dev)) { + mt76_rmw_field(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, + 0x38); + mt76_rmw_field(dev, MT_TX_ALC_CFG_2, MT_TX_ALC_CFG_2_TEMP_COMP, + 0x38); + } + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work, MT_CALIBRATE_INTERVAL); -- cgit v1.2.3 From b305a6ab02475f52ef604b36e4cecd3bf4aa5eb7 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 16 Apr 2018 13:56:17 +0200 Subject: mt7601u: use EWMA to calculate avg_rssi avr_rssi is not calculated correctly as we do not divide result by 256 (mt76 sum avg_rssi1 and avg_rssi2 and divide by 512). However dividing by 256 will make avg_rssi almost the same as last rssi value - not really an average. So use EWMA to calculate avg_rssi. I've chosen weight_rcp=4 to convergence quicker on signal strength changes. Signed-off-by: Stanislaw Gruszka Acked-by: Jakub Kicinski Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt7601u/mac.c | 4 ++-- drivers/net/wireless/mediatek/mt7601u/mt7601u.h | 5 ++++- drivers/net/wireless/mediatek/mt7601u/phy.c | 10 +++++++--- 3 files changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.c b/drivers/net/wireless/mediatek/mt7601u/mac.c index d55d7040a56d..148c36d3d2e5 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mac.c +++ b/drivers/net/wireless/mediatek/mt7601u/mac.c @@ -453,7 +453,7 @@ mt7601u_rx_monitor_beacon(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi, { dev->bcn_freq_off = rxwi->freq_off; dev->bcn_phy_mode = FIELD_GET(MT_RXWI_RATE_PHY, rate); - dev->avg_rssi = (dev->avg_rssi * 15) / 16 + (rssi << 8); + ewma_rssi_add(&dev->avg_rssi, -rssi); } static int @@ -503,7 +503,7 @@ u32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb, if (mt7601u_rx_is_our_beacon(dev, data)) mt7601u_rx_monitor_beacon(dev, rxwi, rate, rssi); else if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_U2M)) - dev->avg_rssi = (dev->avg_rssi * 15) / 16 + (rssi << 8); + ewma_rssi_add(&dev->avg_rssi, -rssi); spin_unlock_bh(&dev->con_mon_lock); return len; diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h index 9233744451a9..db317d8c1652 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "regs.h" @@ -138,6 +139,8 @@ enum { MT7601U_STATE_MORE_STATS, }; +DECLARE_EWMA(rssi, 10, 4); + /** * struct mt7601u_dev - adapter structure * @lock: protects @wcid->tx_rate. @@ -220,7 +223,7 @@ struct mt7601u_dev { s8 bcn_freq_off; u8 bcn_phy_mode; - int avg_rssi; /* starts at 0 and converges */ + struct ewma_rssi avg_rssi; u8 agc_save; diff --git a/drivers/net/wireless/mediatek/mt7601u/phy.c b/drivers/net/wireless/mediatek/mt7601u/phy.c index 9a90f1f09fb0..9d2f9a776ef1 100644 --- a/drivers/net/wireless/mediatek/mt7601u/phy.c +++ b/drivers/net/wireless/mediatek/mt7601u/phy.c @@ -975,6 +975,7 @@ void mt7601u_agc_restore(struct mt7601u_dev *dev) static void mt7601u_agc_tune(struct mt7601u_dev *dev) { u8 val = mt7601u_agc_default(dev); + long avg_rssi; if (test_bit(MT7601U_STATE_SCANNING, &dev->state)) return; @@ -984,9 +985,12 @@ static void mt7601u_agc_tune(struct mt7601u_dev *dev) * Rssi updates are only on beacons and U2M so should work... */ spin_lock_bh(&dev->con_mon_lock); - if (dev->avg_rssi <= -70) + avg_rssi = ewma_rssi_read(&dev->avg_rssi); + WARN_ON_ONCE(avg_rssi == 0); + avg_rssi = -avg_rssi; + if (avg_rssi <= -70) val -= 0x20; - else if (dev->avg_rssi <= -60) + else if (avg_rssi <= -60) val -= 0x10; spin_unlock_bh(&dev->con_mon_lock); @@ -1102,7 +1106,7 @@ void mt7601u_phy_con_cal_onoff(struct mt7601u_dev *dev, /* Start/stop collecting beacon data */ spin_lock_bh(&dev->con_mon_lock); ether_addr_copy(dev->ap_bssid, info->bssid); - dev->avg_rssi = 0; + ewma_rssi_init(&dev->avg_rssi); dev->bcn_freq_off = MT_FREQ_OFFSET_INVALID; spin_unlock_bh(&dev->con_mon_lock); -- cgit v1.2.3 From 2019c39a2d6081e09436254fba320708e8127691 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 16 Apr 2018 13:56:18 +0200 Subject: mt7601u: run calibration works after finishing scanning When finishing scanning we switch to operational channel sill with SCANNING flag. This mean that we never perform calibration works after scanning. To fix the problem queue calibration works on .sw_scan_complete() routine. Signed-off-by: Stanislaw Gruszka Acked-by: Jakub Kicinski Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt7601u/main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt7601u/main.c b/drivers/net/wireless/mediatek/mt7601u/main.c index 3c9ea40d9584..7b21016012c3 100644 --- a/drivers/net/wireless/mediatek/mt7601u/main.c +++ b/drivers/net/wireless/mediatek/mt7601u/main.c @@ -288,6 +288,12 @@ mt7601u_sw_scan_complete(struct ieee80211_hw *hw, mt7601u_agc_restore(dev); clear_bit(MT7601U_STATE_SCANNING, &dev->state); + + ieee80211_queue_delayed_work(dev->hw, &dev->cal_work, + MT_CALIBRATE_INTERVAL); + if (dev->freq_cal.enabled) + ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work, + MT_FREQ_CAL_INIT_DELAY); } static int -- cgit v1.2.3 From cc6603aaeebf75751f5c3b79bc38ab62a0a55e7e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 17 Apr 2018 01:05:59 +0200 Subject: mt76x2: fix TXD_INFO bitmask definition Despite this issue is not harmful since it is not actually used in mt76 driver, fix DMA txinfo bitmask definition Fixes: 7bc04215a66b ('mt76: add driver code for MT76x2e') Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x2_dma.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.h b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.h index 47f79d83fcb4..e9d426bbf91a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_dma.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_dma.h @@ -19,7 +19,7 @@ #include "dma.h" -#define MT_TXD_INFO_LEN GENMASK(13, 0) +#define MT_TXD_INFO_LEN GENMASK(15, 0) #define MT_TXD_INFO_NEXT_VLD BIT(16) #define MT_TXD_INFO_TX_BURST BIT(17) #define MT_TXD_INFO_80211 BIT(19) @@ -27,9 +27,8 @@ #define MT_TXD_INFO_CSO BIT(21) #define MT_TXD_INFO_WIV BIT(24) #define MT_TXD_INFO_QSEL GENMASK(26, 25) -#define MT_TXD_INFO_TCO BIT(29) -#define MT_TXD_INFO_UCO BIT(30) -#define MT_TXD_INFO_ICO BIT(31) +#define MT_TXD_INFO_DPORT GENMASK(29, 27) +#define MT_TXD_INFO_TYPE GENMASK(31, 30) #define MT_RX_FCE_INFO_LEN GENMASK(13, 0) #define MT_RX_FCE_INFO_SELF_GEN BIT(15) -- cgit v1.2.3 From d6c38be09af0c2805cb858e3a20a2b29b2c04735 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 2 Apr 2018 20:31:22 +0800 Subject: mwifiex: uap: filter duplicate ERP IE Firmware parse and attach ERP IE from bss configuration, do not set again from tail IE. Signed-off-by: Xinming Hu Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/ie.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/ie.c b/drivers/net/wireless/marvell/mwifiex/ie.c index 922e3d69fd84..b10baacb51c9 100644 --- a/drivers/net/wireless/marvell/mwifiex/ie.c +++ b/drivers/net/wireless/marvell/mwifiex/ie.c @@ -349,6 +349,7 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv, case WLAN_EID_SUPP_RATES: case WLAN_EID_COUNTRY: case WLAN_EID_PWR_CONSTRAINT: + case WLAN_EID_ERP_INFO: case WLAN_EID_EXT_SUPP_RATES: case WLAN_EID_HT_CAPABILITY: case WLAN_EID_HT_OPERATION: -- cgit v1.2.3 From c1003538bf6b28a4bae8e511672fa5abaabe683c Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 2 Apr 2018 20:31:23 +0800 Subject: mwifiex: uap: support cfg80211 ignore_broadcast_ssid=2 Firmware already support hidden ssid and keep ssid length, Open the capability in driver. Signed-off-by: Xinming Hu Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 7f7e9de2db1c..4857b75e54a7 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -1979,7 +1979,8 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, bss_cfg->bcast_ssid_ctl = 0; break; case NL80211_HIDDEN_SSID_ZERO_CONTENTS: - /* firmware doesn't support this type of hidden SSID */ + bss_cfg->bcast_ssid_ctl = 2; + break; default: kfree(bss_cfg); return -EINVAL; -- cgit v1.2.3 From 01eca2842874b9a85b7cd1e1b0e5b34a5d53a21f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 5 Apr 2018 14:17:19 +0300 Subject: mwifiex: pcie: tighten a check in mwifiex_pcie_process_event_ready() If "evt_len" is 1 then we try to memcpy() negative 3 bytes and it would cause memory corruption. Fixes: d930faee141b ("mwifiex: add support for Marvell pcie8766 chipset") Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/pcie.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 97a6199692ab..7538543d46fa 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -1881,7 +1881,8 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) mwifiex_dbg(adapter, EVENT, "info: Event length: %d\n", evt_len); - if ((evt_len > 0) && (evt_len < MAX_EVENT_SIZE)) + if (evt_len > MWIFIEX_EVENT_HEADER_LEN && + evt_len < MAX_EVENT_SIZE) memcpy(adapter->event_body, skb_cmd->data + MWIFIEX_EVENT_HEADER_LEN, evt_len - MWIFIEX_EVENT_HEADER_LEN); -- cgit v1.2.3 From 1f589e2510d5df1192dca7c089103a2cbd028101 Mon Sep 17 00:00:00 2001 From: Dan Haab Date: Tue, 3 Apr 2018 10:21:56 +0200 Subject: brcmfmac: add support for BCM4366E chipset BCM4366E is a wireless chipset with a BCM43664 ChipCommon. It's supported by the same firmware as 4366c0. Signed-off-by: Dan Haab [arend: rebase patch and remove unnecessary definition] Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 1 + drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 1 + drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h | 1 + 3 files changed, 3 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c index 3b829fed8631..927d62b3d41b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -689,6 +689,7 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci) case BRCM_CC_43525_CHIP_ID: case BRCM_CC_4365_CHIP_ID: case BRCM_CC_4366_CHIP_ID: + case BRCM_CC_43664_CHIP_ID: return 0x200000; case CY_CC_4373_CHIP_ID: return 0x160000; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 091c191ce259..6e25ff94dd07 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -75,6 +75,7 @@ static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_4365_CHIP_ID, 0xFFFFFFF0, 4365C), BRCMF_FW_ENTRY(BRCM_CC_4366_CHIP_ID, 0x0000000F, 4366B), BRCMF_FW_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFF0, 4366C), + BRCMF_FW_ENTRY(BRCM_CC_43664_CHIP_ID, 0xFFFFFFF0, 4366C), BRCMF_FW_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371), }; diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h index 57544a3a3ce4..686f7a85a045 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h @@ -57,6 +57,7 @@ #define BRCM_CC_43602_CHIP_ID 43602 #define BRCM_CC_4365_CHIP_ID 0x4365 #define BRCM_CC_4366_CHIP_ID 0x4366 +#define BRCM_CC_43664_CHIP_ID 43664 #define BRCM_CC_4371_CHIP_ID 0x4371 #define CY_CC_4373_CHIP_ID 0x4373 -- cgit v1.2.3 From 863683cfbbfcd48ae88e2af880f52b91332f1f26 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 4 Apr 2018 19:09:44 -0500 Subject: brcmsmac: phy_lcn: remove duplicate code Remove and refactor some code in order to avoid having identical code for different branches. Notice that this piece of code hasn't been modified since 2011. Addresses-Coverity-ID: 1226756 ("Identical code for different branches") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c index 93d4cde0eb31..9d830d27b229 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c @@ -3388,13 +3388,8 @@ void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode) u8 phybw40; phybw40 = CHSPEC_IS40(pi->radio_chanspec); - if (LCNREV_LT(pi->pubpi.phy_rev, 2)) { - mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5); - mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9); - } else { - mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5); - mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9); - } + mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5); + mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9); if (phybw40 == 0) { mod_phy_reg((pi), 0x410, -- cgit v1.2.3 From 9d81ecde4dce37cd9e147c24c9bc0cd1d4c259d5 Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Thu, 5 Apr 2018 14:22:32 +0200 Subject: rt2x00: rt2800: add antenna diversity for RT5370G RT5370G has hardware RX antenna diversity like RT5390R. Based on DPO_RT5572_LinuxSTA_2.6.1.3_20121022.tar.bz2 manufacturer driver: https://d86o2zu8ugzlg.cloudfront.net/mediatek-craft/drivers/DPO_RT5572_LinuxSTA_2.6.1.3_20121022.tar.bz2 Cc: Stanislaw Gruszka Cc: Helmut Schaa Cc: Gertjan van Wingerde Cc: Jakub Kicinski Cc: wireless newbie Cc: Kalle Valo Cc: linux wireless ml Signed-off-by: Xose Vazquez Perez Acked-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2800.h | 1 + drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800.h b/drivers/net/wireless/ralink/rt2x00/rt2800.h index 6a8c93fb6a43..7a133e94b1bf 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h @@ -94,6 +94,7 @@ #define REV_RT3390E 0x0211 #define REV_RT3593E 0x0211 #define REV_RT5390F 0x0502 +#define REV_RT5370G 0x0503 #define REV_RT5390R 0x1502 #define REV_RT5592C 0x0221 diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 429d07b651dd..e827dc522580 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -6220,8 +6220,9 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, GPIO_CTRL, reg); } - /* This chip has hardware antenna diversity*/ - if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390R)) { + /* These chips have hardware RX antenna diversity */ + if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390R) || + rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5370G)) { rt2800_bbp_write(rt2x00dev, 150, 0); /* Disable Antenna Software OFDM */ rt2800_bbp_write(rt2x00dev, 151, 0); /* Disable Antenna Software CCK */ rt2800_bbp_write(rt2x00dev, 154, 0); /* Clear previously selected antenna */ @@ -8748,7 +8749,9 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00dev->default_ant.rx = ANTENNA_A; } - if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390R)) { + /* These chips have hardware RX antenna diversity */ + if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390R) || + rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5370G)) { rt2x00dev->default_ant.tx = ANTENNA_HW_DIVERSITY; /* Unused */ rt2x00dev->default_ant.rx = ANTENNA_HW_DIVERSITY; /* Unused */ } -- cgit v1.2.3 From 3763770044640caeb1101cdea40697cc0814403c Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 5 Apr 2018 10:49:49 -0500 Subject: qtnfmac: pearl: pcie: fix memory leak in qtnf_fw_work_handler In case memory resources for fw were succesfully allocated, release them before jumping to fw_load_fail. Addresses-Coverity-ID: 1466092 ("Resource leak") Fixes: c3b2f7ca4186 ("qtnfmac: implement asynchronous firmware loading") Signed-off-by: Gustavo A. R. Silva Reviewed-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c index f117904d9120..6c1e139bb8f7 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c @@ -1185,6 +1185,10 @@ static void qtnf_fw_work_handler(struct work_struct *work) if (qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_LOADRDY, QTN_FW_DL_TIMEOUT_MS)) { pr_err("card is not ready\n"); + + if (!flashboot) + release_firmware(fw); + goto fw_load_fail; } -- cgit v1.2.3 From a8cbb46f831d2c101feccdd0e0daf3627b8c1dca Mon Sep 17 00:00:00 2001 From: Golan Ben Ami Date: Sun, 22 Oct 2017 15:58:26 +0300 Subject: iwlwifi: allow different csr flags for different device families Different device families may have different flag values for passing a message to the fw (i.e. SW_RESET). In order to keep the code readable, and avoid conditioning upon the family, store a value for each flag, which indicates the bit that needs to be enabled. Signed-off-by: Golan Ben Ami Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/cfg/1000.c | 8 ++- drivers/net/wireless/intel/iwlwifi/cfg/2000.c | 13 +++-- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 7 +++ drivers/net/wireless/intel/iwlwifi/cfg/5000.c | 8 ++- drivers/net/wireless/intel/iwlwifi/cfg/6000.c | 19 +++++-- drivers/net/wireless/intel/iwlwifi/cfg/7000.c | 5 +- drivers/net/wireless/intel/iwlwifi/cfg/8000.c | 5 +- drivers/net/wireless/intel/iwlwifi/cfg/9000.c | 3 +- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 65 ++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 28 +--------- .../net/wireless/intel/iwlwifi/iwl-eeprom-read.c | 8 ++- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 8 ++- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 3 +- .../net/wireless/intel/iwlwifi/pcie/trans-gen2.c | 15 +++-- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 65 ++++++++++++---------- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 16 +++--- 16 files changed, 184 insertions(+), 92 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/1000.c b/drivers/net/wireless/intel/iwlwifi/cfg/1000.c index b2573b1d1506..591687984962 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/1000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/1000.c @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -27,7 +28,6 @@ #include #include #include "iwl-config.h" -#include "iwl-csr.h" #include "iwl-agn-hw.h" /* Highest firmware API version supported */ @@ -91,7 +91,8 @@ static const struct iwl_eeprom_params iwl1000_eeprom_params = { .base_params = &iwl1000_base_params, \ .eeprom_params = &iwl1000_eeprom_params, \ .led_mode = IWL_LED_BLINK, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ + .csr = &iwl_csr_v1 const struct iwl_cfg iwl1000_bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN", @@ -117,7 +118,8 @@ const struct iwl_cfg iwl1000_bg_cfg = { .eeprom_params = &iwl1000_eeprom_params, \ .led_mode = IWL_LED_RF_STATE, \ .rx_with_siso_diversity = true, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ + .csr = &iwl_csr_v1 const struct iwl_cfg iwl100_bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 100 BGN", diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/2000.c b/drivers/net/wireless/intel/iwlwifi/cfg/2000.c index 1b32ad413b9e..a63ca8820568 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/2000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/2000.c @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -115,7 +116,8 @@ static const struct iwl_eeprom_params iwl20x0_eeprom_params = { .base_params = &iwl2000_base_params, \ .eeprom_params = &iwl20x0_eeprom_params, \ .led_mode = IWL_LED_RF_STATE, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ + .csr = &iwl_csr_v1 const struct iwl_cfg iwl2000_2bgn_cfg = { @@ -142,7 +144,8 @@ const struct iwl_cfg iwl2000_2bgn_d_cfg = { .base_params = &iwl2030_base_params, \ .eeprom_params = &iwl20x0_eeprom_params, \ .led_mode = IWL_LED_RF_STATE, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ + .csr = &iwl_csr_v1 const struct iwl_cfg iwl2030_2bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 2230 BGN", @@ -163,7 +166,8 @@ const struct iwl_cfg iwl2030_2bgn_cfg = { .eeprom_params = &iwl20x0_eeprom_params, \ .led_mode = IWL_LED_RF_STATE, \ .rx_with_siso_diversity = true, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ + .csr = &iwl_csr_v1 const struct iwl_cfg iwl105_bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 105 BGN", @@ -190,7 +194,8 @@ const struct iwl_cfg iwl105_bgn_d_cfg = { .eeprom_params = &iwl20x0_eeprom_params, \ .led_mode = IWL_LED_RF_STATE, \ .rx_with_siso_diversity = true, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ + .csr = &iwl_csr_v1 const struct iwl_cfg iwl135_bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 135 BGN", diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index f2b6e0e8d787..afc78a1e1cfc 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -143,6 +143,7 @@ const struct iwl_cfg iwl22000_2ac_cfg_hr = { .name = "Intel(R) Dual Band Wireless AC 22000", .fw_name_pre = IWL_22000_HR_FW_PRE, IWL_DEVICE_22000, + .csr = &iwl_csr_v1, .ht_params = &iwl_22000_ht_params, .nvm_ver = IWL_22000_NVM_VERSION, .nvm_calib_ver = IWL_22000_TX_POWER_VERSION, @@ -153,6 +154,7 @@ const struct iwl_cfg iwl22000_2ac_cfg_hr_cdb = { .name = "Intel(R) Dual Band Wireless AC 22000", .fw_name_pre = IWL_22000_HR_CDB_FW_PRE, IWL_DEVICE_22000, + .csr = &iwl_csr_v1, .ht_params = &iwl_22000_ht_params, .nvm_ver = IWL_22000_NVM_VERSION, .nvm_calib_ver = IWL_22000_TX_POWER_VERSION, @@ -164,6 +166,7 @@ const struct iwl_cfg iwl22000_2ac_cfg_jf = { .name = "Intel(R) Dual Band Wireless AC 22000", .fw_name_pre = IWL_22000_JF_FW_PRE, IWL_DEVICE_22000, + .csr = &iwl_csr_v1, .ht_params = &iwl_22000_ht_params, .nvm_ver = IWL_22000_NVM_VERSION, .nvm_calib_ver = IWL_22000_TX_POWER_VERSION, @@ -174,6 +177,7 @@ const struct iwl_cfg iwl22000_2ax_cfg_hr = { .name = "Intel(R) Dual Band Wireless AX 22000", .fw_name_pre = IWL_22000_HR_FW_PRE, IWL_DEVICE_22000, + .csr = &iwl_csr_v1, .ht_params = &iwl_22000_ht_params, .nvm_ver = IWL_22000_NVM_VERSION, .nvm_calib_ver = IWL_22000_TX_POWER_VERSION, @@ -184,6 +188,7 @@ const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_f0 = { .name = "Intel(R) Dual Band Wireless AX 22000", .fw_name_pre = IWL_22000_HR_F0_FW_PRE, IWL_DEVICE_22000, + .csr = &iwl_csr_v1, .ht_params = &iwl_22000_ht_params, .nvm_ver = IWL_22000_NVM_VERSION, .nvm_calib_ver = IWL_22000_TX_POWER_VERSION, @@ -194,6 +199,7 @@ const struct iwl_cfg iwl22000_2ax_cfg_qnj_jf_b0 = { .name = "Intel(R) Dual Band Wireless AX 22000", .fw_name_pre = IWL_22000_JF_B0_FW_PRE, IWL_DEVICE_22000, + .csr = &iwl_csr_v1, .ht_params = &iwl_22000_ht_params, .nvm_ver = IWL_22000_NVM_VERSION, .nvm_calib_ver = IWL_22000_TX_POWER_VERSION, @@ -204,6 +210,7 @@ const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_a0 = { .name = "Intel(R) Dual Band Wireless AX 22000", .fw_name_pre = IWL_22000_HR_A0_FW_PRE, IWL_DEVICE_22000, + .csr = &iwl_csr_v1, .ht_params = &iwl_22000_ht_params, .nvm_ver = IWL_22000_NVM_VERSION, .nvm_calib_ver = IWL_22000_TX_POWER_VERSION, diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/5000.c b/drivers/net/wireless/intel/iwlwifi/cfg/5000.c index 4aa8f0a05c8a..a224f1be1ec2 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/5000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/5000.c @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -28,7 +29,6 @@ #include #include "iwl-config.h" #include "iwl-agn-hw.h" -#include "iwl-csr.h" /* Highest firmware API version supported */ #define IWL5000_UCODE_API_MAX 5 @@ -89,7 +89,8 @@ static const struct iwl_eeprom_params iwl5000_eeprom_params = { .base_params = &iwl5000_base_params, \ .eeprom_params = &iwl5000_eeprom_params, \ .led_mode = IWL_LED_BLINK, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ + .csr = &iwl_csr_v1 const struct iwl_cfg iwl5300_agn_cfg = { .name = "Intel(R) Ultimate N WiFi Link 5300 AGN", @@ -153,7 +154,8 @@ const struct iwl_cfg iwl5350_agn_cfg = { .eeprom_params = &iwl5000_eeprom_params, \ .led_mode = IWL_LED_BLINK, \ .internal_wimax_coex = true, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ + .csr = &iwl_csr_v1 const struct iwl_cfg iwl5150_agn_cfg = { .name = "Intel(R) WiMAX/WiFi Link 5150 AGN", diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/6000.c b/drivers/net/wireless/intel/iwlwifi/cfg/6000.c index 39335b7b0c16..51cec0bb75fc 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/6000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/6000.c @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -135,7 +136,8 @@ static const struct iwl_eeprom_params iwl6000_eeprom_params = { .base_params = &iwl6000_g2_base_params, \ .eeprom_params = &iwl6000_eeprom_params, \ .led_mode = IWL_LED_RF_STATE, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ + .csr = &iwl_csr_v1 const struct iwl_cfg iwl6005_2agn_cfg = { .name = "Intel(R) Centrino(R) Advanced-N 6205 AGN", @@ -189,7 +191,8 @@ const struct iwl_cfg iwl6005_2agn_mow2_cfg = { .base_params = &iwl6000_g2_base_params, \ .eeprom_params = &iwl6000_eeprom_params, \ .led_mode = IWL_LED_RF_STATE, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ + .csr = &iwl_csr_v1 const struct iwl_cfg iwl6030_2agn_cfg = { .name = "Intel(R) Centrino(R) Advanced-N 6230 AGN", @@ -225,7 +228,8 @@ const struct iwl_cfg iwl6030_2bg_cfg = { .base_params = &iwl6000_g2_base_params, \ .eeprom_params = &iwl6000_eeprom_params, \ .led_mode = IWL_LED_RF_STATE, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ + .csr = &iwl_csr_v1 const struct iwl_cfg iwl6035_2agn_cfg = { .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN", @@ -280,7 +284,8 @@ const struct iwl_cfg iwl130_bg_cfg = { .base_params = &iwl6000_base_params, \ .eeprom_params = &iwl6000_eeprom_params, \ .led_mode = IWL_LED_BLINK, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ + .csr = &iwl_csr_v1 const struct iwl_cfg iwl6000i_2agn_cfg = { .name = "Intel(R) Centrino(R) Advanced-N 6200 AGN", @@ -313,7 +318,8 @@ const struct iwl_cfg iwl6000i_2bg_cfg = { .eeprom_params = &iwl6000_eeprom_params, \ .led_mode = IWL_LED_BLINK, \ .internal_wimax_coex = true, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ + .csr = &iwl_csr_v1 const struct iwl_cfg iwl6050_2agn_cfg = { .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN", @@ -339,7 +345,8 @@ const struct iwl_cfg iwl6050_2abg_cfg = { .eeprom_params = &iwl6000_eeprom_params, \ .led_mode = IWL_LED_BLINK, \ .internal_wimax_coex = true, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ + .csr = &iwl_csr_v1 const struct iwl_cfg iwl6150_bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN", diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c index ce741beec1fc..8e9684e8e603 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -35,6 +36,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -167,7 +169,8 @@ static const struct iwl_ht_params iwl7000_ht_params = { .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000, \ .non_shared_ant = ANT_A, \ .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ - .dccm_offset = IWL7000_DCCM_OFFSET + .dccm_offset = IWL7000_DCCM_OFFSET, \ + .csr = &iwl_csr_v1 #define IWL_DEVICE_7000 \ IWL_DEVICE_7000_COMMON, \ diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c index 3f4d9bac9f73..e8299b2ab6bd 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c @@ -8,6 +8,7 @@ * Copyright(c) 2014 Intel Corporation. All rights reserved. * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,6 +35,7 @@ * * Copyright(c) 2014 Intel Corporation. All rights reserved. * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -158,7 +160,8 @@ static const struct iwl_tt_params iwl8000_tt_params = { .apmg_not_supported = true, \ .nvm_type = IWL_NVM_EXT, \ .dbgc_supported = true, \ - .min_umac_error_event_table = 0x800000 + .min_umac_error_event_table = 0x800000, \ + .csr = &iwl_csr_v1 #define IWL_DEVICE_8000 \ IWL_DEVICE_8000_COMMON, \ diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index e1c869a1f8cc..fe376fce3444 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -156,7 +156,8 @@ static const struct iwl_tt_params iwl9000_tt_params = { .rf_id = true, \ .nvm_type = IWL_NVM_EXT, \ .dbgc_supported = true, \ - .min_umac_error_event_table = 0x800000 + .min_umac_error_event_table = 0x800000, \ + .csr = &iwl_csr_v1 const struct iwl_cfg iwl9160_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9160", diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 14e69e7a2287..7f0b7cea8b9b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -7,6 +7,7 @@ * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * Copyright (C) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright (C) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -69,6 +71,7 @@ #include #include #include +#include "iwl-csr.h" enum iwl_device_family { IWL_DEVICE_FAMILY_UNDEFINED, @@ -284,6 +287,44 @@ struct iwl_pwr_tx_backoff { u32 backoff; }; +/** + * struct iwl_csr_params + * + * @flag_sw_reset: reset the device + * @flag_mac_clock_ready: + * Indicates MAC (ucode processor, etc.) is powered up and can run. + * Internal resources are accessible. + * NOTE: This does not indicate that the processor is actually running. + * NOTE: This does not indicate that device has completed + * init or post-power-down restore of internal SRAM memory. + * Use CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that + * SRAM is restored and uCode is in normal operation mode. + * This note is relevant only for pre 5xxx devices. + * NOTE: After device reset, this bit remains "0" until host sets + * INIT_DONE + * @flag_init_done: Host sets this to put device into fully operational + * D0 power mode. Host resets this after SW_RESET to put device into + * low power mode. + * @flag_mac_access_req: Host sets this to request and maintain MAC wakeup, + * to allow host access to device-internal resources. Host must wait for + * mac_clock_ready (and !GOING_TO_SLEEP) before accessing non-CSR device + * registers. + * @flag_val_mac_access_en: mac access is enabled + * @flag_master_dis: disable master + * @flag_stop_master: stop master + * @addr_sw_reset: address for resetting the device + */ +struct iwl_csr_params { + u8 flag_sw_reset; + u8 flag_mac_clock_ready; + u8 flag_init_done; + u8 flag_mac_access_req; + u8 flag_val_mac_access_en; + u8 flag_master_dis; + u8 flag_stop_master; + u8 addr_sw_reset; +}; + /** * struct iwl_cfg * @name: Official name of the device @@ -316,6 +357,7 @@ struct iwl_pwr_tx_backoff { * @mac_addr_from_csr: read HW address from CSR registers * @features: hw features, any combination of feature_whitelist * @pwr_tx_backoffs: translation table between power limits and backoffs + * @csr: csr flags and addresses that are different across devices * @max_rx_agg_size: max RX aggregation size of the ADDBA request/response * @max_tx_agg_size: max TX aggregation size of the ADDBA request/response * @max_ht_ampdu_factor: the exponent of the max length of A-MPDU that the @@ -354,6 +396,7 @@ struct iwl_cfg { const struct iwl_pwr_tx_backoff *pwr_tx_backoffs; const char *default_nvm_file_C_step; const struct iwl_tt_params *thermal_params; + const struct iwl_csr_params *csr; enum iwl_device_family device_family; enum iwl_led_mode led_mode; enum iwl_nvm_type nvm_type; @@ -400,6 +443,28 @@ struct iwl_cfg { u32 extra_phy_cfg_flags; }; +static const struct iwl_csr_params iwl_csr_v1 = { + .flag_mac_clock_ready = 0, + .flag_val_mac_access_en = 0, + .flag_init_done = 2, + .flag_mac_access_req = 3, + .flag_sw_reset = 7, + .flag_master_dis = 8, + .flag_stop_master = 9, + .addr_sw_reset = (CSR_BASE + 0x020) +}; + +static const struct iwl_csr_params iwl_csr_v2 = { + .flag_init_done = 6, + .flag_mac_clock_ready = 20, + .flag_val_mac_access_en = 20, + .flag_mac_access_req = 21, + .flag_master_dis = 28, + .flag_stop_master = 29, + .flag_sw_reset = 31, + .addr_sw_reset = (CSR_BASE + 0x024) +}; + /* * This list declares the config structures for all devices. */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index 4f0d070eda54..ba971d3946e2 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -8,6 +8,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,6 +35,7 @@ * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -257,7 +259,6 @@ /* RESET */ #define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001) #define CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002) -#define CSR_RESET_REG_FLAG_SW_RESET (0x00000080) #define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100) #define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) #define CSR_RESET_LINK_PWR_MGMT_DISABLED (0x80000000) @@ -280,35 +281,10 @@ * 4: GOING_TO_SLEEP * Indicates MAC is entering a power-saving sleep power-down. * Not a good time to access device-internal resources. - * 3: MAC_ACCESS_REQ - * Host sets this to request and maintain MAC wakeup, to allow host - * access to device-internal resources. Host must wait for - * MAC_CLOCK_READY (and !GOING_TO_SLEEP) before accessing non-CSR - * device registers. - * 2: INIT_DONE - * Host sets this to put device into fully operational D0 power mode. - * Host resets this after SW_RESET to put device into low power mode. - * 0: MAC_CLOCK_READY - * Indicates MAC (ucode processor, etc.) is powered up and can run. - * Internal resources are accessible. - * NOTE: This does not indicate that the processor is actually running. - * NOTE: This does not indicate that device has completed - * init or post-power-down restore of internal SRAM memory. - * Use CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that - * SRAM is restored and uCode is in normal operation mode. - * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and - * do not need to save/restore it. - * NOTE: After device reset, this bit remains "0" until host sets - * INIT_DONE */ -#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) -#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) -#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) #define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010) #define CSR_GP_CNTRL_REG_FLAG_XTAL_ON (0x00000400) -#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) - #define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000) #define CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN (0x04000000) #define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c index f2cea1c7befc..ac965c34a2f8 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -199,12 +201,12 @@ static int iwl_init_otp_access(struct iwl_trans *trans) /* Enable 40MHz radio clock */ iwl_write32(trans, CSR_GP_CNTRL, iwl_read32(trans, CSR_GP_CNTRL) | - CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + BIT(trans->cfg->csr->flag_init_done)); /* wait for clock to be ready */ ret = iwl_poll_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + BIT(trans->cfg->csr->flag_mac_clock_ready), + BIT(trans->cfg->csr->flag_mac_clock_ready), 25000); if (ret < 0) { IWL_ERR(trans, "Time out access OTP\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 0497c7a44def..b002a7afb5f5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright (C) 2015 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -35,6 +36,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright (C) 2015 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -520,15 +522,15 @@ static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u32 base) /* set INIT_DONE flag */ iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + BIT(trans->cfg->csr->flag_init_done)); /* and wait for clock stabilization */ if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) udelay(2); err = iwl_poll_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + BIT(trans->cfg->csr->flag_mac_clock_ready), + BIT(trans->cfg->csr->flag_mac_clock_ready), 25000); if (err < 0) { IWL_DEBUG_INFO(trans, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index f25ce3a1ea50..f772d70a65e4 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -3,6 +3,7 @@ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -201,7 +202,7 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans, IWL_DEBUG_INFO(trans, "Rx queue requesting wakeup, GP1 = 0x%x\n", reg); iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + BIT(trans->cfg->csr->flag_mac_access_req)); rxq->need_update = true; return; } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index cb4012541f45..b8e8dac2895d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -19,6 +20,7 @@ * BSD LICENSE * * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -92,7 +94,8 @@ static int iwl_pcie_gen2_apm_init(struct iwl_trans *trans) * Set "initialization complete" bit to move adapter from * D0U* --> D0A* (powered-up active) state. */ - iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + iwl_set_bit(trans, CSR_GP_CNTRL, + BIT(trans->cfg->csr->flag_init_done)); /* * Wait for clock stabilization; once stabilized, access to @@ -100,8 +103,9 @@ static int iwl_pcie_gen2_apm_init(struct iwl_trans *trans) * and accesses to uCode SRAM. */ ret = iwl_poll_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + BIT(trans->cfg->csr->flag_mac_clock_ready), + BIT(trans->cfg->csr->flag_mac_clock_ready), + 25000); if (ret < 0) { IWL_DEBUG_INFO(trans, "Failed to init the card\n"); return ret; @@ -143,7 +147,8 @@ static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave) * Clear "initialization complete" bit to move adapter from * D0A* (powered-up Active) --> D0U* (Uninitialized) state. */ - iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + iwl_clear_bit(trans, CSR_GP_CNTRL, + BIT(trans->cfg->csr->flag_init_done)); } void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) @@ -187,7 +192,7 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) /* Make sure (redundant) we've released our request to stay awake */ iwl_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + BIT(trans->cfg->csr->flag_mac_access_req)); /* Stop the device, and put it in low power state */ iwl_pcie_gen2_apm_stop(trans, false); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index f8a0234d332c..623476603cd4 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -8,6 +8,7 @@ * Copyright(c) 2007 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -35,6 +36,7 @@ * Copyright(c) 2005 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -179,7 +181,8 @@ out: static void iwl_trans_pcie_sw_reset(struct iwl_trans *trans) { /* Reset entire device - do controller reset (results in SHRD_HW_RST) */ - iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + iwl_set_bit(trans, trans->cfg->csr->addr_sw_reset, + BIT(trans->cfg->csr->flag_sw_reset)); usleep_range(5000, 6000); } @@ -372,7 +375,8 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) * Set "initialization complete" bit to move adapter from * D0U* --> D0A* (powered-up active) state. */ - iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + iwl_set_bit(trans, CSR_GP_CNTRL, + BIT(trans->cfg->csr->flag_init_done)); /* * Wait for clock stabilization; once stabilized, access to @@ -380,8 +384,9 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) * and accesses to uCode SRAM. */ ret = iwl_poll_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + BIT(trans->cfg->csr->flag_mac_clock_ready), + BIT(trans->cfg->csr->flag_mac_clock_ready), + 25000); if (ret < 0) { IWL_ERR(trans, "Failed to init the card\n"); return ret; @@ -459,15 +464,16 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) * Set "initialization complete" bit to move adapter from * D0U* --> D0A* (powered-up active) state. */ - iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + iwl_set_bit(trans, CSR_GP_CNTRL, + BIT(trans->cfg->csr->flag_init_done)); /* * Wait for clock stabilization; once stabilized, access to * device-internal resources is possible. */ ret = iwl_poll_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + BIT(trans->cfg->csr->flag_mac_clock_ready), + BIT(trans->cfg->csr->flag_mac_clock_ready), 25000); if (WARN_ON(ret < 0)) { IWL_ERR(trans, "Access time out - failed to enable LP XTAL\n"); @@ -519,7 +525,7 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) * D0A* (powered-up Active) --> D0U* (Uninitialized) state. */ iwl_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + BIT(trans->cfg->csr->flag_init_done)); /* Activates XTAL resources monitor */ __iwl_trans_pcie_set_bit(trans, CSR_MONITOR_CFG_REG, @@ -541,11 +547,12 @@ void iwl_pcie_apm_stop_master(struct iwl_trans *trans) int ret; /* stop device's busmaster DMA activity */ - iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); + iwl_set_bit(trans, trans->cfg->csr->addr_sw_reset, + BIT(trans->cfg->csr->flag_stop_master)); - ret = iwl_poll_bit(trans, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, - CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + ret = iwl_poll_bit(trans, trans->cfg->csr->addr_sw_reset, + BIT(trans->cfg->csr->flag_master_dis), + BIT(trans->cfg->csr->flag_master_dis), 100); if (ret < 0) IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n"); @@ -594,7 +601,7 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave) * D0A* (powered-up Active) --> D0U* (Uninitialized) state. */ iwl_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + BIT(trans->cfg->csr->flag_init_done)); } static int iwl_pcie_nic_init(struct iwl_trans *trans) @@ -1267,7 +1274,7 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) /* Make sure (redundant) we've released our request to stay awake */ iwl_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + BIT(trans->cfg->csr->flag_mac_access_req)); /* Stop the device, and put it in low power state */ iwl_pcie_apm_stop(trans, false); @@ -1497,9 +1504,9 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test, iwl_pcie_synchronize_irqs(trans); iwl_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + BIT(trans->cfg->csr->flag_mac_access_req)); iwl_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + BIT(trans->cfg->csr->flag_init_done)); iwl_pcie_enable_rx_wake(trans, false); @@ -1543,15 +1550,17 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, iwl_pcie_reset_ict(trans); iwl_enable_interrupts(trans); - iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + iwl_set_bit(trans, CSR_GP_CNTRL, + BIT(trans->cfg->csr->flag_mac_access_req)); + iwl_set_bit(trans, CSR_GP_CNTRL, + BIT(trans->cfg->csr->flag_init_done)); if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) udelay(2); ret = iwl_poll_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + BIT(trans->cfg->csr->flag_mac_clock_ready), + BIT(trans->cfg->csr->flag_mac_clock_ready), 25000); if (ret < 0) { IWL_ERR(trans, "Failed to resume the device (mac ready)\n"); @@ -1562,7 +1571,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, if (!reset) { iwl_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + BIT(trans->cfg->csr->flag_mac_access_req)); } else { iwl_trans_pcie_tx_reset(trans); @@ -1939,7 +1948,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, /* this bit wakes up the NIC */ __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + BIT(trans->cfg->csr->flag_mac_access_req)); if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) udelay(2); @@ -1964,8 +1973,8 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, * and do not save/restore SRAM when power cycling. */ ret = iwl_poll_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, - (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | + BIT(trans->cfg->csr->flag_val_mac_access_en), + (BIT(trans->cfg->csr->flag_mac_clock_ready) | CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); if (unlikely(ret < 0)) { iwl_trans_pcie_dump_regs(trans); @@ -2003,7 +2012,7 @@ static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans, goto out; __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + BIT(trans->cfg->csr->flag_mac_access_req)); /* * Above we read the CSR_GP_CNTRL register, which will flush * any previous writes, but we need the write that clears the @@ -3232,12 +3241,12 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, * id located at the AUX bus MISC address space. */ iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + BIT(trans->cfg->csr->flag_init_done)); udelay(2); ret = iwl_poll_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + BIT(trans->cfg->csr->flag_mac_clock_ready), + BIT(trans->cfg->csr->flag_mac_clock_ready), 25000); if (ret < 0) { IWL_DEBUG_INFO(trans, "Failed to wake up the nic\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index cf468b9f5a82..1cbb8f470afd 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -3,6 +3,7 @@ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -273,7 +274,7 @@ static void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, IWL_DEBUG_INFO(trans, "Tx queue %d requesting wakeup, GP1 = 0x%x\n", txq_id, reg); iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + BIT(trans->cfg->csr->flag_mac_access_req)); txq->need_update = true; return; } @@ -611,7 +612,7 @@ static void iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans) trans_pcie->cmd_hold_nic_awake = false; __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + BIT(trans->cfg->csr->flag_mac_access_req)); } /* @@ -1171,6 +1172,7 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans, const struct iwl_host_cmd *cmd) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + const struct iwl_cfg *cfg = trans->cfg; int ret; lockdep_assert_held(&trans_pcie->reg_lock); @@ -1188,19 +1190,19 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans, * returned. This needs to be done only on NICs that have * apmg_wake_up_wa set. */ - if (trans->cfg->base_params->apmg_wake_up_wa && + if (cfg->base_params->apmg_wake_up_wa && !trans_pcie->cmd_hold_nic_awake) { __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + BIT(cfg->csr->flag_mac_access_req)); ret = iwl_poll_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, - (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | + BIT(cfg->csr->flag_val_mac_access_en), + (BIT(cfg->csr->flag_mac_clock_ready) | CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); if (ret < 0) { __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + BIT(cfg->csr->flag_mac_access_req)); IWL_ERR(trans, "Failed to wake NIC for hcmd\n"); return -EIO; } -- cgit v1.2.3 From 132db31ca9ee305ca1725db361096ab2230511c7 Mon Sep 17 00:00:00 2001 From: Golan Ben-Ami Date: Mon, 17 Jul 2017 19:42:35 +0300 Subject: iwlwifi: introduce Image Loader (IML) - new firmware image In future devices a new image will be introduced - IML. The IML, image loader, is loaded by the ROM, and as part of the new self-init flow, loads the rest of the firmware images to the device. Store the image, so the ROM can load it to the device. Signed-off-by: Golan Ben Ami Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/file.h | 3 +++ drivers/net/wireless/intel/iwlwifi/fw/img.h | 6 ++++++ drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 8 ++++++++ drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 5 +++++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 3 +++ 5 files changed, 25 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 9b2805e1e3b1..9d939cbaf6c6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -8,6 +8,7 @@ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -35,6 +36,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -143,6 +145,7 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_FW_DBG_TRIGGER = 40, IWL_UCODE_TLV_FW_GSCAN_CAPA = 50, IWL_UCODE_TLV_FW_MEM_SEG = 51, + IWL_UCODE_TLV_IML = 52, }; struct iwl_ucode_tlv { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/img.h b/drivers/net/wireless/intel/iwlwifi/fw/img.h index b23ffe12ad84..f4912382b6af 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/img.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/img.h @@ -8,6 +8,7 @@ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -35,6 +36,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -241,6 +243,8 @@ enum iwl_fw_type { * @ucode_ver: ucode version from the ucode file * @fw_version: firmware version string * @img: ucode image like ucode_rt, ucode_init, ucode_wowlan. + * @iml_len: length of the image loader image + * @iml: image loader fw image * @ucode_capa: capabilities parsed from the ucode file. * @enhance_sensitivity_table: device can do enhanced sensitivity. * @init_evtlog_ptr: event log offset for init ucode. @@ -267,6 +271,8 @@ struct iwl_fw { /* ucode images */ struct fw_img img[IWL_UCODE_TYPE_MAX]; + size_t iml_len; + u8 *iml; struct iwl_ucode_capabilities ucode_capa; bool enhance_sensitivity_table; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index aa2d5c14e202..4f451a6f20b9 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -179,6 +179,7 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv) for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_trigger_tlv); i++) kfree(drv->fw.dbg_trigger_tlv[i]); kfree(drv->fw.dbg_mem_tlv); + kfree(drv->fw.iml); for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) iwl_free_fw_img(drv, drv->fw.img + i); @@ -1126,6 +1127,13 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, pieces->n_dbg_mem_tlv++; break; } + case IWL_UCODE_TLV_IML: { + drv->fw.iml_len = tlv_len; + drv->fw.iml = kmemdup(tlv_data, tlv_len, GFP_KERNEL); + if (!drv->fw.iml) + return -ENOMEM; + break; + } default: IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); break; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index a92832711683..1b9c627ee34d 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -691,6 +691,8 @@ enum iwl_plat_pm_mode { * @wide_cmd_header: true when ucode supports wide command header format * @num_rx_queues: number of RX queues allocated by the transport; * the transport must set this before calling iwl_drv_start() + * @iml_len: the length of the image loader + * @iml: a pointer to the image loader itself * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only. * The user should use iwl_trans_{alloc,free}_tx_cmd. * @rx_mpdu_cmd: MPDU RX command ID, must be assigned by opmode before @@ -735,6 +737,9 @@ struct iwl_trans { u8 num_rx_queues; + size_t iml_len; + u8 *iml; + /* The following fields are internal only */ struct kmem_cache *dev_cmd_pool; char dev_cmd_pool_name[50]; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index de46e6258a5c..ff1e518096c5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -739,6 +739,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, sizeof(trans->dbg_conf_tlv)); trans->dbg_trigger_tlv = mvm->fw->dbg_trigger_tlv; + trans->iml = mvm->fw->iml; + trans->iml_len = mvm->fw->iml_len; + /* set up notification wait support */ iwl_notification_wait_init(&mvm->notif_wait); -- cgit v1.2.3 From 4efc272a45c112bf539da14d480be0448abe4fac Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Tue, 13 Feb 2018 13:52:43 +0200 Subject: iwlwifi: cfg: remove unnecessary cfg data in non-dvm devices The max_data_size and max_inst_size values are only needed for DVM devices. Remove the assignment to those fields in 7000 and newer families so we can also remove the otherwise unnecessary inclusion of iwl-agn.h headers. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 3 --- drivers/net/wireless/intel/iwlwifi/cfg/7000.c | 11 ++++------- drivers/net/wireless/intel/iwlwifi/cfg/8000.c | 9 +++------ drivers/net/wireless/intel/iwlwifi/cfg/9000.c | 3 --- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 4 ++-- 5 files changed, 9 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index afc78a1e1cfc..d4ba66aecdc9 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -54,7 +54,6 @@ #include #include #include "iwl-config.h" -#include "iwl-agn-hw.h" /* Highest firmware API version supported */ #define IWL_22000_UCODE_API_MAX 38 @@ -115,8 +114,6 @@ static const struct iwl_ht_params iwl_22000_ht_params = { .ucode_api_max = IWL_22000_UCODE_API_MAX, \ .ucode_api_min = IWL_22000_UCODE_API_MIN, \ .device_family = IWL_DEVICE_FAMILY_22000, \ - .max_inst_size = IWL60_RTC_INST_SIZE, \ - .max_data_size = IWL60_RTC_DATA_SIZE, \ .base_params = &iwl_22000_base_params, \ .led_mode = IWL_LED_RF_STATE, \ .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_22000, \ diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c index 8e9684e8e603..69bfa827e82a 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c @@ -7,8 +7,8 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -35,8 +35,8 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -70,7 +70,6 @@ #include #include #include "iwl-config.h" -#include "iwl-agn-hw.h" /* Highest firmware API version supported */ #define IWL7260_UCODE_API_MAX 17 @@ -162,8 +161,6 @@ static const struct iwl_ht_params iwl7000_ht_params = { #define IWL_DEVICE_7000_COMMON \ .device_family = IWL_DEVICE_FAMILY_7000, \ - .max_inst_size = IWL60_RTC_INST_SIZE, \ - .max_data_size = IWL60_RTC_DATA_SIZE, \ .base_params = &iwl7000_base_params, \ .led_mode = IWL_LED_RF_STATE, \ .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000, \ diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c index e8299b2ab6bd..7262e973e0d6 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c @@ -7,8 +7,8 @@ * * Copyright(c) 2014 Intel Corporation. All rights reserved. * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -35,7 +35,7 @@ * * Copyright(c) 2014 Intel Corporation. All rights reserved. * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -69,7 +69,6 @@ #include #include #include "iwl-config.h" -#include "iwl-agn-hw.h" /* Highest firmware API version supported */ #define IWL8000_UCODE_API_MAX 36 @@ -142,8 +141,6 @@ static const struct iwl_tt_params iwl8000_tt_params = { #define IWL_DEVICE_8000_COMMON \ .device_family = IWL_DEVICE_FAMILY_8000, \ - .max_inst_size = IWL60_RTC_INST_SIZE, \ - .max_data_size = IWL60_RTC_DATA_SIZE, \ .base_params = &iwl8000_base_params, \ .led_mode = IWL_LED_RF_STATE, \ .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \ diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index fe376fce3444..9706624911f8 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -54,7 +54,6 @@ #include #include #include "iwl-config.h" -#include "iwl-agn-hw.h" #include "fw/file.h" /* Highest firmware API version supported */ @@ -135,8 +134,6 @@ static const struct iwl_tt_params iwl9000_tt_params = { .ucode_api_max = IWL9000_UCODE_API_MAX, \ .ucode_api_min = IWL9000_UCODE_API_MIN, \ .device_family = IWL_DEVICE_FAMILY_9000, \ - .max_inst_size = IWL60_RTC_INST_SIZE, \ - .max_data_size = IWL60_RTC_DATA_SIZE, \ .base_params = &iwl9000_base_params, \ .led_mode = IWL_LED_RF_STATE, \ .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_9000, \ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 7f0b7cea8b9b..7752794d0437 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -337,8 +337,8 @@ struct iwl_csr_params { * next step. Supported only in integrated solutions. * @ucode_api_max: Highest version of uCode API supported by driver. * @ucode_api_min: Lowest version of uCode API supported by driver. - * @max_inst_size: The maximal length of the fw inst section - * @max_data_size: The maximal length of the fw data section + * @max_inst_size: The maximal length of the fw inst section (only DVM) + * @max_data_size: The maximal length of the fw data section (only DVM) * @valid_tx_ant: valid transmit antenna * @valid_rx_ant: valid receive antenna * @non_shared_ant: the antenna that is for WiFi only -- cgit v1.2.3 From bf1ad8978bbfd8579dfd10d2e7742d0f554e449a Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 13 Feb 2018 18:41:46 +0200 Subject: iwlwifi: pcie: allow sending pre-built A-MSDUs In case of A-MSDUs, the trans layer is taking care of building the subframes (out of the given skb), according to the given gso_size. However, in some testing flows, we want to build the whole A-MSDU frame in a different place (e.g. userspace), and ask the driver to send it as-is. In case of gso_size==0, simply treat the frame as normal-frame, although the A-MSDU flag is set. Signed-off-by: Eliad Peller Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 1cbb8f470afd..473fe7ccb07c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -2397,7 +2397,13 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, goto out_err; iwl_pcie_txq_build_tfd(trans, txq, tb1_phys, tb1_len, false); - if (amsdu) { + /* + * If gso_size wasn't set, don't give the frame "amsdu treatment" + * (adding subframes, etc.). + * This can happen in some testing flows when the amsdu was already + * pre-built, and we just need to send the resulting skb. + */ + if (amsdu && skb_shinfo(skb)->gso_size) { if (unlikely(iwl_fill_data_tbs_amsdu(trans, skb, txq, hdr_len, out_meta, dev_cmd, tb1_len))) -- cgit v1.2.3 From 18e8f43ff13e0dd0a485bc35bea91df37c26c4bb Mon Sep 17 00:00:00 2001 From: Golan Ben Ami Date: Wed, 22 Nov 2017 11:40:15 +0200 Subject: iwlwifi: support new csr addresses for hw address In future devices we use different csr addresses for hw addresses. Update csr addresses to support new and legacy devices. Signed-off-by: Golan Ben Ami Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 20 ++++++++++++++++++-- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 14 ++++++++++---- 2 files changed, 28 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 7752794d0437..cfd14e5ea59c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -313,6 +313,10 @@ struct iwl_pwr_tx_backoff { * @flag_master_dis: disable master * @flag_stop_master: stop master * @addr_sw_reset: address for resetting the device + * @mac_addr0_otp: first part of MAC address from OTP + * @mac_addr1_otp: second part of MAC address from OTP + * @mac_addr0_strap: first part of MAC address from strap + * @mac_addr1_strap: second part of MAC address from strap */ struct iwl_csr_params { u8 flag_sw_reset; @@ -323,6 +327,10 @@ struct iwl_csr_params { u8 flag_master_dis; u8 flag_stop_master; u8 addr_sw_reset; + u32 mac_addr0_otp; + u32 mac_addr1_otp; + u32 mac_addr0_strap; + u32 mac_addr1_strap; }; /** @@ -451,7 +459,11 @@ static const struct iwl_csr_params iwl_csr_v1 = { .flag_sw_reset = 7, .flag_master_dis = 8, .flag_stop_master = 9, - .addr_sw_reset = (CSR_BASE + 0x020) + .addr_sw_reset = (CSR_BASE + 0x020), + .mac_addr0_otp = 0x380, + .mac_addr1_otp = 0x384, + .mac_addr0_strap = 0x388, + .mac_addr1_strap = 0x38C }; static const struct iwl_csr_params iwl_csr_v2 = { @@ -462,7 +474,11 @@ static const struct iwl_csr_params iwl_csr_v2 = { .flag_master_dis = 28, .flag_stop_master = 29, .flag_sw_reset = 31, - .addr_sw_reset = (CSR_BASE + 0x024) + .addr_sw_reset = (CSR_BASE + 0x024), + .mac_addr0_otp = 0x30, + .mac_addr1_otp = 0x34, + .mac_addr0_strap = 0x38, + .mac_addr1_strap = 0x3C }; /* diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 1f31d7bfdffc..0f9d56420c42 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -579,8 +579,12 @@ static void iwl_flip_hw_address(__le32 mac_addr0, __le32 mac_addr1, u8 *dest) static void iwl_set_hw_address_from_csr(struct iwl_trans *trans, struct iwl_nvm_data *data) { - __le32 mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_STRAP)); - __le32 mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_STRAP)); + __le32 mac_addr0 = + cpu_to_le32(iwl_read32(trans, + trans->cfg->csr->mac_addr0_strap)); + __le32 mac_addr1 = + cpu_to_le32(iwl_read32(trans, + trans->cfg->csr->mac_addr1_strap)); iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); /* @@ -590,8 +594,10 @@ static void iwl_set_hw_address_from_csr(struct iwl_trans *trans, if (is_valid_ether_addr(data->hw_addr)) return; - mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_OTP)); - mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_OTP)); + mac_addr0 = cpu_to_le32(iwl_read32(trans, + trans->cfg->csr->mac_addr0_otp)); + mac_addr1 = cpu_to_le32(iwl_read32(trans, + trans->cfg->csr->mac_addr1_otp)); iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); } -- cgit v1.2.3 From 1e5b7750315a8c2242444acda495555e7d52a6bf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 20 Feb 2018 16:32:36 +0100 Subject: iwlwifi: mvm: move skb padding reservation earlier Future changes will require moving the HE radiotap data into the SKB head, but this means we need to have the alignment reservation done before that. To prepare, move the alignment reservation earlier here. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 34791628cfb3..bb63e75a9b7f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -151,17 +151,9 @@ static void iwl_mvm_create_skb(struct sk_buff *skb, struct ieee80211_hdr *hdr, unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); if (desc->mac_flags2 & IWL_RX_MPDU_MFLG2_PAD) { + len -= 2; pad_len = 2; - - /* - * If the device inserted padding it means that (it thought) - * the 802.11 header wasn't a multiple of 4 bytes long. In - * this case, reserve two bytes at the start of the SKB to - * align the payload properly in case we end up copying it. - */ - skb_reserve(skb, pad_len); } - len -= pad_len; /* If frame is small enough to fit in skb->head, pull it completely. * If not, only pull ieee80211_hdr (including crypto if present, and @@ -866,6 +858,16 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, return; } + if (desc->mac_flags2 & IWL_RX_MPDU_MFLG2_PAD) { + /* + * If the device inserted padding it means that (it thought) + * the 802.11 header wasn't a multiple of 4 bytes long. In + * this case, reserve two bytes at the start of the SKB to + * align the payload properly in case we end up copying it. + */ + skb_reserve(skb, 2); + } + rx_status = IEEE80211_SKB_RXCB(skb); if (iwl_mvm_rx_crypto(mvm, hdr, rx_status, desc, -- cgit v1.2.3 From 9039d985811d5b109b58b202b7594fd24e433fed Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Tue, 13 Feb 2018 11:09:40 +0200 Subject: iwlwifi: fw: harden page loading code The page loading code trusts the data provided in the firmware images a bit too much and may cause a buffer overflow or copy unknown data if the block sizes don't match what we expect. To prevent potential problems, harden the code by checking if the sizes we are copying are what we expect. Cc: stable@vger.kernel.org Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/paging.c | 49 +++++++++++++++++++++----- 1 file changed, 41 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/paging.c b/drivers/net/wireless/intel/iwlwifi/fw/paging.c index 1fec8e3a6b35..6afcfd1f0eec 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/paging.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/paging.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -163,7 +165,7 @@ static int iwl_alloc_fw_paging_mem(struct iwl_fw_runtime *fwrt, static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt, const struct fw_img *image) { - int sec_idx, idx; + int sec_idx, idx, ret; u32 offset = 0; /* @@ -190,17 +192,23 @@ static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt, */ if (sec_idx >= image->num_sec - 1) { IWL_ERR(fwrt, "Paging: Missing CSS and/or paging sections\n"); - iwl_free_fw_paging(fwrt); - return -EINVAL; + ret = -EINVAL; + goto err; } /* copy the CSS block to the dram */ IWL_DEBUG_FW(fwrt, "Paging: load paging CSS to FW, sec = %d\n", sec_idx); + if (image->sec[sec_idx].len > fwrt->fw_paging_db[0].fw_paging_size) { + IWL_ERR(fwrt, "CSS block is larger than paging size\n"); + ret = -EINVAL; + goto err; + } + memcpy(page_address(fwrt->fw_paging_db[0].fw_paging_block), image->sec[sec_idx].data, - fwrt->fw_paging_db[0].fw_paging_size); + image->sec[sec_idx].len); dma_sync_single_for_device(fwrt->trans->dev, fwrt->fw_paging_db[0].fw_paging_phys, fwrt->fw_paging_db[0].fw_paging_size, @@ -221,6 +229,14 @@ static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt, for (idx = 1; idx < fwrt->num_of_paging_blk; idx++) { struct iwl_fw_paging *block = &fwrt->fw_paging_db[idx]; + if (block->fw_paging_size > image->sec[sec_idx].len - offset) { + IWL_ERR(fwrt, + "Paging: paging size is larger than remaining data in block %d\n", + idx); + ret = -EINVAL; + goto err; + } + memcpy(page_address(block->fw_paging_block), image->sec[sec_idx].data + offset, block->fw_paging_size); @@ -231,19 +247,32 @@ static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt, IWL_DEBUG_FW(fwrt, "Paging: copied %d paging bytes to block %d\n", - fwrt->fw_paging_db[idx].fw_paging_size, - idx); + block->fw_paging_size, idx); - offset += fwrt->fw_paging_db[idx].fw_paging_size; + offset += block->fw_paging_size; + + if (offset > image->sec[sec_idx].len) { + IWL_ERR(fwrt, + "Paging: offset goes over section size\n"); + ret = -EINVAL; + goto err; + } } /* copy the last paging block */ if (fwrt->num_of_pages_in_last_blk > 0) { struct iwl_fw_paging *block = &fwrt->fw_paging_db[idx]; + if (image->sec[sec_idx].len - offset > block->fw_paging_size) { + IWL_ERR(fwrt, + "Paging: last block is larger than paging size\n"); + ret = -EINVAL; + goto err; + } + memcpy(page_address(block->fw_paging_block), image->sec[sec_idx].data + offset, - FW_PAGING_SIZE * fwrt->num_of_pages_in_last_blk); + image->sec[sec_idx].len - offset); dma_sync_single_for_device(fwrt->trans->dev, block->fw_paging_phys, block->fw_paging_size, @@ -255,6 +284,10 @@ static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt, } return 0; + +err: + iwl_free_fw_paging(fwrt); + return ret; } static int iwl_save_fw_paging(struct iwl_fw_runtime *fwrt, -- cgit v1.2.3 From de460ddd8b795ceca8a826771ef8feb016bb438d Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Wed, 14 Feb 2018 08:54:40 +0200 Subject: iwlwifi: fw: combine loading of last page block into main copy loop Now that we check and copy only the actual size of the page block, there is no need to treat the last block separately. Remove the mostly duplicate code and make the main copy loop handle also the last block. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/paging.c | 69 ++++++++++---------------- 1 file changed, 26 insertions(+), 43 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/paging.c b/drivers/net/wireless/intel/iwlwifi/fw/paging.c index 6afcfd1f0eec..9b8dd7fe7112 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/paging.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/paging.c @@ -221,25 +221,39 @@ static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt, sec_idx++; /* - * copy the paging blocks to the dram - * loop index start from 1 since that CSS block already copied to dram - * and CSS index is 0. - * loop stop at num_of_paging_blk since that last block is not full. + * Copy the paging blocks to the dram. The loop index starts + * from 1 since the CSS block (index 0) was already copied to + * dram. We use num_of_paging_blk + 1 to account for that. */ - for (idx = 1; idx < fwrt->num_of_paging_blk; idx++) { + for (idx = 1; idx < fwrt->num_of_paging_blk + 1; idx++) { struct iwl_fw_paging *block = &fwrt->fw_paging_db[idx]; - - if (block->fw_paging_size > image->sec[sec_idx].len - offset) { + int remaining = image->sec[sec_idx].len - offset; + int len = block->fw_paging_size; + + /* + * For the last block, we copy all that is remaining, + * for all other blocks, we copy fw_paging_size at a + * time. */ + if (idx == fwrt->num_of_paging_blk) { + len = remaining; + if (remaining != + fwrt->num_of_pages_in_last_blk * FW_PAGING_SIZE) { + IWL_ERR(fwrt, + "Paging: last block contains more data than expected %d\n", + remaining); + ret = -EINVAL; + goto err; + } + } else if (block->fw_paging_size > remaining) { IWL_ERR(fwrt, - "Paging: paging size is larger than remaining data in block %d\n", - idx); + "Paging: not enough data in other in block %d (%d)\n", + idx, remaining); ret = -EINVAL; goto err; } memcpy(page_address(block->fw_paging_block), - image->sec[sec_idx].data + offset, - block->fw_paging_size); + image->sec[sec_idx].data + offset, len); dma_sync_single_for_device(fwrt->trans->dev, block->fw_paging_phys, block->fw_paging_size, @@ -247,40 +261,9 @@ static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt, IWL_DEBUG_FW(fwrt, "Paging: copied %d paging bytes to block %d\n", - block->fw_paging_size, idx); + len, idx); offset += block->fw_paging_size; - - if (offset > image->sec[sec_idx].len) { - IWL_ERR(fwrt, - "Paging: offset goes over section size\n"); - ret = -EINVAL; - goto err; - } - } - - /* copy the last paging block */ - if (fwrt->num_of_pages_in_last_blk > 0) { - struct iwl_fw_paging *block = &fwrt->fw_paging_db[idx]; - - if (image->sec[sec_idx].len - offset > block->fw_paging_size) { - IWL_ERR(fwrt, - "Paging: last block is larger than paging size\n"); - ret = -EINVAL; - goto err; - } - - memcpy(page_address(block->fw_paging_block), - image->sec[sec_idx].data + offset, - image->sec[sec_idx].len - offset); - dma_sync_single_for_device(fwrt->trans->dev, - block->fw_paging_phys, - block->fw_paging_size, - DMA_BIDIRECTIONAL); - - IWL_DEBUG_FW(fwrt, - "Paging: copied %d pages in the last block %d\n", - fwrt->num_of_pages_in_last_blk, idx); } return 0; -- cgit v1.2.3 From 49564a806fc5551ef22140e9aa4e29c6788d3eb0 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Tue, 12 Dec 2017 08:58:41 +0200 Subject: iwlwifi: pcie: remove non-responsive device If we fail to to grab NIC access because the device is not responding (i.e. CSR_GP_CNTRL returns 0xFFFFFFFF), remove the device from the PCI bus, to avoid any further damage, and to let the user space rescan. In order to inform the userspace that a rescan is needed, we send a kobject uevent with "INACCESSIBLE". This functionality is disabled by default, but can be enabled via a new module parameter called "remove_when_gone". In the future we may change this module parameter to include 3 modes instead: do nothing; auto-rescan or; send uevent. Signed-off-by: Luca Coelho Signed-off-by: Rajat Jain --- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 6 ++ drivers/net/wireless/intel/iwlwifi/iwl-modparams.h | 2 + drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 5 ++ drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 74 +++++++++++++++++++++- 4 files changed, 84 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 4f451a6f20b9..c59ce4f8a5ed 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1850,3 +1850,9 @@ MODULE_PARM_DESC(d0i3_timeout, "Timeout to D0i3 entry when idle (ms)"); module_param_named(disable_11ac, iwlwifi_mod_params.disable_11ac, bool, 0444); MODULE_PARM_DESC(disable_11ac, "Disable VHT capabilities (default: false)"); + +module_param_named(remove_when_gone, + iwlwifi_mod_params.remove_when_gone, bool, + 0444); +MODULE_PARM_DESC(remove_when_gone, + "Remove dev from PCIe bus if it is deemed inaccessible (default: false)"); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h index a41c46e63eb1..a7dd8a8cddf9 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h @@ -122,6 +122,7 @@ enum iwl_uapsd_disable { * @lar_disable: disable LAR (regulatory), default = 0 * @fw_monitor: allow to use firmware monitor * @disable_11ac: disable VHT capabilities, default = false. + * @remove_when_gone: remove an inaccessible device from the PCIe bus. */ struct iwl_mod_params { int swcrypto; @@ -143,6 +144,7 @@ struct iwl_mod_params { bool lar_disable; bool fw_monitor; bool disable_11ac; + bool remove_when_gone; }; #endif /* #__iwl_modparams_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index cda66340d357..45ea32796cda 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -383,6 +383,8 @@ struct iwl_self_init_dram { * @hw_init_mask: initial unmasked hw causes * @fh_mask: current unmasked fh causes * @hw_mask: current unmasked hw causes + * @in_rescan: true if we have triggered a device rescan + * @scheduled_for_removal: true if we have scheduled a device removal */ struct iwl_trans_pcie { struct iwl_rxq *rxq; @@ -464,6 +466,9 @@ struct iwl_trans_pcie { u32 fh_mask; u32 hw_mask; cpumask_t affinity_mask[IWL_MAX_RX_HW_QUEUES]; + u16 tx_cmd_queue_size; + bool in_rescan; + bool scheduled_for_removal; }; static inline struct iwl_trans_pcie * diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 623476603cd4..6e9a9ecfb11c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -75,6 +75,7 @@ #include #include #include +#include #include "iwl-drv.h" #include "iwl-trans.h" @@ -1935,6 +1936,29 @@ static void iwl_trans_pcie_set_pmi(struct iwl_trans *trans, bool state) clear_bit(STATUS_TPOWER_PMI, &trans->status); } +struct iwl_trans_pcie_removal { + struct pci_dev *pdev; + struct work_struct work; +}; + +static void iwl_trans_pcie_removal_wk(struct work_struct *wk) +{ + struct iwl_trans_pcie_removal *removal = + container_of(wk, struct iwl_trans_pcie_removal, work); + struct pci_dev *pdev = removal->pdev; + char *prop[] = {"EVENT=INACCESSIBLE", NULL}; + + dev_err(&pdev->dev, "Device gone - attempting removal\n"); + kobject_uevent_env(&pdev->dev.kobj, KOBJ_CHANGE, prop); + pci_lock_rescan_remove(); + pci_dev_put(pdev); + pci_stop_and_remove_bus_device(pdev); + pci_unlock_rescan_remove(); + + kfree(removal); + module_put(THIS_MODULE); +} + static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, unsigned long *flags) { @@ -1977,11 +2001,55 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, (BIT(trans->cfg->csr->flag_mac_clock_ready) | CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); if (unlikely(ret < 0)) { - iwl_trans_pcie_dump_regs(trans); - iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); + u32 cntrl = iwl_read32(trans, CSR_GP_CNTRL); + WARN_ONCE(1, "Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n", - iwl_read32(trans, CSR_GP_CNTRL)); + cntrl); + + iwl_trans_pcie_dump_regs(trans); + + if (iwlwifi_mod_params.remove_when_gone && cntrl == ~0U) { + struct iwl_trans_pcie_removal *removal; + + if (trans_pcie->scheduled_for_removal) + goto err; + + IWL_ERR(trans, "Device gone - scheduling removal!\n"); + + /* + * get a module reference to avoid doing this + * while unloading anyway and to avoid + * scheduling a work with code that's being + * removed. + */ + if (!try_module_get(THIS_MODULE)) { + IWL_ERR(trans, + "Module is being unloaded - abort\n"); + goto err; + } + + removal = kzalloc(sizeof(*removal), GFP_ATOMIC); + if (!removal) { + module_put(THIS_MODULE); + goto err; + } + /* + * we don't need to clear this flag, because + * the trans will be freed and reallocated. + */ + trans_pcie->scheduled_for_removal = true; + + removal->pdev = to_pci_dev(trans->dev); + INIT_WORK(&removal->work, iwl_trans_pcie_removal_wk); + pci_dev_get(removal->pdev); + schedule_work(&removal->work); + } else { + iwl_write32(trans, CSR_RESET, + CSR_RESET_REG_FLAG_FORCE_NMI); + } + +err: spin_unlock_irqrestore(&trans_pcie->reg_lock, *flags); return false; } -- cgit v1.2.3 From c3039b10df74818bdd1d7e9d2b8706c855c4394b Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Thu, 22 Feb 2018 14:50:06 +0200 Subject: iwlwifi: make bitfield a u32 instead of u16 The bitfield we use in struct iwl_cfg contains 17 bits, but we declare it as u16. The compiler doesn't seem to have any problems with that (it probably automatically makes it u32), but it's cleaner to use a type that is long enough for all the flags. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index cfd14e5ea59c..c503b26793f6 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -420,7 +420,7 @@ struct iwl_cfg { u32 soc_latency; u16 nvm_ver; u16 nvm_calib_ver; - u16 rx_with_siso_diversity:1, + u32 rx_with_siso_diversity:1, bt_shared_single_ant:1, internal_wimax_coex:1, host_interrupt_operation_mode:1, -- cgit v1.2.3 From 755a654cada277b1851737845f63c7ab2059c982 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 4 Feb 2018 15:01:37 +0200 Subject: iwlwifi: mvm: remove check for non low latency TIDs Firmware will only send non low-latency TIDs in the bitmap, so the check is now redundant. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index d0916f2552e2..df4c60496f72 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -803,7 +803,6 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb); if (iwl_mvm_vif_low_latency(iwl_mvm_vif_from_mac80211(mvmsta->vif)) || - tid_to_mac80211_ac[tid] < IEEE80211_AC_BE || !(mvmsta->amsdu_enabled & BIT(tid))) return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb); -- cgit v1.2.3 From d3a6f7fb97fc34a38e40cc56392e701598f99863 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 22 Feb 2018 18:45:49 +0200 Subject: iwlwifi: mvm: set wakeup filters for wowlan "any" configuration In case of "any" wowlan trigger is configured, no valid wakeup filter was configured. Moreover, the fw assumes there's no connection when there are no configured wakeup filters. This leads to the station info not being updated on D3 command, causing rate_n_flags to be 0 when the offloading code sends tx frame (triggering SYSASSERT_102C due to invalid antenna param) Note: "any" trigger is currently assumed to only be used when entering d0i3 (which has a different flow). However, we still reach this code when using d3_test. Signed-off-by: Eliad Peller Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 80a9a7cb83be..3fcf489f3120 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -18,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * @@ -35,6 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -693,6 +690,14 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, IWL_WOWLAN_WAKEUP_LINK_CHANGE); } + if (wowlan->any) { + wowlan_config_cmd->wakeup_filter |= + cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS | + IWL_WOWLAN_WAKEUP_LINK_CHANGE | + IWL_WOWLAN_WAKEUP_RX_FRAME | + IWL_WOWLAN_WAKEUP_BCN_FILTERING); + } + return 0; } -- cgit v1.2.3 From 2f177c1628c3f54cdfcc8093cd4b5297f4baeec4 Mon Sep 17 00:00:00 2001 From: Venkateswara Naralasetty Date: Wed, 25 Apr 2018 11:36:40 +0300 Subject: ath10k: fix information leak in debugfs During write to some of debugfs in ath10k, few variables exposing stack data when process user input. which leads to possible information leak. This patch fix this issue by initializing buffer and checks the return valure of 'simple_write_to_buffer'. Signed-off-by: Venkateswara Naralasetty Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 20 +++++++++--------- drivers/net/wireless/ath/ath10k/debugfs_sta.c | 30 +++++++++++++-------------- 2 files changed, 25 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index bac832ce1873..57d22cd976e5 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -987,13 +987,13 @@ static ssize_t ath10k_write_htt_max_amsdu_ampdu(struct file *file, { struct ath10k *ar = file->private_data; int res; - char buf[64]; + char buf[64] = {0}; unsigned int amsdu, ampdu; - simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); - - /* make sure that buf is null terminated */ - buf[sizeof(buf) - 1] = 0; + res = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, + user_buf, count); + if (res <= 0) + return res; res = sscanf(buf, "%u %u", &amsdu, &du); @@ -1043,14 +1043,14 @@ static ssize_t ath10k_write_fw_dbglog(struct file *file, { struct ath10k *ar = file->private_data; int ret; - char buf[96]; + char buf[96] = {0}; unsigned int log_level; u64 mask; - simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); - - /* make sure that buf is null terminated */ - buf[sizeof(buf) - 1] = 0; + ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, + user_buf, count); + if (ret <= 0) + return ret; ret = sscanf(buf, "%llx %u", &mask, &log_level); diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c index 8f688f136c22..a63c97e2c50c 100644 --- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -254,12 +254,12 @@ static ssize_t ath10k_dbg_sta_write_addba(struct file *file, struct ath10k *ar = arsta->arvif->ar; u32 tid, buf_size; int ret; - char buf[64]; + char buf[64] = {0}; - simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); - - /* make sure that buf is null terminated */ - buf[sizeof(buf) - 1] = '\0'; + ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, + user_buf, count); + if (ret <= 0) + return ret; ret = sscanf(buf, "%u %u", &tid, &buf_size); if (ret != 2) @@ -305,12 +305,12 @@ static ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file, struct ath10k *ar = arsta->arvif->ar; u32 tid, status; int ret; - char buf[64]; - - simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + char buf[64] = {0}; - /* make sure that buf is null terminated */ - buf[sizeof(buf) - 1] = '\0'; + ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, + user_buf, count); + if (ret <= 0) + return ret; ret = sscanf(buf, "%u %u", &tid, &status); if (ret != 2) @@ -355,12 +355,12 @@ static ssize_t ath10k_dbg_sta_write_delba(struct file *file, struct ath10k *ar = arsta->arvif->ar; u32 tid, initiator, reason; int ret; - char buf[64]; - - simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + char buf[64] = {0}; - /* make sure that buf is null terminated */ - buf[sizeof(buf) - 1] = '\0'; + ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, + user_buf, count); + if (ret <= 0) + return ret; ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason); if (ret != 3) -- cgit v1.2.3 From 4b190675ad06f5a6ecbeef0b01890c5fb372e3eb Mon Sep 17 00:00:00 2001 From: Tamizh Chelvam Date: Wed, 25 Apr 2018 11:36:44 +0300 Subject: ath10k: fix kernel panic while reading tpc_stats When attempt to read tpc_stats for the chipsets which support more than 3 tx chain will trigger kernel panic(kernel stack is corrupted) due to writing values on rate_code array out of range. This patch changes the array size depends on the WMI_TPC_TX_N_CHAIN and added check to avoid write values on the array if the num tx chain get in tpc config event is greater than WMI_TPC_TX_N_CHAIN. Tested on QCA9984 with firmware-5.bin_10.4-3.5.3-00057 Kernel panic log : [ 323.510944] Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: bf90c654 [ 323.510944] [ 323.524390] CPU: 0 PID: 1908 Comm: cat Not tainted 3.14.77 #31 [ 323.530224] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 323.537941] [] (show_stack) from [] (dump_stack+0x80/0xa0) [ 323.545146] [] (dump_stack) from [] (panic+0x84/0x1e4) [ 323.552000] [] (panic) from [] (__stack_chk_fail+0x10/0x14) [ 323.559350] [] (__stack_chk_fail) from [] (ath10k_wmi_event_pdev_tpc_config+0x424/0x438 [ath10k_core]) [ 323.570471] [] (ath10k_wmi_event_pdev_tpc_config [ath10k_core]) from [] (ath10k_wmi_10_4_op_rx+0x2f0/0x39c [ath10k_core]) [ 323.583047] [] (ath10k_wmi_10_4_op_rx [ath10k_core]) from [] (ath10k_htc_rx_completion_handler+0x170/0x1a0 [ath10k_core]) [ 323.595702] [] (ath10k_htc_rx_completion_handler [ath10k_core]) from [] (ath10k_pci_hif_send_complete_check+0x1f0/0x220 [ath10k_pci]) [ 323.609421] [] (ath10k_pci_hif_send_complete_check [ath10k_pci]) from [] (ath10k_ce_per_engine_service+0x74/0xc4 [ath10k_pci]) [ 323.622490] [] (ath10k_ce_per_engine_service [ath10k_pci]) from [] (ath10k_ce_per_engine_service_any+0x74/0x80 [ath10k_pci]) [ 323.635423] [] (ath10k_ce_per_engine_service_any [ath10k_pci]) from [] (ath10k_pci_napi_poll+0x44/0xe8 [ath10k_pci]) [ 323.647665] [] (ath10k_pci_napi_poll [ath10k_pci]) from [] (net_rx_action+0xac/0x160) [ 323.657208] [] (net_rx_action) from [] (__do_softirq+0x104/0x294) [ 323.665017] [] (__do_softirq) from [] (irq_exit+0x9c/0x11c) [ 323.672314] [] (irq_exit) from [] (handle_IRQ+0x6c/0x90) [ 323.679341] [] (handle_IRQ) from [] (gic_handle_irq+0x3c/0x60) [ 323.686893] [] (gic_handle_irq) from [] (__irq_svc+0x40/0x70) [ 323.694349] Exception stack(0xdd489c58 to 0xdd489ca0) [ 323.699384] 9c40: 00000000 a0000013 [ 323.707547] 9c60: 00000000 dc4bce40 60000013 ddc1d800 dd488000 00000990 00000000 c085c800 [ 323.715707] 9c80: 00000000 dd489d44 0000092d dd489ca0 c026e664 c026e668 60000013 ffffffff [ 323.723877] [] (__irq_svc) from [] (rcu_note_context_switch+0x170/0x184) [ 323.732298] [] (rcu_note_context_switch) from [] (__schedule+0x50/0x4d4) [ 323.740716] [] (__schedule) from [] (schedule_timeout+0x148/0x178) [ 323.748611] [] (schedule_timeout) from [] (wait_for_common+0x114/0x154) [ 323.756972] [] (wait_for_common) from [] (ath10k_tpc_stats_open+0xc8/0x340 [ath10k_core]) [ 323.766873] [] (ath10k_tpc_stats_open [ath10k_core]) from [] (do_dentry_open+0x1ac/0x274) [ 323.776741] [] (do_dentry_open) from [] (do_last+0x8c0/0xb08) [ 323.784201] [] (do_last) from [] (path_openat+0x210/0x598) [ 323.791408] [] (path_openat) from [] (do_filp_open+0x2c/0x78) [ 323.798873] [] (do_filp_open) from [] (do_sys_open+0x114/0x1b4) [ 323.806509] [] (do_sys_open) from [] (ret_fast_syscall+0x0/0x44) [ 323.814241] CPU1: stopping [ 323.816927] CPU: 1 PID: 0 Comm: swapper/1 Not tainted 3.14.77 #31 [ 323.823008] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 323.830731] [] (show_stack) from [] (dump_stack+0x80/0xa0) [ 323.837934] [] (dump_stack) from [] (handle_IPI+0xb8/0x140) [ 323.845224] [] (handle_IPI) from [] (gic_handle_irq+0x58/0x60) [ 323.852774] [] (gic_handle_irq) from [] (__irq_svc+0x40/0x70) [ 323.860233] Exception stack(0xdd499fa0 to 0xdd499fe8) [ 323.865273] 9fa0: ffffffed 00000000 1d3c9000 00000000 dd498000 dd498030 10c0387d c08b62c8 [ 323.873432] 9fc0: 4220406a 512f04d0 00000000 00000000 00000001 dd499fe8 c021838c c0218390 [ 323.881588] 9fe0: 60000013 ffffffff [ 323.885070] [] (__irq_svc) from [] (arch_cpu_idle+0x30/0x50) [ 323.892454] [] (arch_cpu_idle) from [] (cpu_startup_entry+0xa4/0x108) [ 323.900690] [] (cpu_startup_entry) from [<422085a4>] (0x422085a4) Signed-off-by: Tamizh chelvam Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 8 +++++++- drivers/net/wireless/ath/ath10k/wmi.c | 6 ++++++ drivers/net/wireless/ath/ath10k/wmi.h | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 57d22cd976e5..0d98c93a3aba 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -1519,7 +1519,13 @@ static void ath10k_tpc_stats_print(struct ath10k_tpc_stats *tpc_stats, *len += scnprintf(buf + *len, buf_len - *len, "********************************\n"); *len += scnprintf(buf + *len, buf_len - *len, - "No. Preamble Rate_code tpc_value1 tpc_value2 tpc_value3\n"); + "No. Preamble Rate_code "); + + for (i = 0; i < WMI_TPC_TX_N_CHAIN; i++) + *len += scnprintf(buf + *len, buf_len - *len, + "tpc_value%d ", i); + + *len += scnprintf(buf + *len, buf_len - *len, "\n"); for (i = 0; i < tpc_stats->rate_max; i++) { *len += scnprintf(buf + *len, buf_len - *len, diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index df2e92a6c9bd..d7dba1791a1a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4484,6 +4484,12 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) num_tx_chain = __le32_to_cpu(ev->num_tx_chain); + if (num_tx_chain > WMI_TPC_TX_N_CHAIN) { + ath10k_warn(ar, "number of tx chain is %d greater than TPC configured tx chain %d\n", + num_tx_chain, WMI_TPC_TX_N_CHAIN); + return; + } + ath10k_wmi_tpc_config_get_rate_code(rate_code, pream_table, num_tx_chain); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 16a39244a34f..700b12f46baf 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4026,9 +4026,9 @@ struct wmi_pdev_get_tpc_config_cmd { } __packed; #define WMI_TPC_CONFIG_PARAM 1 -#define WMI_TPC_RATE_MAX 160 #define WMI_TPC_FINAL_RATE_MAX 240 #define WMI_TPC_TX_N_CHAIN 4 +#define WMI_TPC_RATE_MAX (WMI_TPC_TX_N_CHAIN * 65) #define WMI_TPC_PREAM_TABLE_MAX 10 #define WMI_TPC_FLAG 3 #define WMI_TPC_BUF_SIZE 10 -- cgit v1.2.3 From 378b1d65070f3c989a662555eda8564cdd937b4a Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Tue, 24 Apr 2018 15:18:59 +0200 Subject: ath6kl: fix ath6kl_data_tx()'s return type The method ndo_start_xmit() is defined as returning an 'netdev_tx_t', which is a typedef for an enum type, but the implementation in this driver returns an 'int'. Fix this by returning 'netdev_tx_t' in this driver too. Signed-off-by: Luc Van Oostenryck Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/core.h | 2 +- drivers/net/wireless/ath/ath6kl/txrx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index e23d450babd2..0d30e762c090 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -914,7 +914,7 @@ void ath6kl_tx_data_cleanup(struct ath6kl *ar); struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar); void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie); -int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev); +netdev_tx_t ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev); struct aggr_info *aggr_init(struct ath6kl_vif *vif); void aggr_conn_init(struct ath6kl_vif *vif, struct aggr_info *aggr_info, diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index 8da9506f8c2b..618d12ed4b40 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -353,7 +353,7 @@ fail_ctrl_tx: return status; } -int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) +netdev_tx_t ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) { struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_cookie *cookie = NULL; -- cgit v1.2.3 From 785281342d0ce06ec04e4b730fb29b6320139edc Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 26 Apr 2018 10:12:44 +0100 Subject: ath10k: fix spelling mistake: "servive" -> "service" Trivial fix to spelling mistake in ath10k_warn warning message text Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index d7dba1791a1a..bb8e9e259a56 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5286,7 +5286,7 @@ void ath10k_wmi_event_service_available(struct ath10k *ar, struct sk_buff *skb) ret = ath10k_wmi_pull_svc_avail(ar, skb, &arg); if (ret) { - ath10k_warn(ar, "failed to parse servive available event: %d\n", + ath10k_warn(ar, "failed to parse service available event: %d\n", ret); } -- cgit v1.2.3 From e60a92590187d01f1c98254d2d7e8f613ebd31dd Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 26 Apr 2018 14:35:02 +0200 Subject: ath10k: sdio: jump to correct label in error handling path Jump to the correct label in error handling path. At this point of execution create_singlethread_workqueue() has succeeded, so it should be properly destroyed. Jump label was renamed in commit ec2c64e20257 ("ath10k: sdio: fix memory leak for probe allocations"). However, the bug was originally introduced in commit d96db25d2025 ("ath10k: add initial SDIO support"). Fixes: d96db25d2025 ("ath10k: add initial SDIO support") Signed-off-by: Niklas Cassel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 2d04c54a4153..d612ce8c9cff 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -2011,7 +2011,7 @@ static int ath10k_sdio_probe(struct sdio_func *func, ret = -ENODEV; ath10k_err(ar, "unsupported device id %u (0x%x)\n", dev_id_base, id->device); - goto err_core_destroy; + goto err_free_wq; } ar->id.vendor = id->vendor; -- cgit v1.2.3 From 97389373d555cdc03ed346d7dc6f714a1586c705 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 18 Apr 2018 00:27:18 +0200 Subject: mt76x2: fix is_mt7612 routine Fix is_mt7612 routine since asic version is set in mt76_dev revision field and not in mt76x2_dev one. Moreover remove mt76x2_dev rev field since it is never used in the driver Fixes: 7bc04215a66b ('mt76: add driver code for MT76x2e') Signed-off-by: Lorenzo Bianconi Acked-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x2.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index 783b8122ec3c..a5d1255e4b9c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -117,7 +117,6 @@ struct mt76x2_dev { u8 beacon_mask; u8 beacon_data_mask; - u32 rev; u32 rxfilter; u16 chainmask; @@ -151,7 +150,7 @@ struct mt76x2_sta { static inline bool is_mt7612(struct mt76x2_dev *dev) { - return (dev->rev >> 16) == 0x7612; + return mt76_chip(&dev->mt76) == 0x7612; } void mt76x2_set_irq_mask(struct mt76x2_dev *dev, u32 clear, u32 set); -- cgit v1.2.3 From c3d7c82a8bb017e43cafe8eaf7c8309f85ceb781 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 25 Apr 2018 11:11:21 +0200 Subject: mt76: fix concurrent rx calls on A-MPDU release Add a spinlock in mt76_rx_complete. Without this, multiple stats updates could happen in parallel, which can lead to deadlocks. There are probably more corner cases fixed by this change. Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mac80211.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x2_init.c | 1 + 3 files changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index eb49e0a6758c..915e61733131 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -561,6 +561,7 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, if (queue >= 0) napi = &dev->napi[queue]; + spin_lock(&dev->rx_lock); while ((skb = __skb_dequeue(frames)) != NULL) { if (mt76_check_ccmp_pn(skb)) { dev_kfree_skb(skb); @@ -570,6 +571,7 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, sta = mt76_rx_convert(skb); ieee80211_rx_napi(dev->hw, sta, skb, napi); } + spin_unlock(&dev->rx_lock); } void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 065ff78059c3..a74e6eef51e9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -241,6 +241,7 @@ struct mt76_dev { struct device *dev; struct net_device napi_dev; + spinlock_t rx_lock; struct napi_struct napi[__MT_RXQ_MAX]; struct sk_buff_head rx_skb[__MT_RXQ_MAX]; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index 359b105235b3..d21e4a7c1bb9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -645,6 +645,7 @@ struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev) dev->mt76.drv = &drv_ops; mutex_init(&dev->mutex); spin_lock_init(&dev->irq_lock); + spin_lock_init(&dev->mt76.rx_lock); return dev; } -- cgit v1.2.3 From 9febfa67ca1566294ea5fd1f95ebf02181e7a233 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 25 Apr 2018 11:11:22 +0200 Subject: mt76: add rcu locking in tid reorder function Avoids having the tid or station entry disappear prematurely. Also cancel the reorder work earlier to avoid further processing delayed by waiting for the lock to be released Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/agg-rx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c index dbf4057d2d3e..b67acc6189bf 100644 --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c @@ -103,6 +103,7 @@ mt76_rx_aggr_reorder_work(struct work_struct *work) __skb_queue_head_init(&frames); local_bh_disable(); + rcu_read_lock(); spin_lock(&tid->lock); mt76_rx_aggr_check_release(tid, &frames); @@ -114,6 +115,7 @@ mt76_rx_aggr_reorder_work(struct work_struct *work) REORDER_TIMEOUT); mt76_rx_complete(dev, &frames, -1); + rcu_read_unlock(); local_bh_enable(); } @@ -266,6 +268,8 @@ static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid) u8 size = tid->size; int i; + cancel_delayed_work(&tid->reorder_work); + spin_lock_bh(&tid->lock); tid->stopped = true; @@ -280,8 +284,6 @@ static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid) } spin_unlock_bh(&tid->lock); - - cancel_delayed_work(&tid->reorder_work); } void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno) -- cgit v1.2.3 From 1d868b70e06a2319fdda46cc46ec7c6762557543 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 25 Apr 2018 11:11:23 +0200 Subject: mt76: add rcu locking around tx scheduling Fixes a reported lockdep error in mac80211: [ 179.867321] ============================= [ 179.871510] WARNING: suspicious RCU usage [ 179.875528] 4.14.32 #0 Not tainted [ 179.878924] ----------------------------- [ 179.882981] backports-2017-11-01/net/mac80211/tx.c:594 suspicious rcu_dereference_check() usage! [ 179.891785] [ 179.891785] other info that might help us debug this: [ 179.891785] [ 179.899824] [ 179.899824] rcu_scheduler_active = 2, debug_locks = 1 [ 179.906343] 2 locks held by ksoftirqd/0/7: [ 179.910479] #0: (&(&q->lock)->rlock){+.-.}, at: [<86b207a4>] mt76_dma_tx_cleanup+0x64/0x354 [mt76] [ 179.919734] #1: (&(&fq->lock)->rlock){+.-.}, at: [<87238410>] ieee80211_tx_dequeue+0x54/0xc3c [mac80211] [ 179.929890] [ 179.929890] stack backtrace: [ 179.934257] CPU: 0 PID: 7 Comm: ksoftirqd/0 Not tainted 4.14.32 #0 [ 179.940421] Stack : 00000000 00000000 00000000 00000000 80e0fce2 00000036 00000000 00000000 [ 179.948864] 87c3d24c 80696377 8061039c 00000000 00000007 00000001 87c5db78 6534689d [ 179.957306] 00000000 00000000 80e10000 87c5da74 00000001 0000015a 00000007 00000000 [ 179.965748] 00000000 806a0000 000e4171 00000000 00000000 00000000 ffffffff 00000001 [ 179.974189] 806c0000 8692b240 86b000d0 87316fe4 00000001 802c9a68 00000000 80700000 [ 179.982632] ... [ 179.985104] Call Trace: [ 179.987582] [<80010a48>] show_stack+0x58/0x100 [ 179.992040] [<804c2c58>] dump_stack+0xe8/0x170 [ 179.996868] [<87234a04>] ieee80211_tx_h_select_key+0xa8/0x5b8 [mac80211] [ 180.004299] [<87238d44>] ieee80211_tx_dequeue+0x988/0xc3c [mac80211] [ 180.011048] [<86b230dc>] mt76_txq_schedule+0x110/0x3a4 [mt76] [ 180.016821] [<86b209d0>] mt76_dma_tx_cleanup+0x290/0x354 [mt76] [ 180.022777] [<86be2e60>] mt7603_tx_tasklet+0x40/0x6c [mt7603e] [ 180.028637] [<80037058>] tasklet_action+0x110/0x1ec [ 180.033532] [<804e1dac>] __do_softirq+0x164/0x35c [ 180.038235] [<80037174>] run_ksoftirqd+0x40/0x84 [ 180.042870] [<800580c8>] smpboot_thread_fn+0x1a8/0x1d8 [ 180.048023] [<800542e8>] kthread+0x130/0x144 [ 180.052297] [<8000b1f8>] ret_from_kernel_thread+0x14/0x1c Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/tx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 4eef69bd8a9e..6aca794cf998 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -422,12 +422,14 @@ void mt76_txq_schedule(struct mt76_dev *dev, struct mt76_queue *hwq) { int len; + rcu_read_lock(); do { if (hwq->swq_queued >= 4 || list_empty(&hwq->swq)) break; len = mt76_txq_schedule_list(dev, hwq); } while (len > 0); + rcu_read_unlock(); } EXPORT_SYMBOL_GPL(mt76_txq_schedule); -- cgit v1.2.3 From 95135e8c0b4add86d3ce1ab5a24881b673c2db04 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 25 Apr 2018 11:11:24 +0200 Subject: mt76: check for pending reset before attempting to schedule tx The check within mt76_txq_send_burst is not enough, as it happens after a first frame has already been queued up Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/tx.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 6aca794cf998..7ecd2d7c5db4 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -385,6 +385,10 @@ restart: bool empty = false; int cur; + if (test_bit(MT76_SCANNING, &dev->state) || + test_bit(MT76_RESET, &dev->state)) + return -EBUSY; + mtxq = list_first_entry(&hwq->swq, struct mt76_txq, list); if (mtxq->send_bar && mtxq->aggr) { struct ieee80211_txq *txq = mtxq_to_txq(mtxq); -- cgit v1.2.3 From c126e1995f79fb487aa99bbead0f23716b43db01 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Tue, 24 Apr 2018 15:18:02 +0200 Subject: mwifiex: fix mwifiex_hard_start_xmit()'s return type The method ndo_start_xmit() is defined as returning an 'netdev_tx_t', which is a typedef for an enum type, but the implementation in this driver returns an 'int'. Fix this by returning 'netdev_tx_t' in this driver too. Signed-off-by: Luc Van Oostenryck Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index b6484582845a..802fb3ecce97 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -858,7 +858,7 @@ mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv, /* * CFG802.11 network device handler for data transmission. */ -static int +static netdev_tx_t mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); -- cgit v1.2.3 From 307857db47ebdcd56ecf26ff084cf9b966a67e17 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Wed, 25 Apr 2018 17:38:12 +0800 Subject: mwifiex: make firmware mac address consistent with host configuration For user configurated mac address, directly set to firmware with no change. Signed-off-by: Xinming Hu Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 4 +-- drivers/net/wireless/marvell/mwifiex/main.c | 38 ++++++++++++++----------- drivers/net/wireless/marvell/mwifiex/main.h | 3 +- 3 files changed, 26 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 4857b75e54a7..54a2297010d2 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -929,7 +929,7 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv, adapter->rx_locked = false; spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); - mwifiex_set_mac_address(priv, dev); + mwifiex_set_mac_address(priv, dev, false, NULL); return 0; } @@ -2979,7 +2979,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, priv->netdev = dev; if (!adapter->mfg_mode) { - mwifiex_set_mac_address(priv, dev); + mwifiex_set_mac_address(priv, dev, false, NULL); ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, HostCmd_ACT_GEN_SET, 0, NULL, true); diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 802fb3ecce97..99eaff97315c 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -940,28 +940,35 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } int mwifiex_set_mac_address(struct mwifiex_private *priv, - struct net_device *dev) + struct net_device *dev, bool external, + u8 *new_mac) { int ret; u64 mac_addr, old_mac_addr; - if (priv->bss_type == MWIFIEX_BSS_TYPE_ANY) - return -ENOTSUPP; + old_mac_addr = ether_addr_to_u64(priv->curr_addr); - mac_addr = ether_addr_to_u64(priv->curr_addr); - old_mac_addr = mac_addr; + if (external) { + mac_addr = ether_addr_to_u64(new_mac); + } else { + /* Internal mac address change */ + if (priv->bss_type == MWIFIEX_BSS_TYPE_ANY) + return -ENOTSUPP; - if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P) - mac_addr |= BIT_ULL(MWIFIEX_MAC_LOCAL_ADMIN_BIT); + mac_addr = old_mac_addr; - if (mwifiex_get_intf_num(priv->adapter, priv->bss_type) > 1) { - /* Set mac address based on bss_type/bss_num */ - mac_addr ^= BIT_ULL(priv->bss_type + 8); - mac_addr += priv->bss_num; - } + if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P) + mac_addr |= BIT_ULL(MWIFIEX_MAC_LOCAL_ADMIN_BIT); - if (mac_addr == old_mac_addr) - goto done; + if (mwifiex_get_intf_num(priv->adapter, priv->bss_type) > 1) { + /* Set mac address based on bss_type/bss_num */ + mac_addr ^= BIT_ULL(priv->bss_type + 8); + mac_addr += priv->bss_num; + } + + if (mac_addr == old_mac_addr) + goto done; + } u64_to_ether_addr(mac_addr, priv->curr_addr); @@ -989,8 +996,7 @@ mwifiex_ndo_set_mac_address(struct net_device *dev, void *addr) struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct sockaddr *hw_addr = addr; - memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN); - return mwifiex_set_mac_address(priv, dev); + return mwifiex_set_mac_address(priv, dev, true, hw_addr->sa_data); } /* diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 9bde181700dc..7c95c1279548 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -1709,7 +1709,8 @@ void mwifiex_process_multi_chan_event(struct mwifiex_private *priv, struct sk_buff *event_skb); void mwifiex_multi_chan_resync(struct mwifiex_adapter *adapter); int mwifiex_set_mac_address(struct mwifiex_private *priv, - struct net_device *dev); + struct net_device *dev, + bool external, u8 *new_mac); void mwifiex_devdump_tmo_func(unsigned long function_context); #ifdef CONFIG_DEBUG_FS -- cgit v1.2.3 From c3b2a34b82db21bf46e00fbfa1b3c3ccaa0ec18f Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Wed, 25 Apr 2018 17:38:13 +0800 Subject: mwifiex: always configure firmware mac address during changing virtual interface When interface type changed, firmware using a new connction pointer. We need Re-configure the mac address. Signed-off-by: Xinming Hu Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/main.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 99eaff97315c..40c80e38a74b 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -965,9 +965,6 @@ int mwifiex_set_mac_address(struct mwifiex_private *priv, mac_addr ^= BIT_ULL(priv->bss_type + 8); mac_addr += priv->bss_num; } - - if (mac_addr == old_mac_addr) - goto done; } u64_to_ether_addr(mac_addr, priv->curr_addr); @@ -983,7 +980,6 @@ int mwifiex_set_mac_address(struct mwifiex_private *priv, return ret; } -done: ether_addr_copy(dev->dev_addr, priv->curr_addr); return 0; } -- cgit v1.2.3 From 7cce13954f0e6b16b4c18a3985387018f2e3e44e Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Wed, 25 Apr 2018 17:38:14 +0800 Subject: mwifiex: keep user configured mac address during changing virtual interface During changing virtual interface, keep using previous net device mac address. Signed-off-by: Xinming Hu Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 40c80e38a74b..510f6b8e717d 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -1333,7 +1333,10 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv, priv->assocresp_idx = MWIFIEX_AUTO_IDX_MASK; priv->gen_idx = MWIFIEX_AUTO_IDX_MASK; priv->num_tx_timeout = 0; - ether_addr_copy(priv->curr_addr, priv->adapter->perm_addr); + if (is_valid_ether_addr(dev->dev_addr)) + ether_addr_copy(priv->curr_addr, dev->dev_addr); + else + ether_addr_copy(priv->curr_addr, priv->adapter->perm_addr); if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { -- cgit v1.2.3 From 6e1d8d1470b2c9335715f7d52e864f0bd91a5f59 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Tue, 10 Apr 2018 21:54:19 +0800 Subject: net: wireless: b43legacy: Replace GFP_ATOMIC with GFP_KERNEL in dma_tx_fragment dma_tx_fragment() is never called in atomic context. dma_tx_fragment() is only called by b43legacy_dma_tx(), which is only called by b43legacy_tx_work(). b43legacy_tx_work() is only set a parameter of INIT_WORK() in b43legacy_wireless_init(). Despite never getting called from atomic context, dma_tx_fragment() calls alloc_skb() with GFP_ATOMIC, which does not sleep for allocation. GFP_ATOMIC is not necessary and can be replaced with GFP_KERNEL, which can sleep and improve the possibility of sucessful allocation. This is found by a static analysis tool named DCNS written by myself. And I also manually check it. Signed-off-by: Jia-Ju Bai Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/b43legacy/dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/b43legacy/dma.c b/drivers/net/wireless/broadcom/b43legacy/dma.c index cfa617ddb2f1..2f0c64cef65f 100644 --- a/drivers/net/wireless/broadcom/b43legacy/dma.c +++ b/drivers/net/wireless/broadcom/b43legacy/dma.c @@ -1064,7 +1064,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); /* create a bounce buffer in zone_dma on mapping failure. */ if (b43legacy_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { - bounce_skb = alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); + bounce_skb = alloc_skb(skb->len, GFP_KERNEL | GFP_DMA); if (!bounce_skb) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; -- cgit v1.2.3 From 3ff6ee28535f2f6698cc2b3acfd2af6942036067 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Tue, 24 Apr 2018 15:18:04 +0200 Subject: qtnfmac: fix qtnf_netdev_hard_start_xmit()'s return type The method ndo_start_xmit() is defined as returning an 'netdev_tx_t', which is a typedef for an enum type, but the implementation in this driver returns an 'int'. Fix this by returning 'netdev_tx_t' in this driver too. Signed-off-by: Luc Van Oostenryck Reviewed-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c index cf26c15a84f8..b3bfb4faa918 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.c +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -76,7 +76,7 @@ static int qtnf_netdev_close(struct net_device *ndev) /* Netdev handler for data transmission. */ -static int +static netdev_tx_t qtnf_netdev_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct qtnf_vif *vif; -- cgit v1.2.3 From 60f36637bbbdeea199d644eda284dba5144d2377 Mon Sep 17 00:00:00 2001 From: Eyal Reizer Date: Thu, 26 Apr 2018 08:47:11 +0300 Subject: wlcore: sdio: allow pm to handle sdio power pm_runtime handles sdio power on and power off transitions. An old workaround for trying to control the power explicitly from the driver was in fact causing failures on suspend/resume as the mmc layer already power the module on resume. In case of resume pm_runtime_get sync returns a positive device's usage count causing the driver to try an re-initialize an already initialized device. This was causing sdio bus failure on resume. Remove this manual power on/off sequence as it is in-fact not needed. Signed-off-by: Eyal Reizer Acked-by: Tony Lindgren Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/sdio.c | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 1f727babbea0..6dbe61d47dc3 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -155,17 +155,11 @@ static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue) struct mmc_card *card = func->card; ret = pm_runtime_get_sync(&card->dev); - if (ret) { - /* - * Runtime PM might be temporarily disabled, or the device - * might have a positive reference counter. Make sure it is - * really powered on. - */ - ret = mmc_power_restore_host(card->host); - if (ret < 0) { - pm_runtime_put_sync(&card->dev); - goto out; - } + if (ret < 0) { + pm_runtime_put_noidle(&card->dev); + dev_err(glue->dev, "%s: failed to get_sync(%d)\n", + __func__, ret); + goto out; } sdio_claim_host(func); @@ -178,7 +172,6 @@ out: static int wl12xx_sdio_power_off(struct wl12xx_sdio_glue *glue) { - int ret; struct sdio_func *func = dev_to_sdio_func(glue->dev); struct mmc_card *card = func->card; @@ -186,16 +179,8 @@ static int wl12xx_sdio_power_off(struct wl12xx_sdio_glue *glue) sdio_disable_func(func); sdio_release_host(func); - /* Power off the card manually in case it wasn't powered off above */ - ret = mmc_power_save_host(card->host); - if (ret < 0) - goto out; - /* Let runtime PM know the card is powered off */ - pm_runtime_put_sync(&card->dev); - -out: - return ret; + return pm_runtime_put_sync(&card->dev); } static int wl12xx_sdio_set_power(struct device *child, bool enable) -- cgit v1.2.3 From e1fd7ceec194225a822760a40dfa73efdd59881b Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 26 Apr 2018 08:01:38 -0500 Subject: rsi_91x: fix structurally dead code Function rsi_hal_key_config returns before reaching code at line 922 if (status), hence this code is structurally dead. Fix this by storing the value returned by rsi_hal_load_key into _status_ for its further evaluation and use. Addresses-Coverity-ID: 1468409 ("Structurally dead code") Fixes: 4fd6c4762f37 ("rsi: roaming enhancements") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 766d874cc6e2..80e7f4f4f188 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -911,14 +911,14 @@ static int rsi_hal_key_config(struct ieee80211_hw *hw, } } - return rsi_hal_load_key(adapter->priv, - key->key, - key->keylen, - key_type, - key->keyidx, - key->cipher, - sta_id, - vif); + status = rsi_hal_load_key(adapter->priv, + key->key, + key->keylen, + key_type, + key->keyidx, + key->cipher, + sta_id, + vif); if (status) return status; -- cgit v1.2.3 From 48c6b5c9c1180b7f8b35edeaef9b3aa3e3b6c9d5 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 26 Apr 2018 08:13:24 -0500 Subject: rsi_91x: fix uninitialized variable There is a potential execution path in which variable ret is returned without being properly initialized previously. Fix this by storing the value returned by function rsi_usb_master_reg_write into _ret_. Addresses-Coverity-ID: 1468407 ("Uninitialized scalar variable") Fixes: 16d3bb7b2f37 ("rsi: disable fw watchdog timer during reset") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_usb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index b065438f51b2..6ce6b754df12 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -687,9 +687,10 @@ static int rsi_reset_card(struct rsi_hw *adapter) */ msleep(100); - if (rsi_usb_master_reg_write(adapter, SWBL_REGOUT, - RSI_FW_WDT_DISABLE_REQ, - RSI_COMMON_REG_SIZE) < 0) { + ret = rsi_usb_master_reg_write(adapter, SWBL_REGOUT, + RSI_FW_WDT_DISABLE_REQ, + RSI_COMMON_REG_SIZE); + if (ret < 0) { rsi_dbg(ERR_ZONE, "Disabling firmware watchdog timer failed\n"); goto fail; } -- cgit v1.2.3 From cc282a0c5f0823bfcf084103445c69894129227c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 18 Apr 2018 12:47:50 +0100 Subject: rt2x00: fix spelling mistake in various macros, UKNOWN -> UNKNOWN Rename several macros that contain mispellings of UNKNOWN Signed-off-by: Colin Ian King Acked-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2800.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800.h b/drivers/net/wireless/ralink/rt2x00/rt2800.h index 7a133e94b1bf..b05ed2f3025a 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h @@ -1194,10 +1194,10 @@ #define TX_PWR_CFG_3_MCS13 FIELD32(0x000000f0) #define TX_PWR_CFG_3_MCS14 FIELD32(0x00000f00) #define TX_PWR_CFG_3_MCS15 FIELD32(0x0000f000) -#define TX_PWR_CFG_3_UKNOWN1 FIELD32(0x000f0000) -#define TX_PWR_CFG_3_UKNOWN2 FIELD32(0x00f00000) -#define TX_PWR_CFG_3_UKNOWN3 FIELD32(0x0f000000) -#define TX_PWR_CFG_3_UKNOWN4 FIELD32(0xf0000000) +#define TX_PWR_CFG_3_UNKNOWN1 FIELD32(0x000f0000) +#define TX_PWR_CFG_3_UNKNOWN2 FIELD32(0x00f00000) +#define TX_PWR_CFG_3_UNKNOWN3 FIELD32(0x0f000000) +#define TX_PWR_CFG_3_UNKNOWN4 FIELD32(0xf0000000) /* bits for 3T devices */ #define TX_PWR_CFG_3_MCS12_CH0 FIELD32(0x0000000f) #define TX_PWR_CFG_3_MCS12_CH1 FIELD32(0x000000f0) @@ -1217,10 +1217,10 @@ * TX_PWR_CFG_4: */ #define TX_PWR_CFG_4 0x1324 -#define TX_PWR_CFG_4_UKNOWN5 FIELD32(0x0000000f) -#define TX_PWR_CFG_4_UKNOWN6 FIELD32(0x000000f0) -#define TX_PWR_CFG_4_UKNOWN7 FIELD32(0x00000f00) -#define TX_PWR_CFG_4_UKNOWN8 FIELD32(0x0000f000) +#define TX_PWR_CFG_4_UNKNOWN5 FIELD32(0x0000000f) +#define TX_PWR_CFG_4_UNKNOWN6 FIELD32(0x000000f0) +#define TX_PWR_CFG_4_UNKNOWN7 FIELD32(0x00000f00) +#define TX_PWR_CFG_4_UNKNOWN8 FIELD32(0x0000f000) /* bits for 3T devices */ #define TX_PWR_CFG_4_STBC4_CH0 FIELD32(0x0000000f) #define TX_PWR_CFG_4_STBC4_CH1 FIELD32(0x000000f0) -- cgit v1.2.3 From 3ea0a58cf9cf66e53f52184446fd881f828709e4 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 28 Apr 2018 23:31:08 +0100 Subject: ipw2100: fix spelling mistake: "decsribed" -> "described" Trivial fix to spelling mistake in comment and in the ord_data text Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/ipw2x00/ipw2100.c | 2 +- drivers/net/wireless/intel/ipw2x00/ipw2100.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index 236b52423506..7c4f550a1475 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -3732,7 +3732,7 @@ IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"), IPW2100_ORD(ASSOCIATED_AP_PTR, "0 if not associated, else pointer to AP table entry"), IPW2100_ORD(AVAILABLE_AP_CNT, - "AP's decsribed in the AP table"), + "AP's described in the AP table"), IPW2100_ORD(AP_LIST_PTR, "Ptr to list of available APs"), IPW2100_ORD(STAT_AP_ASSNS, "associations"), IPW2100_ORD(STAT_ASSN_FAIL, "association failures"), diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.h b/drivers/net/wireless/intel/ipw2x00/ipw2100.h index 193947865efd..ce3e35f6b60f 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.h +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.h @@ -1009,7 +1009,7 @@ typedef enum _ORDINAL_TABLE_1 { // NS - means Not Supported by FW IPW_ORD_STAT_PERCENT_RETRIES, // current calculation of % missed tx retries IPW_ORD_ASSOCIATED_AP_PTR, // If associated, this is ptr to the associated // AP table entry. set to 0 if not associated - IPW_ORD_AVAILABLE_AP_CNT, // # of AP's decsribed in the AP table + IPW_ORD_AVAILABLE_AP_CNT, // # of AP's described in the AP table IPW_ORD_AP_LIST_PTR, // Ptr to list of available APs IPW_ORD_STAT_AP_ASSNS, // # of associations IPW_ORD_STAT_ASSN_FAIL, // # of association failures -- cgit v1.2.3 From cb746e47837ad0f35c8ae28e9aacc8eb07916d2a Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Thu, 26 Apr 2018 12:16:47 +0200 Subject: brcmfmac: check p2pdev mac address uniqueness The mac address for p2pdev must be different from the primary interface due to firmware requirement. Add an explicit check for this requirement if user-space provides a mac address. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index bcef208a81a5..4b2149b48362 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -2073,6 +2073,13 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p, } pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; + + /* firmware requires unique mac address for p2pdev interface */ + if (addr && ether_addr_equal(addr, pri_ifp->mac_addr)) { + brcmf_err("discovery vif must be different from primary interface\n"); + return ERR_PTR(-EINVAL); + } + brcmf_p2p_generate_bss_mac(p2p, addr); brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr); -- cgit v1.2.3 From 7742fce4c007141617dab9bcb90034b3c0fe2347 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Thu, 26 Apr 2018 12:18:35 +0200 Subject: brcmfmac: reports boottime_ns while informing bss Provides a timestamp in bss information so user space can see when the bss info was updated. Since tsf is not available from the dongle events boottime is reported instead. Reported-by: Dmitry Shmidt Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 89b86251910e..5d891cb4d625 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -2728,7 +2728,6 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, struct brcmf_bss_info_le *bi) { struct wiphy *wiphy = cfg_to_wiphy(cfg); - struct ieee80211_channel *notify_channel; struct cfg80211_bss *bss; struct ieee80211_supported_band *band; struct brcmu_chan ch; @@ -2738,7 +2737,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, u16 notify_interval; u8 *notify_ie; size_t notify_ielen; - s32 notify_signal; + struct cfg80211_inform_bss bss_data = { 0 }; if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) { brcmf_err("Bss info is larger than buffer. Discarding\n"); @@ -2758,27 +2757,28 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, band = wiphy->bands[NL80211_BAND_5GHZ]; freq = ieee80211_channel_to_frequency(channel, band->band); - notify_channel = ieee80211_get_channel(wiphy, freq); + bss_data.chan = ieee80211_get_channel(wiphy, freq); + bss_data.scan_width = NL80211_BSS_CHAN_WIDTH_20; + bss_data.boottime_ns = ktime_to_ns(ktime_get_boottime()); notify_capability = le16_to_cpu(bi->capability); notify_interval = le16_to_cpu(bi->beacon_period); notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset); notify_ielen = le32_to_cpu(bi->ie_length); - notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100; + bss_data.signal = (s16)le16_to_cpu(bi->RSSI) * 100; brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID); brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq); brcmf_dbg(CONN, "Capability: %X\n", notify_capability); brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval); - brcmf_dbg(CONN, "Signal: %d\n", notify_signal); - - bss = cfg80211_inform_bss(wiphy, notify_channel, - CFG80211_BSS_FTYPE_UNKNOWN, - (const u8 *)bi->BSSID, - 0, notify_capability, - notify_interval, notify_ie, - notify_ielen, notify_signal, - GFP_KERNEL); + brcmf_dbg(CONN, "Signal: %d\n", bss_data.signal); + + bss = cfg80211_inform_bss_data(wiphy, &bss_data, + CFG80211_BSS_FTYPE_UNKNOWN, + (const u8 *)bi->BSSID, + 0, notify_capability, + notify_interval, notify_ie, + notify_ielen, GFP_KERNEL); if (!bss) return -ENOMEM; -- cgit v1.2.3 From aed14219067ab96e5eeb7730e9bceed10d9be989 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Thu, 26 Apr 2018 12:16:48 +0200 Subject: brcmfmac: use nl80211_band directly to get ieee80211 channel The enum nl80211_band used to retrieve wiphy->bands is the same as wiphy->bands->band which is checked by wiphy_register(). So it can be used directly as parameter of ieee80211_channel_to_frequency(). Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 5d891cb4d625..ff6b3514c501 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -2729,7 +2729,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, { struct wiphy *wiphy = cfg_to_wiphy(cfg); struct cfg80211_bss *bss; - struct ieee80211_supported_band *band; + enum nl80211_band band; struct brcmu_chan ch; u16 channel; u32 freq; @@ -2752,11 +2752,11 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, channel = bi->ctl_ch; if (channel <= CH_MAX_2G_CHANNEL) - band = wiphy->bands[NL80211_BAND_2GHZ]; + band = NL80211_BAND_2GHZ; else - band = wiphy->bands[NL80211_BAND_5GHZ]; + band = NL80211_BAND_5GHZ; - freq = ieee80211_channel_to_frequency(channel, band->band); + freq = ieee80211_channel_to_frequency(channel, band); bss_data.chan = ieee80211_get_channel(wiphy, freq); bss_data.scan_width = NL80211_BSS_CHAN_WIDTH_20; bss_data.boottime_ns = ktime_to_ns(ktime_get_boottime()); -- cgit v1.2.3 From ff68c9f9c06d1fd437c8f90fc05ca28c47f7d85e Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Thu, 26 Apr 2018 12:16:49 +0200 Subject: brcmfmac: constify firmware mapping tables The information in the firmware mapping does not need to be modified so it can be static const. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | 2 +- drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h | 2 +- drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 2 +- drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 2 +- drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c index 94e177d7c9b5..9095b830ae4d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c @@ -634,7 +634,7 @@ int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req, struct brcmf_fw_request * brcmf_fw_alloc_request(u32 chip, u32 chiprev, - struct brcmf_firmware_mapping mapping_table[], + const struct brcmf_firmware_mapping mapping_table[], u32 table_size, struct brcmf_fw_name *fwnames, u32 n_fwnames) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h index 79a21095c349..2893e56910f0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h @@ -80,7 +80,7 @@ struct brcmf_fw_name { struct brcmf_fw_request * brcmf_fw_alloc_request(u32 chip, u32 chiprev, - struct brcmf_firmware_mapping mapping_table[], + const struct brcmf_firmware_mapping mapping_table[], u32 table_size, struct brcmf_fw_name *fwnames, u32 n_fwnames); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 6e25ff94dd07..9708647b99e7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -59,7 +59,7 @@ BRCMF_FW_DEF(4366B, "brcmfmac4366b-pcie"); BRCMF_FW_DEF(4366C, "brcmfmac4366c-pcie"); BRCMF_FW_DEF(4371, "brcmfmac4371-pcie"); -static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { +static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602), BRCMF_FW_ENTRY(BRCM_CC_43465_CHIP_ID, 0xFFFFFFF0, 4366C), BRCMF_FW_ENTRY(BRCM_CC_4350_CHIP_ID, 0x000000FF, 4350C), diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 1037df7297bb..412a05b9a2b2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -619,7 +619,7 @@ BRCMF_FW_DEF(4354, "brcmfmac4354-sdio"); BRCMF_FW_DEF(4356, "brcmfmac4356-sdio"); BRCMF_FW_DEF(4373, "brcmfmac4373-sdio"); -static struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { +static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143), BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x0000001F, 43241B0), BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x00000020, 43241B4), diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index a0873adcc01c..a4308c6e72d7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -52,7 +52,7 @@ BRCMF_FW_DEF(43242A, "brcmfmac43242a"); BRCMF_FW_DEF(43569, "brcmfmac43569"); BRCMF_FW_DEF(4373, "brcmfmac4373"); -static struct brcmf_firmware_mapping brcmf_usb_fwnames[] = { +static const struct brcmf_firmware_mapping brcmf_usb_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143), BRCMF_FW_ENTRY(BRCM_CC_43235_CHIP_ID, 0x00000008, 43236B), BRCMF_FW_ENTRY(BRCM_CC_43236_CHIP_ID, 0x00000008, 43236B), -- cgit v1.2.3 From 84ad327d18debe19b8d509059b61db445d048b02 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Thu, 26 Apr 2018 12:16:50 +0200 Subject: brcmfmac: add hostready indication A hostready signal is introduced to inform firmware through mailbox doorbell1 when common ring initialized or D3 exited. Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 9708647b99e7..71b69af9294c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -105,7 +105,8 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { #define BRCMF_PCIE_PCIE2REG_MAILBOXMASK 0x4C #define BRCMF_PCIE_PCIE2REG_CONFIGADDR 0x120 #define BRCMF_PCIE_PCIE2REG_CONFIGDATA 0x124 -#define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX 0x140 +#define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_0 0x140 +#define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_1 0x144 #define BRCMF_PCIE2_INTA 0x01 #define BRCMF_PCIE2_INTB 0x02 @@ -140,6 +141,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { #define BRCMF_PCIE_SHARED_VERSION_MASK 0x00FF #define BRCMF_PCIE_SHARED_DMA_INDEX 0x10000 #define BRCMF_PCIE_SHARED_DMA_2B_IDX 0x100000 +#define BRCMF_PCIE_SHARED_HOSTRDY_DB1 0x10000000 #define BRCMF_PCIE_FLAGS_HTOD_SPLIT 0x4000 #define BRCMF_PCIE_FLAGS_DTOH_SPLIT 0x8000 @@ -782,6 +784,12 @@ static void brcmf_pcie_intr_enable(struct brcmf_pciedev_info *devinfo) BRCMF_PCIE_MB_INT_FN0_1); } +static void brcmf_pcie_hostready(struct brcmf_pciedev_info *devinfo) +{ + if (devinfo->shared.flags & BRCMF_PCIE_SHARED_HOSTRDY_DB1) + brcmf_pcie_write_reg32(devinfo, + BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_1, 1); +} static irqreturn_t brcmf_pcie_quick_check_isr(int irq, void *arg) { @@ -924,7 +932,7 @@ static int brcmf_pcie_ring_mb_ring_bell(void *ctx) brcmf_dbg(PCIE, "RING !\n"); /* Any arbitrary value will do, lets use 1 */ - brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_H2D_MAILBOX, 1); + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_0, 1); return 0; } @@ -1728,6 +1736,7 @@ static void brcmf_pcie_setup(struct device *dev, int ret, init_waitqueue_head(&devinfo->mbdata_resp_wait); brcmf_pcie_intr_enable(devinfo); + brcmf_pcie_hostready(devinfo); if (brcmf_attach(&devinfo->pdev->dev, devinfo->settings) == 0) return; @@ -1950,6 +1959,7 @@ static int brcmf_pcie_pm_leave_D3(struct device *dev) brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); brcmf_bus_change_state(bus, BRCMF_BUS_UP); brcmf_pcie_intr_enable(devinfo); + brcmf_pcie_hostready(devinfo); return 0; } -- cgit v1.2.3 From f56324baf329bc9362a52ad77a4a1a0f3356d1bc Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Thu, 26 Apr 2018 12:16:51 +0200 Subject: brcmfmac: coarse support for PCIe shared structure rev7 Revision 7 of PCIe dongle interface increases the item size of tx and rx complete rings to accommodate extra payload for new feature. This patch simply bump up the size of these two rings without adding the support for utilizing the new space. This makes brcmfmac compatible with rev7 firmware. Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../wireless/broadcom/brcm80211/brcmfmac/msgbuf.h | 6 ++++-- .../wireless/broadcom/brcm80211/brcmfmac/pcie.c | 23 ++++++++++++++++++---- 2 files changed, 23 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h index f93ba6be1ef8..692235d25277 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h @@ -27,8 +27,10 @@ #define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_ITEMSIZE 40 #define BRCMF_H2D_MSGRING_RXPOST_SUBMIT_ITEMSIZE 32 #define BRCMF_D2H_MSGRING_CONTROL_COMPLETE_ITEMSIZE 24 -#define BRCMF_D2H_MSGRING_TX_COMPLETE_ITEMSIZE 16 -#define BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE 32 +#define BRCMF_D2H_MSGRING_TX_COMPLETE_ITEMSIZE_PRE_V7 16 +#define BRCMF_D2H_MSGRING_TX_COMPLETE_ITEMSIZE 24 +#define BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE_PRE_V7 32 +#define BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE 40 #define BRCMF_H2D_TXFLOWRING_ITEMSIZE 48 struct msgbuf_buf_addr { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 71b69af9294c..f0797aeada67 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -136,8 +136,9 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { BRCMF_PCIE_MB_INT_D2H3_DB0 | \ BRCMF_PCIE_MB_INT_D2H3_DB1) +#define BRCMF_PCIE_SHARED_VERSION_7 7 #define BRCMF_PCIE_MIN_SHARED_VERSION 5 -#define BRCMF_PCIE_MAX_SHARED_VERSION 6 +#define BRCMF_PCIE_MAX_SHARED_VERSION BRCMF_PCIE_SHARED_VERSION_7 #define BRCMF_PCIE_SHARED_VERSION_MASK 0x00FF #define BRCMF_PCIE_SHARED_DMA_INDEX 0x10000 #define BRCMF_PCIE_SHARED_DMA_2B_IDX 0x100000 @@ -318,6 +319,14 @@ static const u32 brcmf_ring_max_item[BRCMF_NROF_COMMON_MSGRINGS] = { BRCMF_D2H_MSGRING_RX_COMPLETE_MAX_ITEM }; +static const u32 brcmf_ring_itemsize_pre_v7[BRCMF_NROF_COMMON_MSGRINGS] = { + BRCMF_H2D_MSGRING_CONTROL_SUBMIT_ITEMSIZE, + BRCMF_H2D_MSGRING_RXPOST_SUBMIT_ITEMSIZE, + BRCMF_D2H_MSGRING_CONTROL_COMPLETE_ITEMSIZE, + BRCMF_D2H_MSGRING_TX_COMPLETE_ITEMSIZE_PRE_V7, + BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE_PRE_V7 +}; + static const u32 brcmf_ring_itemsize[BRCMF_NROF_COMMON_MSGRINGS] = { BRCMF_H2D_MSGRING_CONTROL_SUBMIT_ITEMSIZE, BRCMF_H2D_MSGRING_RXPOST_SUBMIT_ITEMSIZE, @@ -1007,8 +1016,14 @@ brcmf_pcie_alloc_dma_and_ring(struct brcmf_pciedev_info *devinfo, u32 ring_id, struct brcmf_pcie_ringbuf *ring; u32 size; u32 addr; + const u32 *ring_itemsize_array; + + if (devinfo->shared.version < BRCMF_PCIE_SHARED_VERSION_7) + ring_itemsize_array = brcmf_ring_itemsize_pre_v7; + else + ring_itemsize_array = brcmf_ring_itemsize; - size = brcmf_ring_max_item[ring_id] * brcmf_ring_itemsize[ring_id]; + size = brcmf_ring_max_item[ring_id] * ring_itemsize_array[ring_id]; dma_buf = brcmf_pcie_init_dmabuffer_for_device(devinfo, size, tcm_ring_phys_addr + BRCMF_RING_MEM_BASE_ADDR_OFFSET, &dma_handle); @@ -1018,7 +1033,7 @@ brcmf_pcie_alloc_dma_and_ring(struct brcmf_pciedev_info *devinfo, u32 ring_id, addr = tcm_ring_phys_addr + BRCMF_RING_MAX_ITEM_OFFSET; brcmf_pcie_write_tcm16(devinfo, addr, brcmf_ring_max_item[ring_id]); addr = tcm_ring_phys_addr + BRCMF_RING_LEN_ITEMS_OFFSET; - brcmf_pcie_write_tcm16(devinfo, addr, brcmf_ring_itemsize[ring_id]); + brcmf_pcie_write_tcm16(devinfo, addr, ring_itemsize_array[ring_id]); ring = kzalloc(sizeof(*ring), GFP_KERNEL); if (!ring) { @@ -1027,7 +1042,7 @@ brcmf_pcie_alloc_dma_and_ring(struct brcmf_pciedev_info *devinfo, u32 ring_id, return NULL; } brcmf_commonring_config(&ring->commonring, brcmf_ring_max_item[ring_id], - brcmf_ring_itemsize[ring_id], dma_buf); + ring_itemsize_array[ring_id], dma_buf); ring->dma_handle = dma_handle; ring->devinfo = devinfo; brcmf_commonring_register_cb(&ring->commonring, -- cgit v1.2.3 From 9c87758cf0893d6d3b51aac34546807b138cb3e7 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 30 Apr 2018 15:19:16 +0200 Subject: rt2x00: call sta_add/remove directly in rt2800 Only rt2800 subdriver of rt2x00 implement sta_add() and sta_remove(), we do not need generic version of those. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 11 +++++++---- drivers/net/wireless/ralink/rt2x00/rt2800lib.h | 5 +++-- drivers/net/wireless/ralink/rt2x00/rt2800pci.c | 6 ++---- drivers/net/wireless/ralink/rt2x00/rt2800soc.c | 6 ++---- drivers/net/wireless/ralink/rt2x00/rt2800usb.c | 6 ++---- drivers/net/wireless/ralink/rt2x00/rt2x00.h | 4 ---- 6 files changed, 16 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index e827dc522580..a567bc273ffc 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -1557,12 +1557,13 @@ static void rt2800_set_max_psdu_len(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, MAX_LEN_CFG, reg); } -int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif, +int rt2800_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - int wcid; - struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta); + struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; + struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta); + int wcid; /* * Limit global maximum TX AMPDU length to smallest value of all @@ -1608,8 +1609,10 @@ int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(rt2800_sta_add); -int rt2800_sta_remove(struct rt2x00_dev *rt2x00dev, struct ieee80211_sta *sta) +int rt2800_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) { + struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2800_drv_data *drv_data = rt2x00dev->drv_data; struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta); int wcid = sta_priv->wcid; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h index 275e3969abdd..51d9c2a932cc 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h @@ -208,9 +208,10 @@ int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev, int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_crypto *crypto, struct ieee80211_key_conf *key); -int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif, +int rt2800_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); -int rt2800_sta_remove(struct rt2x00_dev *rt2x00dev, struct ieee80211_sta *sta); +int rt2800_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); void rt2800_config_filter(struct rt2x00_dev *rt2x00dev, const unsigned int filter_flags); void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c index 1172eefd1c1a..71b1affc3885 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c @@ -311,8 +311,8 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = { .get_stats = rt2x00mac_get_stats, .get_key_seq = rt2800_get_key_seq, .set_rts_threshold = rt2800_set_rts_threshold, - .sta_add = rt2x00mac_sta_add, - .sta_remove = rt2x00mac_sta_remove, + .sta_add = rt2800_sta_add, + .sta_remove = rt2800_sta_remove, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2800_conf_tx, .get_tsf = rt2800_get_tsf, @@ -377,8 +377,6 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { .config_erp = rt2800_config_erp, .config_ant = rt2800_config_ant, .config = rt2800_config, - .sta_add = rt2800_sta_add, - .sta_remove = rt2800_sta_remove, }; static const struct rt2x00_ops rt2800pci_ops = { diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c index 6848ebc83534..a502816214ab 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c @@ -150,8 +150,8 @@ static const struct ieee80211_ops rt2800soc_mac80211_ops = { .get_stats = rt2x00mac_get_stats, .get_key_seq = rt2800_get_key_seq, .set_rts_threshold = rt2800_set_rts_threshold, - .sta_add = rt2x00mac_sta_add, - .sta_remove = rt2x00mac_sta_remove, + .sta_add = rt2800_sta_add, + .sta_remove = rt2800_sta_remove, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2800_conf_tx, .get_tsf = rt2800_get_tsf, @@ -216,8 +216,6 @@ static const struct rt2x00lib_ops rt2800soc_rt2x00_ops = { .config_erp = rt2800_config_erp, .config_ant = rt2800_config_ant, .config = rt2800_config, - .sta_add = rt2800_sta_add, - .sta_remove = rt2800_sta_remove, }; static const struct rt2x00_ops rt2800soc_ops = { diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c index d901a41d36e4..98a7313fea4a 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c @@ -797,8 +797,8 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = { .get_stats = rt2x00mac_get_stats, .get_key_seq = rt2800_get_key_seq, .set_rts_threshold = rt2800_set_rts_threshold, - .sta_add = rt2x00mac_sta_add, - .sta_remove = rt2x00mac_sta_remove, + .sta_add = rt2800_sta_add, + .sta_remove = rt2800_sta_remove, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2800_conf_tx, .get_tsf = rt2800_get_tsf, @@ -858,8 +858,6 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { .config_erp = rt2800_config_erp, .config_ant = rt2800_config_ant, .config = rt2800_config, - .sta_add = rt2800_sta_add, - .sta_remove = rt2800_sta_remove, }; static void rt2800usb_queue_init(struct data_queue *queue) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index 1f38c338ca7a..a279a4363bc1 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -1457,10 +1457,6 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, #else #define rt2x00mac_set_key NULL #endif /* CONFIG_RT2X00_LIB_CRYPTO */ -int rt2x00mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -int rt2x00mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *mac_addr); -- cgit v1.2.3 From 811a3991510735566b66069fdd4ce3ce33a2ec18 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 30 Apr 2018 15:19:17 +0200 Subject: rt2x00: check against flushing empty queue We have check if queue is not empty when start flushing queues on by mac80211 callback, but we also can start flushing queues by internal driver calls. So move check into rt2x00queue_flush_queue() to assure we do not flush empty queue anytime. Additionally add warning if we start to kick empty queue as in such situation we set wrong index in the HW queue, what can confuse the HW and have various negative consequences. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2800mmio.c | 1 + drivers/net/wireless/ralink/rt2x00/rt2x00mac.c | 3 +-- drivers/net/wireless/ralink/rt2x00/rt2x00queue.c | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c index 1123e2bed803..e1a7ed7e4892 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c @@ -600,6 +600,7 @@ void rt2800mmio_kick_queue(struct data_queue *queue) case QID_AC_VI: case QID_AC_BE: case QID_AC_BK: + WARN_ON_ONCE(rt2x00queue_empty(queue)); entry = rt2x00queue_get_entry(queue, Q_INDEX); rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX(queue->qid), entry->entry_idx); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c index a971bc7a6b63..c380c1f56ba6 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c @@ -739,8 +739,7 @@ void rt2x00mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return; tx_queue_for_each(rt2x00dev, queue) - if (!rt2x00queue_empty(queue)) - rt2x00queue_flush_queue(queue, drop); + rt2x00queue_flush_queue(queue, drop); } EXPORT_SYMBOL_GPL(rt2x00mac_flush); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c index a6884e73d2ab..7c1f8f561d4a 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c @@ -1000,6 +1000,8 @@ void rt2x00queue_flush_queue(struct data_queue *queue, bool drop) (queue->qid == QID_AC_BE) || (queue->qid == QID_AC_BK); + if (rt2x00queue_empty(queue)) + return; /* * If we are not supposed to drop any pending -- cgit v1.2.3 From 070fc356e21addb579edcd7a1f2ef692b29a78e5 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 30 Apr 2018 14:41:02 +0100 Subject: rtlwifi: fix spelling mistake: "dismatch" -> "mismatch" Trivial fix to spelling mistake in RT_TRACE message text. Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c | 2 +- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c | 2 +- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c index 8fce371749d3..f22fec093f1d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c @@ -1783,7 +1783,7 @@ static void btc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, bool scan = false, link = false, roam = false; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], PsTdma type dismatch!!!, "); + "[BTCoex], PsTdma type mismatch!!!, "); RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "curPsTdma=%d, recordPsTdma=%d\n", coex_dm->cur_ps_tdma, coex_dm->tdma_adj_type); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 73ec31972944..279fe01bb55e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -2766,7 +2766,7 @@ static void btc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, if (coex_dm->cur_ps_tdma != coex_dm->ps_tdma_du_adj_type) { bool scan = false, link = false, roam = false; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], PsTdma type dismatch!!!, curPsTdma=%d, recordPsTdma=%d\n", + "[BTCoex], PsTdma type mismatch!!!, curPsTdma=%d, recordPsTdma=%d\n", coex_dm->cur_ps_tdma, coex_dm->ps_tdma_du_adj_type); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 2202d5e18977..01a9d303603b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -2614,7 +2614,7 @@ static void btc8821a2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, bool scan = false, link = false, roam = false; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], PsTdma type dismatch!!!, cur_ps_tdma = %d, recordPsTdma = %d\n", + "[BTCoex], PsTdma type mismatch!!!, cur_ps_tdma = %d, recordPsTdma = %d\n", coex_dm->cur_ps_tdma, coex_dm->ps_tdma_du_adj_type); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); -- cgit v1.2.3 From 8efb868566db107d6d0130ea61a653a29f851661 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 1 May 2018 10:33:54 +0200 Subject: mt76x2: remove unnecessary break in mt76x2_mac_process_tx_rate() Remove unnecessary break statement in the default case of bw switch block in mt76x2_mac_process_tx_rate routine Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x2_mac.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c index d18315652583..dab713756004 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c @@ -410,7 +410,6 @@ mt76x2_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate, break; default: return -EINVAL; - break; } if (rate & MT_RXWI_RATE_SGI) -- cgit v1.2.3 From 7e7939e80e3cda3e5677c3905d20c066bfb22ef2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 1 May 2018 10:36:43 +0100 Subject: ipw2200: fix spelling mistake: "functionalitis" -> "functionalities" Trivial fix to spelling mistake in module parameter description text Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/ipw2x00/ipw2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index 87a5e414c2f7..ba3fb1d2ddb4 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -12012,7 +12012,7 @@ MODULE_PARM_DESC(rtap_iface, "create the rtap interface (1 - create, default 0)" #ifdef CONFIG_IPW2200_QOS module_param(qos_enable, int, 0444); -MODULE_PARM_DESC(qos_enable, "enable all QoS functionalitis"); +MODULE_PARM_DESC(qos_enable, "enable all QoS functionalities"); module_param(qos_burst_enable, int, 0444); MODULE_PARM_DESC(qos_burst_enable, "enable QoS burst mode"); -- cgit v1.2.3 From c990affd5abce1f338ac52539e092dad04647fb6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 2 May 2018 11:46:36 +0200 Subject: mt76x2: fix avg_rssi estimation Add leftover filter coefficients in IIR rssi estimation Fixes: 7bc04215a66b ("mt76: add driver code for MT76x2e") Signed-off-by: Lorenzo Bianconi Acked-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x2_phy.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c index 038d1fe6c726..c1c38ca3330a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_phy.c @@ -508,8 +508,10 @@ mt76x2_phy_update_channel_gain(struct mt76x2_dev *dev) u8 gain_delta; int low_gain; - dev->cal.avg_rssi[0] = (dev->cal.avg_rssi[0] * 15) / 16 + (rssi0 << 8); - dev->cal.avg_rssi[1] = (dev->cal.avg_rssi[1] * 15) / 16 + (rssi1 << 8); + dev->cal.avg_rssi[0] = (dev->cal.avg_rssi[0] * 15) / 16 + + (rssi0 << 8) / 16; + dev->cal.avg_rssi[1] = (dev->cal.avg_rssi[1] * 15) / 16 + + (rssi1 << 8) / 16; dev->cal.avg_rssi_all = (dev->cal.avg_rssi[0] + dev->cal.avg_rssi[1]) / 512; -- cgit v1.2.3 From bf516e7d8b1c1ff7706d56961306fa7e19f352b6 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 4 May 2018 10:42:04 +0800 Subject: rtlwifi: remove duplicate definition of antenna number for btcoex Two enumerations bt_total_ant_num and bt_ant_num are identical, so one can be removed. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c | 4 ++-- drivers/net/wireless/realtek/rtlwifi/wifi.h | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c index fd7928fdbd1a..3f2295fdb02d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c @@ -2574,11 +2574,11 @@ void rtl92ee_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, rtlpriv->btcoexist.btc_info.btcoexist = 0; rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8192E; - rtlpriv->btcoexist.btc_info.ant_num = ANT_TOTAL_X2; + rtlpriv->btcoexist.btc_info.ant_num = ANT_X2; } else { rtlpriv->btcoexist.btc_info.btcoexist = 1; rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8192E; - rtlpriv->btcoexist.btc_info.ant_num = ANT_TOTAL_X1; + rtlpriv->btcoexist.btc_info.ant_num = ANT_X1; } } diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index ce1754054a07..208010fcde21 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2842,11 +2842,6 @@ enum bt_co_type { BT_RTL8812A = 11, }; -enum bt_total_ant_num { - ANT_TOTAL_X2 = 0, - ANT_TOTAL_X1 = 1 -}; - enum bt_cur_state { BT_OFF = 0, BT_ON = 1, -- cgit v1.2.3 From 9c4a121e82634aa000a702c98cd6f05b27d6e186 Mon Sep 17 00:00:00 2001 From: Sean Lanigan Date: Fri, 4 May 2018 16:48:23 +1000 Subject: brcmfmac: Add support for bcm43364 wireless chipset Add support for the BCM43364 chipset via an SDIO interface, as used in e.g. the Murata 1FX module. The BCM43364 uses the same firmware as the BCM43430 (which is already included), the only difference is the omission of Bluetooth. However, the SDIO_ID for the BCM43364 is 02D0:A9A4, giving it a MODALIAS of sdio:c00v02D0dA9A4, which doesn't get recognised and hence doesn't load the brcmfmac module. Adding the 'A9A4' ID in the appropriate place triggers the brcmfmac driver to load, and then correctly use the firmware file 'brcmfmac43430-sdio.bin'. Signed-off-by: Sean Lanigan Acked-by: Ulf Hansson Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index 0b68240ec7b4..a1915411c280 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -963,6 +963,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43340), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43364), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4339), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430), -- cgit v1.2.3 From 4793e5a954faf2fa5e88726332bf851fbebcbf1c Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 6 May 2018 09:53:53 +0200 Subject: mwifiex: delete unneeded include Nothing that is defined in 11ac.h is referenced in cmdevt.c. Signed-off-by: Julia Lawall Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cmdevt.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 7014f440e6f8..9cfcdf6bec52 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -25,7 +25,6 @@ #include "main.h" #include "wmm.h" #include "11n.h" -#include "11ac.h" static void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter); -- cgit v1.2.3 From 4f9fb990013c03c5d56266fb4c439816cd84e1a6 Mon Sep 17 00:00:00 2001 From: Ganapathi Bhat Date: Tue, 8 May 2018 00:10:58 +0530 Subject: mwifiex: increase TX threashold to avoid TX timeout during ED MAC test While carrying energy detection(ED) tests, the chip will stop transmission upon detecting an energy in the connected channel. As a feedback, driver will stop dequeuing TX packets and due to which wmm_tx_pending keep incremeting. Once wmm_tx_pending reaches 100, driver calls netif_tx_stop_queue(). If TX ques is not restarted within 5(watchdog_timeo) seconds, it will result in TX timeout. The ED test is carried out for one minute and the current threshold of 100 is easily overcome by the traffic, cuasing TX timeouts. To fix this increase the threshold to 400. Signed-off-by: Cathy Luo Signed-off-by: Ganapathi Bhat Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/main.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 7c95c1279548..8ae74ed78805 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -84,8 +84,8 @@ enum { #define MWIFIEX_TIMER_10S 10000 #define MWIFIEX_TIMER_1S 1000 -#define MAX_TX_PENDING 100 -#define LOW_TX_PENDING 80 +#define MAX_TX_PENDING 400 +#define LOW_TX_PENDING 380 #define HIGH_RX_PENDING 50 #define LOW_RX_PENDING 20 -- cgit v1.2.3 From 41bd3d585da2fa480c3ded58965d9ccd2c9221e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= Date: Thu, 10 May 2018 14:57:35 +0200 Subject: wireless-drivers: Dynamically allocate struct station_info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the addition of the TXQ stats to cfg80211, the station_info struct has grown to be quite large, which results in warnings when allocated on the stack. Fix the affected places to do dynamic allocations instead. Fixes: 52539ca89f36 ("cfg80211: Expose TXQ stats and parameters to userspace") Reviewed-by: Sergey Matyukevich Signed-off-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/main.c | 14 +++++--- drivers/net/wireless/ath/wil6210/debugfs.c | 22 +++++++----- drivers/net/wireless/ath/wil6210/wmi.c | 19 ++++++---- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 18 ++++++---- drivers/net/wireless/marvell/mwifiex/uap_event.c | 25 ++++++++----- drivers/net/wireless/quantenna/qtnfmac/event.c | 41 ++++++++++++++-------- 6 files changed, 91 insertions(+), 48 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index db95f85751e3..808fb30be9ad 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -426,7 +426,7 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr, { u8 *ies = NULL, *wpa_ie = NULL, *pos; size_t ies_len = 0; - struct station_info sinfo; + struct station_info *sinfo; ath6kl_dbg(ATH6KL_DBG_TRC, "new station %pM aid=%d\n", mac_addr, aid); @@ -482,16 +482,20 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr, keymgmt, ucipher, auth, apsd_info); /* send event to application */ - memset(&sinfo, 0, sizeof(sinfo)); + sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL); + if (!sinfo) + return; /* TODO: sinfo.generation */ - sinfo.assoc_req_ies = ies; - sinfo.assoc_req_ies_len = ies_len; + sinfo->assoc_req_ies = ies; + sinfo->assoc_req_ies_len = ies_len; - cfg80211_new_sta(vif->ndev, mac_addr, &sinfo, GFP_KERNEL); + cfg80211_new_sta(vif->ndev, mac_addr, sinfo, GFP_KERNEL); netif_wake_queue(vif->ndev); + + kfree(sinfo); } void disconnect_timer_handler(struct timer_list *t) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 8c90b3111f0b..11e46e44381e 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1200,8 +1200,12 @@ static const struct file_operations fops_freq = { static int wil_link_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; - struct station_info sinfo; - int i, rc; + struct station_info *sinfo; + int i, rc = 0; + + sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL); + if (!sinfo) + return -ENOMEM; for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { struct wil_sta_info *p = &wil->sta[i]; @@ -1229,19 +1233,21 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data) vif = (mid < wil->max_vifs) ? wil->vifs[mid] : NULL; if (vif) { - rc = wil_cid_fill_sinfo(vif, i, &sinfo); + rc = wil_cid_fill_sinfo(vif, i, sinfo); if (rc) - return rc; + goto out; - seq_printf(s, " Tx_mcs = %d\n", sinfo.txrate.mcs); - seq_printf(s, " Rx_mcs = %d\n", sinfo.rxrate.mcs); - seq_printf(s, " SQ = %d\n", sinfo.signal); + seq_printf(s, " Tx_mcs = %d\n", sinfo->txrate.mcs); + seq_printf(s, " Rx_mcs = %d\n", sinfo->rxrate.mcs); + seq_printf(s, " SQ = %d\n", sinfo->signal); } else { seq_puts(s, " INVALID MID\n"); } } - return 0; +out: + kfree(sinfo); + return rc; } static int wil_link_seq_open(struct inode *inode, struct file *file) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index a3dda9a97c1f..90de9a916241 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -824,7 +824,7 @@ static void wmi_evt_connect(struct wil6210_vif *vif, int id, void *d, int len) struct wireless_dev *wdev = vif_to_wdev(vif); struct wmi_connect_event *evt = d; int ch; /* channel number */ - struct station_info sinfo; + struct station_info *sinfo; u8 *assoc_req_ie, *assoc_resp_ie; size_t assoc_req_ielen, assoc_resp_ielen; /* capinfo(u16) + listen_interval(u16) + IEs */ @@ -940,6 +940,7 @@ static void wmi_evt_connect(struct wil6210_vif *vif, int id, void *d, int len) vif->bss = NULL; } else if ((wdev->iftype == NL80211_IFTYPE_AP) || (wdev->iftype == NL80211_IFTYPE_P2P_GO)) { + if (rc) { if (disable_ap_sme) /* notify new_sta has failed */ @@ -947,16 +948,22 @@ static void wmi_evt_connect(struct wil6210_vif *vif, int id, void *d, int len) goto out; } - memset(&sinfo, 0, sizeof(sinfo)); + sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL); + if (!sinfo) { + rc = -ENOMEM; + goto out; + } - sinfo.generation = wil->sinfo_gen++; + sinfo->generation = wil->sinfo_gen++; if (assoc_req_ie) { - sinfo.assoc_req_ies = assoc_req_ie; - sinfo.assoc_req_ies_len = assoc_req_ielen; + sinfo->assoc_req_ies = assoc_req_ie; + sinfo->assoc_req_ies_len = assoc_req_ielen; } - cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL); + cfg80211_new_sta(ndev, evt->bssid, sinfo, GFP_KERNEL); + + kfree(sinfo); } else { wil_err(wil, "unhandled iftype %d for CID %d\n", wdev->iftype, evt->cid); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index ff6b3514c501..79a124d1aa23 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -5498,7 +5498,7 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, static int generation; u32 event = e->event_code; u32 reason = e->reason; - struct station_info sinfo; + struct station_info *sinfo; brcmf_dbg(CONN, "event %s (%u), reason %d\n", brcmf_fweh_event_name(event), event, reason); @@ -5511,16 +5511,22 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) && (reason == BRCMF_E_STATUS_SUCCESS)) { - memset(&sinfo, 0, sizeof(sinfo)); if (!data) { brcmf_err("No IEs present in ASSOC/REASSOC_IND"); return -EINVAL; } - sinfo.assoc_req_ies = data; - sinfo.assoc_req_ies_len = e->datalen; + + sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL); + if (!sinfo) + return -ENOMEM; + + sinfo->assoc_req_ies = data; + sinfo->assoc_req_ies_len = e->datalen; generation++; - sinfo.generation = generation; - cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL); + sinfo->generation = generation; + cfg80211_new_sta(ndev, e->addr, sinfo, GFP_KERNEL); + + kfree(sinfo); } else if ((event == BRCMF_E_DISASSOC_IND) || (event == BRCMF_E_DEAUTH_IND) || (event == BRCMF_E_DEAUTH)) { diff --git a/drivers/net/wireless/marvell/mwifiex/uap_event.c b/drivers/net/wireless/marvell/mwifiex/uap_event.c index e8c8728db15a..e86217a6b9ca 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_event.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_event.c @@ -108,7 +108,7 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) struct mwifiex_adapter *adapter = priv->adapter; int len, i; u32 eventcause = adapter->event_cause; - struct station_info sinfo; + struct station_info *sinfo; struct mwifiex_assoc_event *event; struct mwifiex_sta_node *node; u8 *deauth_mac; @@ -117,7 +117,10 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) switch (eventcause) { case EVENT_UAP_STA_ASSOC: - memset(&sinfo, 0, sizeof(sinfo)); + sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL); + if (!sinfo) + return -ENOMEM; + event = (struct mwifiex_assoc_event *) (adapter->event_body + MWIFIEX_UAP_EVENT_EXTRA_HEADER); if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) { @@ -132,28 +135,31 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) len = ETH_ALEN; if (len != -1) { - sinfo.assoc_req_ies = &event->data[len]; - len = (u8 *)sinfo.assoc_req_ies - + sinfo->assoc_req_ies = &event->data[len]; + len = (u8 *)sinfo->assoc_req_ies - (u8 *)&event->frame_control; - sinfo.assoc_req_ies_len = + sinfo->assoc_req_ies_len = le16_to_cpu(event->len) - (u16)len; } } - cfg80211_new_sta(priv->netdev, event->sta_addr, &sinfo, + cfg80211_new_sta(priv->netdev, event->sta_addr, sinfo, GFP_KERNEL); node = mwifiex_add_sta_entry(priv, event->sta_addr); if (!node) { mwifiex_dbg(adapter, ERROR, "could not create station entry!\n"); + kfree(sinfo); return -1; } - if (!priv->ap_11n_enabled) + if (!priv->ap_11n_enabled) { + kfree(sinfo); break; + } - mwifiex_set_sta_ht_cap(priv, sinfo.assoc_req_ies, - sinfo.assoc_req_ies_len, node); + mwifiex_set_sta_ht_cap(priv, sinfo->assoc_req_ies, + sinfo->assoc_req_ies_len, node); for (i = 0; i < MAX_NUM_TID; i++) { if (node->is_11n_enabled) @@ -163,6 +169,7 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) node->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED; } memset(node->rx_seq, 0xff, sizeof(node->rx_seq)); + kfree(sinfo); break; case EVENT_UAP_STA_DEAUTH: deauth_mac = adapter->event_body + diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.c b/drivers/net/wireless/quantenna/qtnfmac/event.c index cb2a6c12f870..16617c44f81b 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/event.c +++ b/drivers/net/wireless/quantenna/qtnfmac/event.c @@ -34,12 +34,13 @@ qtnf_event_handle_sta_assoc(struct qtnf_wmac *mac, struct qtnf_vif *vif, { const u8 *sta_addr; u16 frame_control; - struct station_info sinfo = { 0 }; + struct station_info *sinfo; size_t payload_len; u16 tlv_type; u16 tlv_value_len; size_t tlv_full_len; const struct qlink_tlv_hdr *tlv; + int ret = 0; if (unlikely(len < sizeof(*sta_assoc))) { pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", @@ -53,6 +54,10 @@ qtnf_event_handle_sta_assoc(struct qtnf_wmac *mac, struct qtnf_vif *vif, return -EPROTO; } + sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL); + if (!sinfo) + return -ENOMEM; + sta_addr = sta_assoc->sta_addr; frame_control = le16_to_cpu(sta_assoc->frame_control); @@ -61,9 +66,9 @@ qtnf_event_handle_sta_assoc(struct qtnf_wmac *mac, struct qtnf_vif *vif, qtnf_sta_list_add(vif, sta_addr); - sinfo.assoc_req_ies = NULL; - sinfo.assoc_req_ies_len = 0; - sinfo.generation = vif->generation; + sinfo->assoc_req_ies = NULL; + sinfo->assoc_req_ies_len = 0; + sinfo->generation = vif->generation; payload_len = len - sizeof(*sta_assoc); tlv = (const struct qlink_tlv_hdr *)sta_assoc->ies; @@ -73,23 +78,27 @@ qtnf_event_handle_sta_assoc(struct qtnf_wmac *mac, struct qtnf_vif *vif, tlv_value_len = le16_to_cpu(tlv->len); tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); - if (tlv_full_len > payload_len) - return -EINVAL; + if (tlv_full_len > payload_len) { + ret = -EINVAL; + goto out; + } if (tlv_type == QTN_TLV_ID_IE_SET) { const struct qlink_tlv_ie_set *ie_set; unsigned int ie_len; - if (payload_len < sizeof(*ie_set)) - return -EINVAL; + if (payload_len < sizeof(*ie_set)) { + ret = -EINVAL; + goto out; + } ie_set = (const struct qlink_tlv_ie_set *)tlv; ie_len = tlv_value_len - (sizeof(*ie_set) - sizeof(ie_set->hdr)); if (ie_set->type == QLINK_IE_SET_ASSOC_REQ && ie_len) { - sinfo.assoc_req_ies = ie_set->ie_data; - sinfo.assoc_req_ies_len = ie_len; + sinfo->assoc_req_ies = ie_set->ie_data; + sinfo->assoc_req_ies_len = ie_len; } } @@ -97,13 +106,17 @@ qtnf_event_handle_sta_assoc(struct qtnf_wmac *mac, struct qtnf_vif *vif, tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); } - if (payload_len) - return -EINVAL; + if (payload_len) { + ret = -EINVAL; + goto out; + } - cfg80211_new_sta(vif->netdev, sta_assoc->sta_addr, &sinfo, + cfg80211_new_sta(vif->netdev, sta_assoc->sta_addr, sinfo, GFP_KERNEL); - return 0; +out: + kfree(sinfo); + return ret; } static int -- cgit v1.2.3 From 6823dc0d91e5d238ca14a252228a5121d41eb517 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 10 May 2018 16:06:09 +0200 Subject: mt76x2: add a polling delay in mt76x2_mac_stop routine Add a usleep_range in mt76x2_mac_stop routine in order to add a polling delay checking values of MT_MAC_STATUS and IBI_R12 registers Signed-off-by: Lorenzo Bianconi Acked-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x2_init.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index d21e4a7c1bb9..dd4c1127797e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -370,12 +370,12 @@ void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force) /* Wait for MAC to become idle */ for (i = 0; i < 300; i++) { - if (mt76_rr(dev, MT_MAC_STATUS) & - (MT_MAC_STATUS_RX | MT_MAC_STATUS_TX)) - continue; - - if (mt76_rr(dev, MT_BBP(IBI, 12))) + if ((mt76_rr(dev, MT_MAC_STATUS) & + (MT_MAC_STATUS_RX | MT_MAC_STATUS_TX)) || + mt76_rr(dev, MT_BBP(IBI, 12))) { + usleep_range(10, 20); continue; + } stopped = true; break; -- cgit v1.2.3 From b41c393676696c20456d5fd8cbe71453560ee06e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 10 May 2018 15:32:17 +0100 Subject: rsi: fix spelling mistake: "thead" -> "thread" Trivial fix to spelling mistake in rsi_dbg debug message text Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index 1f1b97220d43..3644d7d99463 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -485,7 +485,7 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) } rsi_core_queue_pkt(common, skb); - rsi_dbg(DATA_TX_ZONE, "%s: ===> Scheduling TX thead <===\n", __func__); + rsi_dbg(DATA_TX_ZONE, "%s: ===> Scheduling TX thread <===\n", __func__); rsi_set_event(&common->tx_thread.event); return; -- cgit v1.2.3 From cfb353c0dc058bc1619cc226d3cbbda1f360bdd3 Mon Sep 17 00:00:00 2001 From: Yu Wang Date: Thu, 3 May 2018 14:01:25 +0800 Subject: ath10k: add quiet mode support for QCA6174/QCA9377 To enable thermal throttling for QCA6174 and QCA9377, implement gen_pdev_set_quiet_mode for them. With this change, quiet period for QCA6174/QCA9377 can be also set/get via debugfs. Usage: To set quiet period: echo > /sys/kernel/debug/ieee80211/phyX/ath10k/quiet_period To get the current quiet period: cat /sys/kernel/debug/ieee80211/phyX/ath10k/quiet_period This change has been verified with QCA6174 hw3.2(fw: WLAN_RM.4.4.1-00102-QCARMSWP-1). Signed-off-by: Yu Wang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 33 ++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/wmi-tlv.h | 16 +++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 01f4eb201330..2e34a1fc5ba6 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -3135,6 +3135,37 @@ ath10k_wmi_tlv_op_gen_tdls_peer_update(struct ath10k *ar, return skb; } +static struct sk_buff * +ath10k_wmi_tlv_op_gen_pdev_set_quiet_mode(struct ath10k *ar, u32 period, + u32 duration, u32 next_offset, + u32 enabled) +{ + struct wmi_tlv_set_quiet_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_QUIET_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + + /* vdev_id is not in use, set to 0 */ + cmd->vdev_id = __cpu_to_le32(0); + cmd->period = __cpu_to_le32(period); + cmd->duration = __cpu_to_le32(duration); + cmd->next_start = __cpu_to_le32(next_offset); + cmd->enabled = __cpu_to_le32(enabled); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi tlv quiet param: period %u duration %u enabled %d\n", + period, duration, enabled); + return skb; +} + static struct sk_buff * ath10k_wmi_tlv_op_gen_wow_enable(struct ath10k *ar) { @@ -3854,7 +3885,7 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg, .gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable, .gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable, - /* .gen_pdev_set_quiet_mode not implemented */ + .gen_pdev_set_quiet_mode = ath10k_wmi_tlv_op_gen_pdev_set_quiet_mode, .gen_pdev_get_temperature = ath10k_wmi_tlv_op_gen_pdev_get_temperature, /* .gen_addba_clear_resp not implemented */ /* .gen_addba_send not implemented */ diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 954c50bb3f66..3e1e340cd834 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -1952,6 +1953,21 @@ struct wmi_tlv_wow_add_del_event_cmd { __le32 event_bitmap; } __packed; +/* Command to set/unset chip in quiet mode */ +struct wmi_tlv_set_quiet_cmd { + __le32 vdev_id; + + /* in TUs */ + __le32 period; + + /* in TUs */ + __le32 duration; + + /* offset in TUs */ + __le32 next_start; + __le32 enabled; +} __packed; + struct wmi_tlv_wow_enable_cmd { __le32 enable; } __packed; -- cgit v1.2.3 From 469bd5eab6224c966253e62c50af1084a7cdad64 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 5 May 2018 00:04:08 -0300 Subject: ath10k: snoc: Remove owner assignment from platform_driver Structure platform_driver does not need to set the owner field, as this will be populated by the driver core. Generated by scripts/coccinelle/api/platform_no_drv_owner.cocci. Signed-off-by: Fabio Estevam Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/snoc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 47a4d2a5bd4c..a3a7042fe13a 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -1385,7 +1385,6 @@ static struct platform_driver ath10k_snoc_driver = { .remove = ath10k_snoc_remove, .driver = { .name = "ath10k_snoc", - .owner = THIS_MODULE, .of_match_table = ath10k_snoc_dt_match, }, }; -- cgit v1.2.3 From e3148cc5fecf60dcbd07e5c9cae987976d25cb17 Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Sun, 6 May 2018 15:25:00 +0200 Subject: ath10k: fix return value check in wake_tx_q op ath10k_mac_tx_push_txq returns either a postive integer (length) on success or a negative error code on error. The "if (ret) break;" statement will thus always break out of the loop immediately after ath10k_mac_tx_push_txq has returned (making the loop pointless). A side effect of this fix is that we will iterate the queue until ath10k_mac_tx_push_txq returns -ENOENT. This will make sure the queue is not added back to ar->txqs when it is empty. This could potentially improve performance somewhat (I have seen a small improvement with SDIO devices). Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 3d7119ad7c7a..487a7a7380fd 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4290,7 +4290,7 @@ static void ath10k_mac_op_wake_tx_queue(struct ieee80211_hw *hw, while (ath10k_mac_tx_can_push(hw, f_txq) && max--) { ret = ath10k_mac_tx_push_txq(hw, f_txq); - if (ret) + if (ret < 0) break; } if (ret != -ENOENT) -- cgit v1.2.3 From 3e2740cda22473cca2abd117baeabf20d9024fba Mon Sep 17 00:00:00 2001 From: Kenneth Lu Date: Mon, 7 May 2018 17:39:48 +0800 Subject: ath10k: remove variables which set but not used Variable buf_len and num_vdev_stats are being assigned but never read. These are redundant and can be remove. Signed-off-by: Kenneth Lu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index bb8e9e259a56..46fb96ee5852 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2318,7 +2318,6 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) u32 phy_mode; u32 snr; u32 rate; - u32 buf_len; u16 fc; int ret; @@ -2330,7 +2329,6 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) } channel = __le32_to_cpu(arg.channel); - buf_len = __le32_to_cpu(arg.buf_len); rx_status = __le32_to_cpu(arg.status); snr = __le32_to_cpu(arg.snr); phy_mode = __le32_to_cpu(arg.phy_mode); @@ -2740,14 +2738,13 @@ static int ath10k_wmi_main_op_pull_fw_stats(struct ath10k *ar, struct ath10k_fw_stats *stats) { const struct wmi_stats_event *ev = (void *)skb->data; - u32 num_pdev_stats, num_vdev_stats, num_peer_stats; + u32 num_pdev_stats, num_peer_stats; int i; if (!skb_pull(skb, sizeof(*ev))) return -EPROTO; num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); - num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); num_peer_stats = __le32_to_cpu(ev->num_peer_stats); for (i = 0; i < num_pdev_stats; i++) { @@ -2795,14 +2792,13 @@ static int ath10k_wmi_10x_op_pull_fw_stats(struct ath10k *ar, struct ath10k_fw_stats *stats) { const struct wmi_stats_event *ev = (void *)skb->data; - u32 num_pdev_stats, num_vdev_stats, num_peer_stats; + u32 num_pdev_stats, num_peer_stats; int i; if (!skb_pull(skb, sizeof(*ev))) return -EPROTO; num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); - num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); num_peer_stats = __le32_to_cpu(ev->num_peer_stats); for (i = 0; i < num_pdev_stats; i++) { @@ -2856,7 +2852,6 @@ static int ath10k_wmi_10_2_op_pull_fw_stats(struct ath10k *ar, const struct wmi_10_2_stats_event *ev = (void *)skb->data; u32 num_pdev_stats; u32 num_pdev_ext_stats; - u32 num_vdev_stats; u32 num_peer_stats; int i; @@ -2865,7 +2860,6 @@ static int ath10k_wmi_10_2_op_pull_fw_stats(struct ath10k *ar, num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats); - num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); num_peer_stats = __le32_to_cpu(ev->num_peer_stats); for (i = 0; i < num_pdev_stats; i++) { @@ -2935,7 +2929,6 @@ static int ath10k_wmi_10_2_4_op_pull_fw_stats(struct ath10k *ar, const struct wmi_10_2_stats_event *ev = (void *)skb->data; u32 num_pdev_stats; u32 num_pdev_ext_stats; - u32 num_vdev_stats; u32 num_peer_stats; int i; @@ -2944,7 +2937,6 @@ static int ath10k_wmi_10_2_4_op_pull_fw_stats(struct ath10k *ar, num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats); - num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); num_peer_stats = __le32_to_cpu(ev->num_peer_stats); for (i = 0; i < num_pdev_stats; i++) { -- cgit v1.2.3 From 0be928850dac4dc3f9f4e0a9966b6c809557a494 Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Wed, 9 May 2018 09:56:33 +0200 Subject: ath10k: hw: make consistent usage of ATH10K_FW_DIR in paths For some reason not all entries used ATH10K_FW_DIR so fix that. No functional changes. Signed-off-by: Marcus Folkesson Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/hw.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index b8bdabe73073..23467e9fefeb 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -85,11 +85,11 @@ enum qca9377_chip_id_rev { QCA9377_HW_1_1_CHIP_ID_REV = 0x1, }; -#define QCA6174_HW_2_1_FW_DIR "ath10k/QCA6174/hw2.1" +#define QCA6174_HW_2_1_FW_DIR ATH10K_FW_DIR "/QCA6174/hw2.1" #define QCA6174_HW_2_1_BOARD_DATA_FILE "board.bin" #define QCA6174_HW_2_1_PATCH_LOAD_ADDR 0x1234 -#define QCA6174_HW_3_0_FW_DIR "ath10k/QCA6174/hw3.0" +#define QCA6174_HW_3_0_FW_DIR ATH10K_FW_DIR "/QCA6174/hw3.0" #define QCA6174_HW_3_0_BOARD_DATA_FILE "board.bin" #define QCA6174_HW_3_0_PATCH_LOAD_ADDR 0x1234 -- cgit v1.2.3 From c3f7f31efe39209722a6fd19d7b7a4cceb7ca75c Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Wed, 9 May 2018 15:03:21 +0530 Subject: ath10k: replace bit shifts with the BIT() macro for rx desc bits Use the BIT() macro from 'linux/bitops.h' to define the rx desc bit flags to have consistency with new definitions. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/rx_desc.h | 136 +++++++++++++++--------------- 1 file changed, 69 insertions(+), 67 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index 545deb6d7af1..ea4075d456fa 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -18,39 +18,41 @@ #ifndef _RX_DESC_H_ #define _RX_DESC_H_ +#include + enum rx_attention_flags { - RX_ATTENTION_FLAGS_FIRST_MPDU = 1 << 0, - RX_ATTENTION_FLAGS_LAST_MPDU = 1 << 1, - RX_ATTENTION_FLAGS_MCAST_BCAST = 1 << 2, - RX_ATTENTION_FLAGS_PEER_IDX_INVALID = 1 << 3, - RX_ATTENTION_FLAGS_PEER_IDX_TIMEOUT = 1 << 4, - RX_ATTENTION_FLAGS_POWER_MGMT = 1 << 5, - RX_ATTENTION_FLAGS_NON_QOS = 1 << 6, - RX_ATTENTION_FLAGS_NULL_DATA = 1 << 7, - RX_ATTENTION_FLAGS_MGMT_TYPE = 1 << 8, - RX_ATTENTION_FLAGS_CTRL_TYPE = 1 << 9, - RX_ATTENTION_FLAGS_MORE_DATA = 1 << 10, - RX_ATTENTION_FLAGS_EOSP = 1 << 11, - RX_ATTENTION_FLAGS_U_APSD_TRIGGER = 1 << 12, - RX_ATTENTION_FLAGS_FRAGMENT = 1 << 13, - RX_ATTENTION_FLAGS_ORDER = 1 << 14, - RX_ATTENTION_FLAGS_CLASSIFICATION = 1 << 15, - RX_ATTENTION_FLAGS_OVERFLOW_ERR = 1 << 16, - RX_ATTENTION_FLAGS_MSDU_LENGTH_ERR = 1 << 17, - RX_ATTENTION_FLAGS_TCP_UDP_CHKSUM_FAIL = 1 << 18, - RX_ATTENTION_FLAGS_IP_CHKSUM_FAIL = 1 << 19, - RX_ATTENTION_FLAGS_SA_IDX_INVALID = 1 << 20, - RX_ATTENTION_FLAGS_DA_IDX_INVALID = 1 << 21, - RX_ATTENTION_FLAGS_SA_IDX_TIMEOUT = 1 << 22, - RX_ATTENTION_FLAGS_DA_IDX_TIMEOUT = 1 << 23, - RX_ATTENTION_FLAGS_ENCRYPT_REQUIRED = 1 << 24, - RX_ATTENTION_FLAGS_DIRECTED = 1 << 25, - RX_ATTENTION_FLAGS_BUFFER_FRAGMENT = 1 << 26, - RX_ATTENTION_FLAGS_MPDU_LENGTH_ERR = 1 << 27, - RX_ATTENTION_FLAGS_TKIP_MIC_ERR = 1 << 28, - RX_ATTENTION_FLAGS_DECRYPT_ERR = 1 << 29, - RX_ATTENTION_FLAGS_FCS_ERR = 1 << 30, - RX_ATTENTION_FLAGS_MSDU_DONE = 1 << 31, + RX_ATTENTION_FLAGS_FIRST_MPDU = BIT(0), + RX_ATTENTION_FLAGS_LAST_MPDU = BIT(1), + RX_ATTENTION_FLAGS_MCAST_BCAST = BIT(2), + RX_ATTENTION_FLAGS_PEER_IDX_INVALID = BIT(3), + RX_ATTENTION_FLAGS_PEER_IDX_TIMEOUT = BIT(4), + RX_ATTENTION_FLAGS_POWER_MGMT = BIT(5), + RX_ATTENTION_FLAGS_NON_QOS = BIT(6), + RX_ATTENTION_FLAGS_NULL_DATA = BIT(7), + RX_ATTENTION_FLAGS_MGMT_TYPE = BIT(8), + RX_ATTENTION_FLAGS_CTRL_TYPE = BIT(9), + RX_ATTENTION_FLAGS_MORE_DATA = BIT(10), + RX_ATTENTION_FLAGS_EOSP = BIT(11), + RX_ATTENTION_FLAGS_U_APSD_TRIGGER = BIT(12), + RX_ATTENTION_FLAGS_FRAGMENT = BIT(13), + RX_ATTENTION_FLAGS_ORDER = BIT(14), + RX_ATTENTION_FLAGS_CLASSIFICATION = BIT(15), + RX_ATTENTION_FLAGS_OVERFLOW_ERR = BIT(16), + RX_ATTENTION_FLAGS_MSDU_LENGTH_ERR = BIT(17), + RX_ATTENTION_FLAGS_TCP_UDP_CHKSUM_FAIL = BIT(18), + RX_ATTENTION_FLAGS_IP_CHKSUM_FAIL = BIT(19), + RX_ATTENTION_FLAGS_SA_IDX_INVALID = BIT(20), + RX_ATTENTION_FLAGS_DA_IDX_INVALID = BIT(21), + RX_ATTENTION_FLAGS_SA_IDX_TIMEOUT = BIT(22), + RX_ATTENTION_FLAGS_DA_IDX_TIMEOUT = BIT(23), + RX_ATTENTION_FLAGS_ENCRYPT_REQUIRED = BIT(24), + RX_ATTENTION_FLAGS_DIRECTED = BIT(25), + RX_ATTENTION_FLAGS_BUFFER_FRAGMENT = BIT(26), + RX_ATTENTION_FLAGS_MPDU_LENGTH_ERR = BIT(27), + RX_ATTENTION_FLAGS_TKIP_MIC_ERR = BIT(28), + RX_ATTENTION_FLAGS_DECRYPT_ERR = BIT(29), + RX_ATTENTION_FLAGS_FCS_ERR = BIT(30), + RX_ATTENTION_FLAGS_MSDU_DONE = BIT(31), }; struct rx_attention { @@ -254,15 +256,15 @@ enum htt_rx_mpdu_encrypt_type { #define RX_MPDU_START_INFO0_SEQ_NUM_LSB 16 #define RX_MPDU_START_INFO0_ENCRYPT_TYPE_MASK 0xf0000000 #define RX_MPDU_START_INFO0_ENCRYPT_TYPE_LSB 28 -#define RX_MPDU_START_INFO0_FROM_DS (1 << 11) -#define RX_MPDU_START_INFO0_TO_DS (1 << 12) -#define RX_MPDU_START_INFO0_ENCRYPTED (1 << 13) -#define RX_MPDU_START_INFO0_RETRY (1 << 14) -#define RX_MPDU_START_INFO0_TXBF_H_INFO (1 << 15) +#define RX_MPDU_START_INFO0_FROM_DS BIT(11) +#define RX_MPDU_START_INFO0_TO_DS BIT(12) +#define RX_MPDU_START_INFO0_ENCRYPTED BIT(13) +#define RX_MPDU_START_INFO0_RETRY BIT(14) +#define RX_MPDU_START_INFO0_TXBF_H_INFO BIT(15) #define RX_MPDU_START_INFO1_TID_MASK 0xf0000000 #define RX_MPDU_START_INFO1_TID_LSB 28 -#define RX_MPDU_START_INFO1_DIRECTED (1 << 16) +#define RX_MPDU_START_INFO1_DIRECTED BIT(16) struct rx_mpdu_start { __le32 info0; @@ -357,13 +359,13 @@ struct rx_mpdu_start { #define RX_MPDU_END_INFO0_RESERVED_0_LSB 0 #define RX_MPDU_END_INFO0_POST_DELIM_CNT_MASK 0x0fff0000 #define RX_MPDU_END_INFO0_POST_DELIM_CNT_LSB 16 -#define RX_MPDU_END_INFO0_OVERFLOW_ERR (1 << 13) -#define RX_MPDU_END_INFO0_LAST_MPDU (1 << 14) -#define RX_MPDU_END_INFO0_POST_DELIM_ERR (1 << 15) -#define RX_MPDU_END_INFO0_MPDU_LENGTH_ERR (1 << 28) -#define RX_MPDU_END_INFO0_TKIP_MIC_ERR (1 << 29) -#define RX_MPDU_END_INFO0_DECRYPT_ERR (1 << 30) -#define RX_MPDU_END_INFO0_FCS_ERR (1 << 31) +#define RX_MPDU_END_INFO0_OVERFLOW_ERR BIT(13) +#define RX_MPDU_END_INFO0_LAST_MPDU BIT(14) +#define RX_MPDU_END_INFO0_POST_DELIM_ERR BIT(15) +#define RX_MPDU_END_INFO0_MPDU_LENGTH_ERR BIT(28) +#define RX_MPDU_END_INFO0_TKIP_MIC_ERR BIT(29) +#define RX_MPDU_END_INFO0_DECRYPT_ERR BIT(30) +#define RX_MPDU_END_INFO0_FCS_ERR BIT(31) struct rx_mpdu_end { __le32 info0; @@ -422,12 +424,12 @@ struct rx_mpdu_end { #define RX_MSDU_START_INFO1_DECAP_FORMAT_LSB 8 #define RX_MSDU_START_INFO1_SA_IDX_MASK 0x07ff0000 #define RX_MSDU_START_INFO1_SA_IDX_LSB 16 -#define RX_MSDU_START_INFO1_IPV4_PROTO (1 << 10) -#define RX_MSDU_START_INFO1_IPV6_PROTO (1 << 11) -#define RX_MSDU_START_INFO1_TCP_PROTO (1 << 12) -#define RX_MSDU_START_INFO1_UDP_PROTO (1 << 13) -#define RX_MSDU_START_INFO1_IP_FRAG (1 << 14) -#define RX_MSDU_START_INFO1_TCP_ONLY_ACK (1 << 15) +#define RX_MSDU_START_INFO1_IPV4_PROTO BIT(10) +#define RX_MSDU_START_INFO1_IPV6_PROTO BIT(11) +#define RX_MSDU_START_INFO1_TCP_PROTO BIT(12) +#define RX_MSDU_START_INFO1_UDP_PROTO BIT(13) +#define RX_MSDU_START_INFO1_IP_FRAG BIT(14) +#define RX_MSDU_START_INFO1_TCP_ONLY_ACK BIT(15) #define RX_MSDU_START_INFO2_DA_IDX_MASK 0x000007ff #define RX_MSDU_START_INFO2_DA_IDX_LSB 0 @@ -568,10 +570,10 @@ struct rx_msdu_start { #define RX_MSDU_END_INFO0_REPORTED_MPDU_LENGTH_MASK 0x00003fff #define RX_MSDU_END_INFO0_REPORTED_MPDU_LENGTH_LSB 0 -#define RX_MSDU_END_INFO0_FIRST_MSDU (1 << 14) -#define RX_MSDU_END_INFO0_LAST_MSDU (1 << 15) -#define RX_MSDU_END_INFO0_PRE_DELIM_ERR (1 << 30) -#define RX_MSDU_END_INFO0_RESERVED_3B (1 << 31) +#define RX_MSDU_END_INFO0_FIRST_MSDU BIT(14) +#define RX_MSDU_END_INFO0_LAST_MSDU BIT(15) +#define RX_MSDU_END_INFO0_PRE_DELIM_ERR BIT(30) +#define RX_MSDU_END_INFO0_RESERVED_3B BIT(31) struct rx_msdu_end_common { __le16 ip_hdr_cksum; @@ -691,7 +693,7 @@ struct rx_msdu_end { #define HTT_RX_PPDU_START_PREAMBLE_VHT 0x0C #define HTT_RX_PPDU_START_PREAMBLE_VHT_WITH_TXBF 0x0D -#define RX_PPDU_START_INFO0_IS_GREENFIELD (1 << 0) +#define RX_PPDU_START_INFO0_IS_GREENFIELD BIT(0) #define RX_PPDU_START_INFO1_L_SIG_RATE_MASK 0x0000000f #define RX_PPDU_START_INFO1_L_SIG_RATE_LSB 0 @@ -701,15 +703,15 @@ struct rx_msdu_end { #define RX_PPDU_START_INFO1_L_SIG_TAIL_LSB 18 #define RX_PPDU_START_INFO1_PREAMBLE_TYPE_MASK 0xff000000 #define RX_PPDU_START_INFO1_PREAMBLE_TYPE_LSB 24 -#define RX_PPDU_START_INFO1_L_SIG_RATE_SELECT (1 << 4) -#define RX_PPDU_START_INFO1_L_SIG_PARITY (1 << 17) +#define RX_PPDU_START_INFO1_L_SIG_RATE_SELECT BIT(4) +#define RX_PPDU_START_INFO1_L_SIG_PARITY BIT(17) #define RX_PPDU_START_INFO2_HT_SIG_VHT_SIG_A_1_MASK 0x00ffffff #define RX_PPDU_START_INFO2_HT_SIG_VHT_SIG_A_1_LSB 0 #define RX_PPDU_START_INFO3_HT_SIG_VHT_SIG_A_2_MASK 0x00ffffff #define RX_PPDU_START_INFO3_HT_SIG_VHT_SIG_A_2_LSB 0 -#define RX_PPDU_START_INFO3_TXBF_H_INFO (1 << 24) +#define RX_PPDU_START_INFO3_TXBF_H_INFO BIT(24) #define RX_PPDU_START_INFO4_VHT_SIG_B_MASK 0x1fffffff #define RX_PPDU_START_INFO4_VHT_SIG_B_LSB 0 @@ -898,14 +900,14 @@ struct rx_ppdu_start { * Reserved: HW should fill with 0, FW should ignore. */ -#define RX_PPDU_END_FLAGS_PHY_ERR (1 << 0) -#define RX_PPDU_END_FLAGS_RX_LOCATION (1 << 1) -#define RX_PPDU_END_FLAGS_TXBF_H_INFO (1 << 2) +#define RX_PPDU_END_FLAGS_PHY_ERR BIT(0) +#define RX_PPDU_END_FLAGS_RX_LOCATION BIT(1) +#define RX_PPDU_END_FLAGS_TXBF_H_INFO BIT(2) #define RX_PPDU_END_INFO0_RX_ANTENNA_MASK 0x00ffffff #define RX_PPDU_END_INFO0_RX_ANTENNA_LSB 0 -#define RX_PPDU_END_INFO0_FLAGS_TX_HT_VHT_ACK (1 << 24) -#define RX_PPDU_END_INFO0_BB_CAPTURED_CHANNEL (1 << 25) +#define RX_PPDU_END_INFO0_FLAGS_TX_HT_VHT_ACK BIT(24) +#define RX_PPDU_END_INFO0_BB_CAPTURED_CHANNEL BIT(25) #define RX_PPDU_END_INFO1_PEER_IDX_MASK 0x1ffc #define RX_PPDU_END_INFO1_PEER_IDX_LSB 2 @@ -1265,9 +1267,9 @@ struct rx_ppdu_end { * to 0. */ -#define FW_RX_DESC_INFO0_DISCARD (1 << 0) -#define FW_RX_DESC_INFO0_FORWARD (1 << 1) -#define FW_RX_DESC_INFO0_INSPECT (1 << 5) +#define FW_RX_DESC_INFO0_DISCARD BIT(0) +#define FW_RX_DESC_INFO0_FORWARD BIT(1) +#define FW_RX_DESC_INFO0_INSPECT BIT(5) #define FW_RX_DESC_INFO0_EXT_MASK 0xC0 #define FW_RX_DESC_INFO0_EXT_LSB 6 -- cgit v1.2.3 From 777b4690fc4a39a753da97541de2d4fab3dc65b3 Mon Sep 17 00:00:00 2001 From: Alexei Avshalom Lazar Date: Wed, 9 May 2018 13:06:52 +0300 Subject: wil6210: disable tracing config option Disable WIL6210_TRACING by default to avoid its performance overhead. Signed-off-by: Alexei Avshalom Lazar Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig index b448926b0c0f..3548e8d5e18e 100644 --- a/drivers/net/wireless/ath/wil6210/Kconfig +++ b/drivers/net/wireless/ath/wil6210/Kconfig @@ -33,7 +33,7 @@ config WIL6210_TRACING bool "wil6210 tracing support" depends on WIL6210 depends on EVENT_TRACING - default y + default n ---help--- Say Y here to enable tracepoints for the wil6210 driver using the kernel tracing infrastructure. Select this -- cgit v1.2.3 From 8a4fa21438e38ed2db8c01a282de3995a6c0d75f Mon Sep 17 00:00:00 2001 From: Ahmad Masri Date: Wed, 9 May 2018 13:06:53 +0300 Subject: wil6210: align to latest auto generated wmi.h Align to latest version of the auto generated wmi file describing the interface with FW Signed-off-by: Ahmad Masri Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wmi.c | 6 +- drivers/net/wireless/ath/wil6210/wmi.h | 387 +++++++++++++++++++++++++++++++-- 2 files changed, 371 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index a3dda9a97c1f..73efa13bc742 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1554,7 +1554,9 @@ int wmi_pcp_start(struct wil6210_vif *vif, .pcp_max_assoc_sta = max_assoc_sta, .hidden_ssid = hidden_ssid, .is_go = is_go, - .disable_ap_sme = disable_ap_sme, + .ap_sme_offload_mode = disable_ap_sme ? + WMI_AP_SME_OFFLOAD_PARTIAL : + WMI_AP_SME_OFFLOAD_FULL, .abft_len = wil->abft_len, }; struct { @@ -1574,7 +1576,7 @@ int wmi_pcp_start(struct wil6210_vif *vif, } if (disable_ap_sme && - !test_bit(WMI_FW_CAPABILITY_DISABLE_AP_SME, + !test_bit(WMI_FW_CAPABILITY_AP_SME_OFFLOAD_PARTIAL, wil->fw_capabilities)) { wil_err(wil, "disable_ap_sme not supported by FW\n"); return -EOPNOTSUPP; diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index d3e75f0ff245..dc503d903786 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -1,4 +1,5 @@ /* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2006-2012 Wilocity * @@ -29,8 +30,6 @@ #ifndef __WILOCITY_WMI_H__ #define __WILOCITY_WMI_H__ -/* General */ -#define WMI_MAX_ASSOC_STA (8) #define WMI_DEFAULT_ASSOC_STA (1) #define WMI_MAC_LEN (6) #define WMI_PROX_RANGE_NUM (3) @@ -41,6 +40,19 @@ #define WMI_RF_ETYPE_LENGTH (3) #define WMI_RF_RX2TX_LENGTH (3) #define WMI_RF_ETYPE_VAL_PER_RANGE (5) +/* DTYPE configuration array size + * must always be kept equal to (WMI_RF_DTYPE_LENGTH+1) + */ +#define WMI_RF_DTYPE_CONF_LENGTH (4) +/* ETYPE configuration array size + * must always be kept equal to + * (WMI_RF_ETYPE_LENGTH+WMI_RF_ETYPE_VAL_PER_RANGE) + */ +#define WMI_RF_ETYPE_CONF_LENGTH (8) +/* RX2TX configuration array size + * must always be kept equal to (WMI_RF_RX2TX_LENGTH+1) + */ +#define WMI_RF_RX2TX_CONF_LENGTH (4) /* Mailbox interface * used for commands and events @@ -61,7 +73,7 @@ enum wmi_fw_capability { WMI_FW_CAPABILITY_PS_CONFIG = 1, WMI_FW_CAPABILITY_RF_SECTORS = 2, WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT = 3, - WMI_FW_CAPABILITY_DISABLE_AP_SME = 4, + WMI_FW_CAPABILITY_AP_SME_OFFLOAD_PARTIAL = 4, WMI_FW_CAPABILITY_WMI_ONLY = 5, WMI_FW_CAPABILITY_THERMAL_THROTTLING = 7, WMI_FW_CAPABILITY_D3_SUSPEND = 8, @@ -73,6 +85,7 @@ enum wmi_fw_capability { WMI_FW_CAPABILITY_LO_POWER_CALIB_FROM_OTP = 14, WMI_FW_CAPABILITY_PNO = 15, WMI_FW_CAPABILITY_REF_CLOCK_CONTROL = 18, + WMI_FW_CAPABILITY_AP_SME_OFFLOAD_NONE = 19, WMI_FW_CAPABILITY_MAX, }; @@ -164,12 +177,14 @@ enum wmi_command_id { WMI_SET_ACTIVE_SILENT_RSSI_TABLE_CMDID = 0x85C, WMI_RF_PWR_ON_DELAY_CMDID = 0x85D, WMI_SET_HIGH_POWER_TABLE_PARAMS_CMDID = 0x85E, + WMI_FIXED_SCHEDULING_UL_CONFIG_CMDID = 0x85F, /* Performance monitoring commands */ WMI_BF_CTRL_CMDID = 0x862, WMI_NOTIFY_REQ_CMDID = 0x863, WMI_GET_STATUS_CMDID = 0x864, WMI_GET_RF_STATUS_CMDID = 0x866, WMI_GET_BASEBAND_TYPE_CMDID = 0x867, + WMI_VRING_SWITCH_TIMING_CONFIG_CMDID = 0x868, WMI_UNIT_TEST_CMDID = 0x900, WMI_FLASH_READ_CMDID = 0x902, WMI_FLASH_WRITE_CMDID = 0x903, @@ -202,6 +217,7 @@ enum wmi_command_id { WMI_GET_THERMAL_THROTTLING_CFG_CMDID = 0x941, /* Read Power Save profile type */ WMI_PS_DEV_PROFILE_CFG_READ_CMDID = 0x942, + WMI_TSF_SYNC_CMDID = 0x973, WMI_TOF_SESSION_START_CMDID = 0x991, WMI_TOF_GET_CAPABILITIES_CMDID = 0x992, WMI_TOF_SET_LCR_CMDID = 0x993, @@ -218,11 +234,16 @@ enum wmi_command_id { WMI_PRIO_TX_SECTORS_ORDER_CMDID = 0x9A5, WMI_PRIO_TX_SECTORS_NUMBER_CMDID = 0x9A6, WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_CMDID = 0x9A7, + WMI_BF_CONTROL_CMDID = 0x9AA, WMI_SCHEDULING_SCHEME_CMDID = 0xA01, WMI_FIXED_SCHEDULING_CONFIG_CMDID = 0xA02, WMI_ENABLE_FIXED_SCHEDULING_CMDID = 0xA03, WMI_SET_MULTI_DIRECTED_OMNIS_CONFIG_CMDID = 0xA04, WMI_SET_LONG_RANGE_CONFIG_CMDID = 0xA05, + WMI_GET_ASSOC_LIST_CMDID = 0xA06, + WMI_GET_CCA_INDICATIONS_CMDID = 0xA07, + WMI_SET_CCA_INDICATIONS_BI_AVG_NUM_CMDID = 0xA08, + WMI_INTERNAL_FW_IOCTL_CMDID = 0xA0B, WMI_SET_MAC_ADDRESS_CMDID = 0xF003, WMI_ABORT_SCAN_CMDID = 0xF007, WMI_SET_PROMISCUOUS_MODE_CMDID = 0xF041, @@ -484,6 +505,18 @@ enum wmi_rf_mgmt_type { WMI_RF_MGMT_GET_STATUS = 0x02, }; +/* WMI_BF_CONTROL_CMDID */ +enum wmi_bf_triggers { + WMI_BF_TRIGGER_RS_MCS1_TH_FAILURE = 0x01, + WMI_BF_TRIGGER_RS_MCS1_NO_BACK_FAILURE = 0x02, + WMI_BF_TRIGGER_MAX_CTS_FAILURE_IN_TXOP = 0x04, + WMI_BF_TRIGGER_MAX_BACK_FAILURE = 0x08, + WMI_BF_TRIGGER_FW = 0x10, + WMI_BF_TRIGGER_MAX_CTS_FAILURE_IN_KEEP_ALIVE = 0x20, + WMI_BF_TRIGGER_AOA = 0x40, + WMI_BF_TRIGGER_MAX_CTS_FAILURE_IN_UPM = 0x80, +}; + /* WMI_RF_MGMT_CMDID */ struct wmi_rf_mgmt_cmd { __le32 rf_mgmt_type; @@ -519,7 +552,9 @@ struct wmi_bcon_ctrl_cmd { u8 disable_sec; u8 hidden_ssid; u8 is_go; - u8 reserved[2]; + /* A-BFT length override if non-0 */ + u8 abft_len; + u8 reserved; } __packed; /* WMI_PORT_ALLOCATE_CMDID */ @@ -584,6 +619,16 @@ struct wmi_power_mgmt_cfg_cmd { u8 reserved[3]; } __packed; +/* WMI_PCP_START_CMDID */ +enum wmi_ap_sme_offload_mode { + /* Full AP SME in FW */ + WMI_AP_SME_OFFLOAD_FULL = 0x00, + /* Probe AP SME in FW */ + WMI_AP_SME_OFFLOAD_PARTIAL = 0x01, + /* AP SME in host */ + WMI_AP_SME_OFFLOAD_NONE = 0x02, +}; + /* WMI_PCP_START_CMDID */ struct wmi_pcp_start_cmd { __le16 bcon_interval; @@ -593,7 +638,8 @@ struct wmi_pcp_start_cmd { u8 reserved0[5]; /* A-BFT length override if non-0 */ u8 abft_len; - u8 disable_ap_sme; + /* enum wmi_ap_sme_offload_mode_e */ + u8 ap_sme_offload_mode; u8 network_type; u8 channel; u8 disable_sec_offload; @@ -607,6 +653,17 @@ struct wmi_sw_tx_req_cmd { u8 payload[0]; } __packed; +/* WMI_VRING_SWITCH_TIMING_CONFIG_CMDID */ +struct wmi_vring_switch_timing_config_cmd { + /* Set vring timing configuration: + * + * defined interval for vring switch + */ + __le32 interval_usec; + /* vring inactivity threshold */ + __le32 idle_th_usec; +} __packed; + struct wmi_sw_ring_cfg { __le64 ring_mem_base; __le16 ring_size; @@ -642,6 +699,7 @@ enum wmi_vring_cfg_schd_params_priority { WMI_SCH_PRIO_HIGH = 0x01, }; +#define CIDXTID_EXTENDED_CID_TID (0xFF) #define CIDXTID_CID_POS (0) #define CIDXTID_CID_LEN (4) #define CIDXTID_CID_MSK (0xF) @@ -662,6 +720,9 @@ struct wmi_vring_cfg { struct wmi_sw_ring_cfg tx_sw_ring; /* 0-23 vrings */ u8 ringid; + /* Used for cid less than 8. For higher cid set + * CIDXTID_EXTENDED_CID_TID here and use cid and tid members instead + */ u8 cidxtid; u8 encap_trans_type; /* 802.3 DS cfg */ @@ -671,6 +732,11 @@ struct wmi_vring_cfg { u8 to_resolution; u8 agg_max_wsize; struct wmi_vring_cfg_schd schd_params; + /* Used when cidxtid = CIDXTID_EXTENDED_CID_TID */ + u8 cid; + /* Used when cidxtid = CIDXTID_EXTENDED_CID_TID */ + u8 tid; + u8 reserved[2]; } __packed; enum wmi_vring_cfg_cmd_action { @@ -868,23 +934,42 @@ struct wmi_cfg_rx_chain_cmd { /* WMI_RCP_ADDBA_RESP_CMDID */ struct wmi_rcp_addba_resp_cmd { + /* Used for cid less than 8. For higher cid set + * CIDXTID_EXTENDED_CID_TID here and use cid and tid members instead + */ u8 cidxtid; u8 dialog_token; __le16 status_code; /* ieee80211_ba_parameterset field to send */ __le16 ba_param_set; __le16 ba_timeout; + /* Used when cidxtid = CIDXTID_EXTENDED_CID_TID */ + u8 cid; + /* Used when cidxtid = CIDXTID_EXTENDED_CID_TID */ + u8 tid; + u8 reserved[2]; } __packed; /* WMI_RCP_DELBA_CMDID */ struct wmi_rcp_delba_cmd { + /* Used for cid less than 8. For higher cid set + * CIDXTID_EXTENDED_CID_TID here and use cid and tid members instead + */ u8 cidxtid; u8 reserved; __le16 reason; + /* Used when cidxtid = CIDXTID_EXTENDED_CID_TID */ + u8 cid; + /* Used when cidxtid = CIDXTID_EXTENDED_CID_TID */ + u8 tid; + u8 reserved2[2]; } __packed; /* WMI_RCP_ADDBA_REQ_CMDID */ struct wmi_rcp_addba_req_cmd { + /* Used for cid less than 8. For higher cid set + * CIDXTID_EXTENDED_CID_TID here and use cid and tid members instead + */ u8 cidxtid; u8 dialog_token; /* ieee80211_ba_parameterset field as it received */ @@ -892,6 +977,11 @@ struct wmi_rcp_addba_req_cmd { __le16 ba_timeout; /* ieee80211_ba_seqstrl field as it received */ __le16 ba_seq_ctrl; + /* Used when cidxtid = CIDXTID_EXTENDED_CID_TID */ + u8 cid; + /* Used when cidxtid = CIDXTID_EXTENDED_CID_TID */ + u8 tid; + u8 reserved[2]; } __packed; /* WMI_SET_MAC_ADDRESS_CMDID */ @@ -902,15 +992,20 @@ struct wmi_set_mac_address_cmd { /* WMI_ECHO_CMDID * Check FW is alive - * WMI_DEEP_ECHO_CMDID - * Check FW and ucode are alive * Returned event: WMI_ECHO_RSP_EVENTID - * same event for both commands */ struct wmi_echo_cmd { __le32 value; } __packed; +/* WMI_DEEP_ECHO_CMDID + * Check FW and ucode are alive + * Returned event: WMI_ECHO_RSP_EVENTID + */ +struct wmi_deep_echo_cmd { + __le32 value; +} __packed; + /* WMI_RF_PWR_ON_DELAY_CMDID * set FW time parameters used through RF resetting * RF reset consists of bringing its power down for a period of time, then @@ -928,7 +1023,7 @@ struct wmi_rf_pwr_on_delay_cmd { __le16 up_delay_usec; } __packed; -/* \WMI_SET_HIGH_POWER_TABLE_PARAMS_CMDID +/* WMI_SET_HIGH_POWER_TABLE_PARAMS_CMDID * This API controls the Tx and Rx gain over temperature. * It controls the Tx D-type, Rx D-type and Rx E-type amplifiers. * It also controls the Tx gain index, by controlling the Rx to Tx gain index @@ -942,25 +1037,46 @@ struct wmi_set_high_power_table_params_cmd { u8 tx_dtype_temp[WMI_RF_DTYPE_LENGTH]; u8 reserved0; /* Tx D-type values to be used for each temperature range */ - __le32 tx_dtype_conf[WMI_RF_DTYPE_LENGTH + 1]; + __le32 tx_dtype_conf[WMI_RF_DTYPE_CONF_LENGTH]; + /* Temperature range for Tx E-type parameters */ + u8 tx_etype_temp[WMI_RF_ETYPE_LENGTH]; + u8 reserved1; + /* Tx E-type values to be used for each temperature range. + * The last 4 values of any range are the first 4 values of the next + * range and so on + */ + __le32 tx_etype_conf[WMI_RF_ETYPE_CONF_LENGTH]; /* Temperature range for Rx D-type parameters */ u8 rx_dtype_temp[WMI_RF_DTYPE_LENGTH]; - u8 reserved1; + u8 reserved2; /* Rx D-type values to be used for each temperature range */ - __le32 rx_dtype_conf[WMI_RF_DTYPE_LENGTH + 1]; + __le32 rx_dtype_conf[WMI_RF_DTYPE_CONF_LENGTH]; /* Temperature range for Rx E-type parameters */ u8 rx_etype_temp[WMI_RF_ETYPE_LENGTH]; - u8 reserved2; + u8 reserved3; /* Rx E-type values to be used for each temperature range. * The last 4 values of any range are the first 4 values of the next * range and so on */ - __le32 rx_etype_conf[WMI_RF_ETYPE_VAL_PER_RANGE + WMI_RF_ETYPE_LENGTH]; + __le32 rx_etype_conf[WMI_RF_ETYPE_CONF_LENGTH]; /* Temperature range for rx_2_tx_offs parameters */ u8 rx_2_tx_temp[WMI_RF_RX2TX_LENGTH]; - u8 reserved3; + u8 reserved4; /* Rx to Tx gain index offset */ - s8 rx_2_tx_offs[WMI_RF_RX2TX_LENGTH + 1]; + s8 rx_2_tx_offs[WMI_RF_RX2TX_CONF_LENGTH]; +} __packed; + +/* WMI_FIXED_SCHEDULING_UL_CONFIG_CMDID + * This API sets rd parameter per mcs. + * Relevant only in Fixed Scheduling mode. + * Returned event: WMI_FIXED_SCHEDULING_UL_CONFIG_EVENTID + */ +struct wmi_fixed_scheduling_ul_config_cmd { + /* Use mcs -1 to set for every mcs */ + s8 mcs; + /* Number of frames with rd bit set in a single virtual slot */ + u8 rd_count_per_slot; + u8 reserved[2]; } __packed; /* CMD: WMI_RF_XPM_READ_CMDID */ @@ -1267,6 +1383,93 @@ struct wmi_set_long_range_config_complete_event { u8 reserved[3]; } __packed; +/* payload max size is 236 bytes: max event buffer size (256) - WMI headers + * (16) - prev struct field size (4) + */ +#define WMI_MAX_IOCTL_PAYLOAD_SIZE (236) +#define WMI_MAX_IOCTL_REPLY_PAYLOAD_SIZE (236) +#define WMI_MAX_INTERNAL_EVENT_PAYLOAD_SIZE (236) + +enum wmi_internal_fw_ioctl_code { + WMI_INTERNAL_FW_CODE_NONE = 0x0, + WMI_INTERNAL_FW_CODE_QCOM = 0x1, +}; + +/* WMI_INTERNAL_FW_IOCTL_CMDID */ +struct wmi_internal_fw_ioctl_cmd { + /* enum wmi_internal_fw_ioctl_code */ + __le16 code; + __le16 length; + /* payload max size is WMI_MAX_IOCTL_PAYLOAD_SIZE + * Must be the last member of the struct + */ + __le32 payload[0]; +} __packed; + +/* WMI_INTERNAL_FW_IOCTL_EVENTID */ +struct wmi_internal_fw_ioctl_event { + /* wmi_fw_status */ + u8 status; + u8 reserved; + __le16 length; + /* payload max size is WMI_MAX_IOCTL_REPLY_PAYLOAD_SIZE + * Must be the last member of the struct + */ + __le32 payload[0]; +} __packed; + +/* WMI_INTERNAL_FW_EVENT_EVENTID */ +struct wmi_internal_fw_event_event { + __le16 id; + __le16 length; + /* payload max size is WMI_MAX_INTERNAL_EVENT_PAYLOAD_SIZE + * Must be the last member of the struct + */ + __le32 payload[0]; +} __packed; + +/* WMI_BF_CONTROL_CMDID */ +struct wmi_bf_control_cmd { + /* wmi_bf_triggers */ + __le32 triggers; + u8 cid; + /* DISABLED = 0, ENABLED = 1 , DRY_RUN = 2 */ + u8 txss_mode; + /* DISABLED = 0, ENABLED = 1, DRY_RUN = 2 */ + u8 brp_mode; + /* Max cts threshold (correspond to + * WMI_BF_TRIGGER_MAX_CTS_FAILURE_IN_TXOP) + */ + u8 bf_trigger_max_cts_failure_thr; + /* Max cts threshold in dense (correspond to + * WMI_BF_TRIGGER_MAX_CTS_FAILURE_IN_TXOP) + */ + u8 bf_trigger_max_cts_failure_dense_thr; + /* Max b-ack threshold (correspond to + * WMI_BF_TRIGGER_MAX_BACK_FAILURE) + */ + u8 bf_trigger_max_back_failure_thr; + /* Max b-ack threshold in dense (correspond to + * WMI_BF_TRIGGER_MAX_BACK_FAILURE) + */ + u8 bf_trigger_max_back_failure_dense_thr; + u8 reserved0; + /* Wrong sectors threshold */ + __le32 wrong_sector_bis_thr; + /* BOOL to enable/disable long term trigger */ + u8 long_term_enable; + /* 1 = Update long term thresholds from the long_term_mbps_th_tbl and + * long_term_trig_timeout_per_mcs arrays, 0 = Ignore + */ + u8 long_term_update_thr; + /* Long term throughput threshold [Mbps] */ + u8 long_term_mbps_th_tbl[WMI_NUM_MCS]; + u8 reserved1; + /* Long term timeout threshold table [msec] */ + __le16 long_term_trig_timeout_per_mcs[WMI_NUM_MCS]; + u8 reserved2[2]; +} __packed; + /* WMI Events * List of Events (target to host) */ @@ -1325,6 +1528,7 @@ enum wmi_event_id { WMI_SET_SILENT_RSSI_TABLE_DONE_EVENTID = 0x185C, WMI_RF_PWR_ON_DELAY_RSP_EVENTID = 0x185D, WMI_SET_HIGH_POWER_TABLE_PARAMS_EVENTID = 0x185E, + WMI_FIXED_SCHEDULING_UL_CONFIG_EVENTID = 0x185F, /* Performance monitoring events */ WMI_DATA_PORT_OPEN_EVENTID = 0x1860, WMI_WBE_LINK_DOWN_EVENTID = 0x1861, @@ -1334,6 +1538,7 @@ enum wmi_event_id { WMI_VRING_EN_EVENTID = 0x1865, WMI_GET_RF_STATUS_EVENTID = 0x1866, WMI_GET_BASEBAND_TYPE_EVENTID = 0x1867, + WMI_VRING_SWITCH_TIMING_CONFIG_EVENTID = 0x1868, WMI_UNIT_TEST_EVENTID = 0x1900, WMI_FLASH_READ_DONE_EVENTID = 0x1902, WMI_FLASH_WRITE_DONE_EVENTID = 0x1903, @@ -1363,6 +1568,7 @@ enum wmi_event_id { WMI_GET_THERMAL_THROTTLING_CFG_EVENTID = 0x1941, /* return the Power Save profile */ WMI_PS_DEV_PROFILE_CFG_READ_EVENTID = 0x1942, + WMI_TSF_SYNC_STATUS_EVENTID = 0x1973, WMI_TOF_SESSION_END_EVENTID = 0x1991, WMI_TOF_GET_CAPABILITIES_EVENTID = 0x1992, WMI_TOF_SET_LCR_EVENTID = 0x1993, @@ -1380,17 +1586,24 @@ enum wmi_event_id { WMI_PRIO_TX_SECTORS_ORDER_EVENTID = 0x19A5, WMI_PRIO_TX_SECTORS_NUMBER_EVENTID = 0x19A6, WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_EVENTID = 0x19A7, + WMI_BF_CONTROL_EVENTID = 0x19AA, WMI_SCHEDULING_SCHEME_EVENTID = 0x1A01, WMI_FIXED_SCHEDULING_CONFIG_COMPLETE_EVENTID = 0x1A02, WMI_ENABLE_FIXED_SCHEDULING_COMPLETE_EVENTID = 0x1A03, WMI_SET_MULTI_DIRECTED_OMNIS_CONFIG_EVENTID = 0x1A04, WMI_SET_LONG_RANGE_CONFIG_COMPLETE_EVENTID = 0x1A05, + WMI_GET_ASSOC_LIST_RES_EVENTID = 0x1A06, + WMI_GET_CCA_INDICATIONS_EVENTID = 0x1A07, + WMI_SET_CCA_INDICATIONS_BI_AVG_NUM_EVENTID = 0x1A08, + WMI_INTERNAL_FW_EVENT_EVENTID = 0x1A0A, + WMI_INTERNAL_FW_IOCTL_EVENTID = 0x1A0B, WMI_SET_CHANNEL_EVENTID = 0x9000, WMI_ASSOC_REQ_EVENTID = 0x9001, WMI_EAPOL_RX_EVENTID = 0x9002, WMI_MAC_ADDR_RESP_EVENTID = 0x9003, WMI_FW_VER_EVENTID = 0x9004, WMI_ACS_PASSIVE_SCAN_COMPLETE_EVENTID = 0x9005, + WMI_INTERNAL_FW_SET_CHANNEL = 0x9006, WMI_COMMAND_NOT_SUPPORTED_EVENTID = 0xFFFF, }; @@ -1462,12 +1675,16 @@ enum rf_type { RF_UNKNOWN = 0x00, RF_MARLON = 0x01, RF_SPARROW = 0x02, + RF_TALYNA1 = 0x03, + RF_TALYNA2 = 0x04, }; /* WMI_GET_RF_STATUS_EVENTID */ enum board_file_rf_type { BF_RF_MARLON = 0x00, BF_RF_SPARROW = 0x01, + BF_RF_TALYNA1 = 0x02, + BF_RF_TALYNA2 = 0x03, }; /* WMI_GET_RF_STATUS_EVENTID */ @@ -1507,6 +1724,7 @@ enum baseband_type { BASEBAND_SPARROW_M_C0 = 0x06, BASEBAND_SPARROW_M_D0 = 0x07, BASEBAND_TALYN_M_A0 = 0x08, + BASEBAND_TALYN_M_B0 = 0x09, }; /* WMI_GET_BASEBAND_TYPE_EVENTID */ @@ -1551,7 +1769,11 @@ struct wmi_ready_event { u8 numof_additional_mids; /* rfc read calibration result. 5..15 */ u8 rfc_read_calib_result; - u8 reserved[3]; + /* Max associated STAs supported by FW in AP mode (default 0 means 8 + * STA) + */ + u8 max_assoc_sta; + u8 reserved[2]; } __packed; /* WMI_NOTIFY_REQ_DONE_EVENTID */ @@ -1666,13 +1888,13 @@ enum wmi_pno_result { }; struct wmi_start_sched_scan_event { - /* pno_result */ + /* wmi_pno_result */ u8 result; u8 reserved[3]; } __packed; struct wmi_stop_sched_scan_event { - /* pno_result */ + /* wmi_pno_result */ u8 result; u8 reserved[3]; } __packed; @@ -1739,9 +1961,17 @@ struct wmi_ba_status_event { /* WMI_DELBA_EVENTID */ struct wmi_delba_event { + /* Used for cid less than 8. For higher cid set + * CIDXTID_EXTENDED_CID_TID here and use cid and tid members instead + */ u8 cidxtid; u8 from_initiator; __le16 reason; + /* Used when cidxtid = CIDXTID_EXTENDED_CID_TID */ + u8 cid; + /* Used when cidxtid = CIDXTID_EXTENDED_CID_TID */ + u8 tid; + u8 reserved[2]; } __packed; /* WMI_VRING_CFG_DONE_EVENTID */ @@ -1754,13 +1984,24 @@ struct wmi_vring_cfg_done_event { /* WMI_RCP_ADDBA_RESP_SENT_EVENTID */ struct wmi_rcp_addba_resp_sent_event { + /* Used for cid less than 8. For higher cid set + * CIDXTID_EXTENDED_CID_TID here and use cid and tid members instead + */ u8 cidxtid; u8 reserved; __le16 status; + /* Used when cidxtid = CIDXTID_EXTENDED_CID_TID */ + u8 cid; + /* Used when cidxtid = CIDXTID_EXTENDED_CID_TID */ + u8 tid; + u8 reserved2[2]; } __packed; /* WMI_RCP_ADDBA_REQ_EVENTID */ struct wmi_rcp_addba_req_event { + /* Used for cid less than 8. For higher cid set + * CIDXTID_EXTENDED_CID_TID here and use cid and tid members instead + */ u8 cidxtid; u8 dialog_token; /* ieee80211_ba_parameterset as it received */ @@ -1768,6 +2009,11 @@ struct wmi_rcp_addba_req_event { __le16 ba_timeout; /* ieee80211_ba_seqstrl field as it received */ __le16 ba_seq_ctrl; + /* Used when cidxtid = CIDXTID_EXTENDED_CID_TID */ + u8 cid; + /* Used when cidxtid = CIDXTID_EXTENDED_CID_TID */ + u8 tid; + u8 reserved[2]; } __packed; /* WMI_CFG_RX_CHAIN_DONE_EVENTID */ @@ -1942,6 +2188,13 @@ struct wmi_set_high_power_table_params_event { u8 reserved[3]; } __packed; +/* WMI_FIXED_SCHEDULING_UL_CONFIG_EVENTID */ +struct wmi_fixed_scheduling_ul_config_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + /* WMI_TEMP_SENSE_DONE_EVENTID * * Measure MAC and radio temperatures @@ -2290,6 +2543,8 @@ struct wmi_link_maintain_cfg { __le32 bad_beacons_num_threshold; /* SNR limit for bad_beacons_detector */ __le32 bad_beacons_snr_threshold_db; + /* timeout for disassoc response frame in uSec */ + __le32 disconnect_timeout; } __packed; /* WMI_LINK_MAINTAIN_CFG_WRITE_CMDID */ @@ -2519,6 +2774,7 @@ enum wmi_tof_session_end_status { WMI_TOF_SESSION_END_FAIL = 0x01, WMI_TOF_SESSION_END_PARAMS_ERROR = 0x02, WMI_TOF_SESSION_END_ABORTED = 0x03, + WMI_TOF_SESSION_END_BUSY = 0x04, }; /* WMI_TOF_SESSION_END_EVENTID */ @@ -2925,7 +3181,40 @@ struct wmi_set_silent_rssi_table_done_event { __le32 table; } __packed; -/* \WMI_COMMAND_NOT_SUPPORTED_EVENTID */ +/* WMI_VRING_SWITCH_TIMING_CONFIG_EVENTID */ +struct wmi_vring_switch_timing_config_event { + /* enum wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_GET_ASSOC_LIST_RES_EVENTID */ +struct wmi_assoc_sta_info { + u8 mac[WMI_MAC_LEN]; + u8 omni_index_address; + u8 reserved; +} __packed; + +#define WMI_GET_ASSOC_LIST_SIZE (8) + +/* WMI_GET_ASSOC_LIST_RES_EVENTID + * Returns up to MAX_ASSOC_STA_LIST_SIZE associated STAs + */ +struct wmi_get_assoc_list_res_event { + struct wmi_assoc_sta_info assoc_sta_list[WMI_GET_ASSOC_LIST_SIZE]; + /* STA count */ + u8 count; + u8 reserved[3]; +} __packed; + +/* WMI_BF_CONTROL_EVENTID */ +struct wmi_bf_control_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_COMMAND_NOT_SUPPORTED_EVENTID */ struct wmi_command_not_supported_event { /* device id */ u8 mid; @@ -2936,4 +3225,62 @@ struct wmi_command_not_supported_event { __le16 reserved1; } __packed; +/* WMI_TSF_SYNC_CMDID */ +struct wmi_tsf_sync_cmd { + /* The time interval to send announce frame in one BI */ + u8 interval_ms; + /* The mcs to send announce frame */ + u8 mcs; + u8 reserved[6]; +} __packed; + +/* WMI_TSF_SYNC_STATUS_EVENTID */ +enum wmi_tsf_sync_status { + WMI_TSF_SYNC_SUCCESS = 0x00, + WMI_TSF_SYNC_FAILED = 0x01, + WMI_TSF_SYNC_REJECTED = 0x02, +}; + +/* WMI_TSF_SYNC_STATUS_EVENTID */ +struct wmi_tsf_sync_status_event { + /* enum wmi_tsf_sync_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_GET_CCA_INDICATIONS_EVENTID */ +struct wmi_get_cca_indications_event { + /* wmi_fw_status */ + u8 status; + /* CCA-Energy Detect in percentage over last BI (0..100) */ + u8 cca_ed_percent; + /* Averaged CCA-Energy Detect in percent over number of BIs (0..100) */ + u8 cca_ed_avg_percent; + /* NAV percent over last BI (0..100) */ + u8 nav_percent; + /* Averaged NAV percent over number of BIs (0..100) */ + u8 nav_avg_percent; + u8 reserved[3]; +} __packed; + +/* WMI_SET_CCA_INDICATIONS_BI_AVG_NUM_CMDID */ +struct wmi_set_cca_indications_bi_avg_num_cmd { + /* set the number of bis to average cca_ed (0..255) */ + u8 bi_number; + u8 reserved[3]; +} __packed; + +/* WMI_SET_CCA_INDICATIONS_BI_AVG_NUM_EVENTID */ +struct wmi_set_cca_indications_bi_avg_num_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_INTERNAL_FW_SET_CHANNEL */ +struct wmi_internal_fw_set_channel_event { + u8 channel_num; + u8 reserved[3]; +} __packed; + #endif /* __WILOCITY_WMI_H__ */ -- cgit v1.2.3 From 9861bf3b818fbe810442b89230b80c0385ef9e04 Mon Sep 17 00:00:00 2001 From: Lior David Date: Wed, 9 May 2018 13:06:54 +0300 Subject: wil6210: fix call to wil6210_disconnect during unload Move the call to wil6210_disconnect so it will be called before unregister_netdevice. This is because it calls netif_carrier_off which is forbidden to call on an unregistered net device. Calling netif_carrier_off can add a link watch event which might be handled after net device was freed, causing a kernel oops. Signed-off-by: Lior David Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/netdev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 05e9408e7ea3..eb6c14ed65a4 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -457,16 +457,16 @@ void wil_vif_remove(struct wil6210_priv *wil, u8 mid) return; } + mutex_lock(&wil->mutex); + wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING, false); + mutex_unlock(&wil->mutex); + ndev = vif_to_ndev(vif); /* during unregister_netdevice cfg80211_leave may perform operations * such as stop AP, disconnect, so we only clear the VIF afterwards */ unregister_netdevice(ndev); - mutex_lock(&wil->mutex); - wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING, false); - mutex_unlock(&wil->mutex); - if (any_active && vif->mid != 0) wmi_port_delete(wil, vif->mid); -- cgit v1.2.3 From 5f85c7e702d2185d3d553982f916b5ac96ae77a9 Mon Sep 17 00:00:00 2001 From: Lior David Date: Wed, 9 May 2018 13:06:55 +0300 Subject: wil6210: change reply_size arg to u16 in wmi_call Change the type of the argument reply_size from u8 to u16 in order to support reply sizes > 255 bytes. The driver already supports u16 reply size in all other places, this was the only missing change. Signed-off-by: Lior David Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wil6210.h | 2 +- drivers/net/wireless/ath/wil6210/wmi.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index f9c5155025bc..9ac92921d47c 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -986,7 +986,7 @@ int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr, int wmi_send(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len); void wmi_recv_cmd(struct wil6210_priv *wil); int wmi_call(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len, - u16 reply_id, void *reply, u8 reply_size, int to_msec); + u16 reply_id, void *reply, u16 reply_size, int to_msec); void wmi_event_worker(struct work_struct *work); void wmi_event_flush(struct wil6210_priv *wil); int wmi_set_ssid(struct wil6210_vif *vif, u8 ssid_len, const void *ssid); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 73efa13bc742..fcd95299eb4f 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1416,7 +1416,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil) } int wmi_call(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len, - u16 reply_id, void *reply, u8 reply_size, int to_msec) + u16 reply_id, void *reply, u16 reply_size, int to_msec) { int rc; unsigned long remain; -- cgit v1.2.3 From 1c21cc5fc4df4997eddc6e0b5c5bad225c3f1ecc Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Wed, 9 May 2018 13:06:56 +0300 Subject: wil6210: move WMI functionality out of wil_cfg80211_mgmt_tx Rearrange the code by having new function wmi_mgmt_tx() to take care of the WMI part of wil_cfg80211_mgmt_tx(). Signed-off-by: Dedy Lansky Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 39 +++--------------------- drivers/net/wireless/ath/wil6210/wil6210.h | 1 + drivers/net/wireless/ath/wil6210/wmi.c | 47 +++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 35 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index cdbb393863f3..109bae1436db 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1081,17 +1081,11 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, u64 *cookie) { const u8 *buf = params->buf; - size_t len = params->len, total; + size_t len = params->len; struct wil6210_priv *wil = wiphy_to_wil(wiphy); struct wil6210_vif *vif = wdev_to_vif(wil, wdev); int rc; - bool tx_status = false; - struct ieee80211_mgmt *mgmt_frame = (void *)buf; - struct wmi_sw_tx_req_cmd *cmd; - struct { - struct wmi_cmd_hdr wmi; - struct wmi_sw_tx_complete_event evt; - } __packed evt; + bool tx_status; /* Note, currently we do not support the "wait" parameter, user-space * must call remain_on_channel before mgmt_tx or listen on a channel @@ -1100,34 +1094,9 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, * different from currently "listened" channel and fail if it is. */ - wil_dbg_misc(wil, "mgmt_tx mid %d\n", vif->mid); - wil_hex_dump_misc("mgmt tx frame ", DUMP_PREFIX_OFFSET, 16, 1, buf, - len, true); - - if (len < sizeof(struct ieee80211_hdr_3addr)) - return -EINVAL; - - total = sizeof(*cmd) + len; - if (total < len) - return -EINVAL; - - cmd = kmalloc(total, GFP_KERNEL); - if (!cmd) { - rc = -ENOMEM; - goto out; - } - - memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN); - cmd->len = cpu_to_le16(len); - memcpy(cmd->payload, buf, len); - - rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, vif->mid, cmd, total, - WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); - if (rc == 0) - tx_status = !evt.evt.status; + rc = wmi_mgmt_tx(vif, buf, len); + tx_status = (rc == 0); - kfree(cmd); - out: cfg80211_mgmt_tx_status(wdev, cookie ? *cookie : 0, buf, len, tx_status, GFP_KERNEL); return rc; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 9ac92921d47c..c9120dc8a435 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1150,5 +1150,6 @@ void wil6210_clear_halp(struct wil6210_priv *wil); int wmi_start_sched_scan(struct wil6210_priv *wil, struct cfg80211_sched_scan_request *request); int wmi_stop_sched_scan(struct wil6210_priv *wil); +int wmi_mgmt_tx(struct wil6210_vif *vif, const u8 *buf, size_t len); #endif /* __WIL6210_H__ */ diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index fcd95299eb4f..bf110e3b4477 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -2773,3 +2773,50 @@ int wmi_stop_sched_scan(struct wil6210_priv *wil) return 0; } + +int wmi_mgmt_tx(struct wil6210_vif *vif, const u8 *buf, size_t len) +{ + size_t total; + struct wil6210_priv *wil = vif_to_wil(vif); + struct ieee80211_mgmt *mgmt_frame = (void *)buf; + struct wmi_sw_tx_req_cmd *cmd; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_sw_tx_complete_event evt; + } __packed evt = { + .evt = {.status = WMI_FW_STATUS_FAILURE}, + }; + int rc; + + wil_dbg_misc(wil, "mgmt_tx mid %d\n", vif->mid); + wil_hex_dump_misc("mgmt tx frame ", DUMP_PREFIX_OFFSET, 16, 1, buf, + len, true); + + if (len < sizeof(struct ieee80211_hdr_3addr)) + return -EINVAL; + + total = sizeof(*cmd) + len; + if (total < len) { + wil_err(wil, "mgmt_tx invalid len %zu\n", len); + return -EINVAL; + } + + cmd = kmalloc(total, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN); + cmd->len = cpu_to_le16(len); + memcpy(cmd->payload, buf, len); + + rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, vif->mid, cmd, total, + WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); + if (!rc && evt.evt.status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "mgmt_tx failed with status %d\n", evt.evt.status); + rc = -EINVAL; + } + + kfree(cmd); + + return rc; +} -- cgit v1.2.3 From 807b086053df9bdbc9bf732130e9acda1c161aa5 Mon Sep 17 00:00:00 2001 From: Alexei Avshalom Lazar Date: Wed, 9 May 2018 13:06:57 +0300 Subject: wil6210: Initialize reply struct of the WMI commands WMI command reply saved in uninitialized struct. In order to avoid accessing unset values from FW initialize the reply struct. Signed-off-by: Alexei Avshalom Lazar Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 22 ++++--- drivers/net/wireless/ath/wil6210/debugfs.c | 2 + drivers/net/wireless/ath/wil6210/main.c | 2 + drivers/net/wireless/ath/wil6210/txrx.c | 8 ++- drivers/net/wireless/ath/wil6210/wmi.c | 97 ++++++++++++++++++----------- 5 files changed, 85 insertions(+), 46 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 109bae1436db..78946f28d0c7 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -276,6 +276,8 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid, struct wil_net_stats *stats = &wil->sta[cid].stats; int rc; + memset(&reply, 0, sizeof(reply)); + rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20); if (rc) @@ -2246,7 +2248,9 @@ static int wil_rf_sector_get_cfg(struct wiphy *wiphy, struct { struct wmi_cmd_hdr wmi; struct wmi_get_rf_sector_params_done_event evt; - } __packed reply; + } __packed reply = { + .evt = {.status = WMI_RF_SECTOR_STATUS_NOT_SUPPORTED_ERROR}, + }; struct sk_buff *msg; struct nlattr *nl_cfgs, *nl_cfg; u32 i; @@ -2292,7 +2296,6 @@ static int wil_rf_sector_get_cfg(struct wiphy *wiphy, cmd.sector_idx = cpu_to_le16(sector_index); cmd.sector_type = sector_type; cmd.rf_modules_vec = rf_modules_vec & 0xFF; - memset(&reply, 0, sizeof(reply)); rc = wmi_call(wil, WMI_GET_RF_SECTOR_PARAMS_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID, &reply, sizeof(reply), @@ -2367,7 +2370,9 @@ static int wil_rf_sector_set_cfg(struct wiphy *wiphy, struct { struct wmi_cmd_hdr wmi; struct wmi_set_rf_sector_params_done_event evt; - } __packed reply; + } __packed reply = { + .evt = {.status = WMI_RF_SECTOR_STATUS_NOT_SUPPORTED_ERROR}, + }; struct nlattr *nl_cfg; struct wmi_rf_sector_info *si; @@ -2450,7 +2455,6 @@ static int wil_rf_sector_set_cfg(struct wiphy *wiphy, } cmd.rf_modules_vec = rf_modules_vec & 0xFF; - memset(&reply, 0, sizeof(reply)); rc = wmi_call(wil, WMI_SET_RF_SECTOR_PARAMS_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID, &reply, sizeof(reply), @@ -2474,7 +2478,9 @@ static int wil_rf_sector_get_selected(struct wiphy *wiphy, struct { struct wmi_cmd_hdr wmi; struct wmi_get_selected_rf_sector_index_done_event evt; - } __packed reply; + } __packed reply = { + .evt = {.status = WMI_RF_SECTOR_STATUS_NOT_SUPPORTED_ERROR}, + }; struct sk_buff *msg; if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities)) @@ -2514,7 +2520,6 @@ static int wil_rf_sector_get_selected(struct wiphy *wiphy, memset(&cmd, 0, sizeof(cmd)); cmd.cid = (u8)cid; cmd.sector_type = sector_type; - memset(&reply, 0, sizeof(reply)); rc = wmi_call(wil, WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID, @@ -2555,14 +2560,15 @@ static int wil_rf_sector_wmi_set_selected(struct wil6210_priv *wil, struct { struct wmi_cmd_hdr wmi; struct wmi_set_selected_rf_sector_index_done_event evt; - } __packed reply; + } __packed reply = { + .evt = {.status = WMI_RF_SECTOR_STATUS_NOT_SUPPORTED_ERROR}, + }; int rc; memset(&cmd, 0, sizeof(cmd)); cmd.sector_idx = cpu_to_le16(sector_index); cmd.sector_type = sector_type; cmd.cid = (u8)cid; - memset(&reply, 0, sizeof(reply)); rc = wmi_call(wil, WMI_SET_SELECTED_RF_SECTOR_INDEX_CMDID, mid, &cmd, sizeof(cmd), WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID, diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 8c90b3111f0b..d3b1069ebf7a 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1078,6 +1078,8 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data) struct wmi_notify_req_done_event evt; } __packed reply; + memset(&reply, 0, sizeof(reply)); + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { u32 status; diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 82aec6b06d09..e7006c2428a0 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -342,6 +342,8 @@ void wil_disconnect_worker(struct work_struct *work) /* already disconnected */ return; + memset(&reply, 0, sizeof(reply)); + rc = wmi_call(wil, WMI_DISCONNECT_CMDID, vif->mid, NULL, 0, WMI_DISCONNECT_EVENTID, &reply, sizeof(reply), WIL6210_DISCONNECT_TO_MS); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index b60b9fcaaebd..411130a4f2ed 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -963,7 +963,9 @@ int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size, struct { struct wmi_cmd_hdr wmi; struct wmi_vring_cfg_done_event cmd; - } __packed reply; + } __packed reply = { + .cmd = {.status = WMI_FW_STATUS_FAILURE}, + }; struct vring *vring = &wil->vring_tx[id]; struct vring_tx_data *txdata = &wil->vring_tx_data[id]; @@ -1045,7 +1047,9 @@ int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size) struct { struct wmi_cmd_hdr wmi; struct wmi_vring_cfg_done_event cmd; - } __packed reply; + } __packed reply = { + .cmd = {.status = WMI_FW_STATUS_FAILURE}, + }; struct vring *vring = &wil->vring_tx[id]; struct vring_tx_data *txdata = &wil->vring_tx_data[id]; diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index bf110e3b4477..8a9bbd6bcea8 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1509,7 +1509,9 @@ int wmi_led_cfg(struct wil6210_priv *wil, bool enable) struct { struct wmi_cmd_hdr wmi; struct wmi_led_cfg_done_event evt; - } __packed reply; + } __packed reply = { + .evt = {.status = cpu_to_le32(WMI_FW_STATUS_FAILURE)}, + }; if (led_id == WIL_LED_INVALID_ID) goto out; @@ -1562,7 +1564,9 @@ int wmi_pcp_start(struct wil6210_vif *vif, struct { struct wmi_cmd_hdr wmi; struct wmi_pcp_started_event evt; - } __packed reply; + } __packed reply = { + .evt = {.status = WMI_FW_STATUS_FAILURE}, + }; if (!vif->privacy) cmd.disable_sec = 1; @@ -1639,6 +1643,8 @@ int wmi_get_ssid(struct wil6210_vif *vif, u8 *ssid_len, void *ssid) } __packed reply; int len; /* reply.cmd.ssid_len in CPU order */ + memset(&reply, 0, sizeof(reply)); + rc = wmi_call(wil, WMI_GET_SSID_CMDID, vif->mid, NULL, 0, WMI_GET_SSID_EVENTID, &reply, sizeof(reply), 20); if (rc) @@ -1674,6 +1680,8 @@ int wmi_get_channel(struct wil6210_priv *wil, int *channel) struct wmi_set_pcp_channel_cmd cmd; } __packed reply; + memset(&reply, 0, sizeof(reply)); + rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, vif->mid, NULL, 0, WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply), 20); if (rc) @@ -1699,7 +1707,9 @@ int wmi_p2p_cfg(struct wil6210_vif *vif, int channel, int bi) struct { struct wmi_cmd_hdr wmi; struct wmi_p2p_cfg_done_event evt; - } __packed reply; + } __packed reply = { + .evt = {.status = WMI_FW_STATUS_FAILURE}, + }; wil_dbg_wmi(wil, "sending WMI_P2P_CFG_CMDID\n"); @@ -1720,7 +1730,9 @@ int wmi_start_listen(struct wil6210_vif *vif) struct { struct wmi_cmd_hdr wmi; struct wmi_listen_started_event evt; - } __packed reply; + } __packed reply = { + .evt = {.status = WMI_FW_STATUS_FAILURE}, + }; wil_dbg_wmi(wil, "sending WMI_START_LISTEN_CMDID\n"); @@ -1742,7 +1754,9 @@ int wmi_start_search(struct wil6210_vif *vif) struct { struct wmi_cmd_hdr wmi; struct wmi_search_started_event evt; - } __packed reply; + } __packed reply = { + .evt = {.status = WMI_FW_STATUS_FAILURE}, + }; wil_dbg_wmi(wil, "sending WMI_START_SEARCH_CMDID\n"); @@ -1868,7 +1882,9 @@ int wmi_rxon(struct wil6210_priv *wil, bool on) struct { struct wmi_cmd_hdr wmi; struct wmi_listen_started_event evt; - } __packed reply; + } __packed reply = { + .evt = {.status = WMI_FW_STATUS_FAILURE}, + }; wil_info(wil, "(%s)\n", on ? "on" : "off"); @@ -1910,6 +1926,8 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) } __packed evt; int rc; + memset(&evt, 0, sizeof(evt)); + if (wdev->iftype == NL80211_IFTYPE_MONITOR) { struct ieee80211_channel *ch = wil->monitor_chandef.chan; @@ -1939,14 +1957,14 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) if (rc) return rc; + if (le32_to_cpu(evt.evt.status) != WMI_CFG_RX_CHAIN_SUCCESS) + rc = -EINVAL; + vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr); wil_dbg_misc(wil, "Rx init: status %d tail 0x%08x\n", le32_to_cpu(evt.evt.status), vring->hwtail); - if (le32_to_cpu(evt.evt.status) != WMI_CFG_RX_CHAIN_SUCCESS) - rc = -EINVAL; - return rc; } @@ -1964,6 +1982,8 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf) struct wmi_temp_sense_done_event evt; } __packed reply; + memset(&reply, 0, sizeof(reply)); + rc = wmi_call(wil, WMI_TEMP_SENSE_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_TEMP_SENSE_DONE_EVENTID, &reply, sizeof(reply), 100); if (rc) @@ -1996,6 +2016,7 @@ int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac, wil_dbg_wmi(wil, "disconnect_sta: (%pM, reason %d)\n", mac, reason); + memset(&reply, 0, sizeof(reply)); vif->locally_generated_disc = true; if (del_sta) { ether_addr_copy(del_sta_cmd.dst_mac, mac); @@ -2094,7 +2115,9 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil, struct { struct wmi_cmd_hdr wmi; struct wmi_rcp_addba_resp_sent_event evt; - } __packed reply; + } __packed reply = { + .evt = {.status = cpu_to_le16(WMI_FW_STATUS_FAILURE)}, + }; wil_dbg_wmi(wil, "ADDBA response for MID %d CID %d TID %d size %d timeout %d status %d AMSDU%s\n", @@ -2127,13 +2150,13 @@ int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil, struct { struct wmi_cmd_hdr wmi; struct wmi_ps_dev_profile_cfg_event evt; - } __packed reply; + } __packed reply = { + .evt = {.status = cpu_to_le32(WMI_PS_CFG_CMD_STATUS_ERROR)}, + }; u32 status; wil_dbg_wmi(wil, "Setting ps dev profile %d\n", ps_profile); - reply.evt.status = cpu_to_le32(WMI_PS_CFG_CMD_STATUS_ERROR); - rc = wmi_call(wil, WMI_PS_DEV_PROFILE_CFG_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_PS_DEV_PROFILE_CFG_EVENTID, &reply, sizeof(reply), @@ -2162,15 +2185,15 @@ int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short) struct { struct wmi_cmd_hdr wmi; struct wmi_set_mgmt_retry_limit_event evt; - } __packed reply; + } __packed reply = { + .evt = {.status = WMI_FW_STATUS_FAILURE}, + }; wil_dbg_wmi(wil, "Setting mgmt retry short %d\n", retry_short); if (!test_bit(WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT, wil->fw_capabilities)) return -ENOTSUPP; - reply.evt.status = WMI_FW_STATUS_FAILURE; - rc = wmi_call(wil, WMI_SET_MGMT_RETRY_LIMIT_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_SET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply), @@ -2201,7 +2224,7 @@ int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short) if (!test_bit(WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT, wil->fw_capabilities)) return -ENOTSUPP; - reply.evt.mgmt_retry_limit = 0; + memset(&reply, 0, sizeof(reply)); rc = wmi_call(wil, WMI_GET_MGMT_RETRY_LIMIT_CMDID, vif->mid, NULL, 0, WMI_GET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply), 100); @@ -2284,14 +2307,15 @@ int wmi_suspend(struct wil6210_priv *wil) struct { struct wmi_cmd_hdr wmi; struct wmi_traffic_suspend_event evt; - } __packed reply; + } __packed reply = { + .evt = {.status = WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE}, + }; + u32 suspend_to = WIL_WAIT_FOR_SUSPEND_RESUME_COMP; wil->suspend_resp_rcvd = false; wil->suspend_resp_comp = false; - reply.evt.status = WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE; - rc = wmi_call(wil, WMI_TRAFFIC_SUSPEND_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_TRAFFIC_SUSPEND_EVENTID, &reply, sizeof(reply), @@ -2367,10 +2391,11 @@ int wmi_resume(struct wil6210_priv *wil) struct { struct wmi_cmd_hdr wmi; struct wmi_traffic_resume_event evt; - } __packed reply; - - reply.evt.status = WMI_TRAFFIC_RESUME_FAILED; - reply.evt.resume_triggers = WMI_RESUME_TRIGGER_UNKNOWN; + } __packed reply = { + .evt = {.status = WMI_TRAFFIC_RESUME_FAILED, + .resume_triggers = + cpu_to_le32(WMI_RESUME_TRIGGER_UNKNOWN)}, + }; rc = wmi_call(wil, WMI_TRAFFIC_RESUME_CMDID, vif->mid, NULL, 0, WMI_TRAFFIC_RESUME_EVENTID, &reply, sizeof(reply), @@ -2396,7 +2421,9 @@ int wmi_port_allocate(struct wil6210_priv *wil, u8 mid, struct { struct wmi_cmd_hdr wmi; struct wmi_port_allocated_event evt; - } __packed reply; + } __packed reply = { + .evt = {.status = WMI_FW_STATUS_FAILURE}, + }; wil_dbg_misc(wil, "port allocate, mid %d iftype %d, mac %pM\n", mid, iftype, mac); @@ -2421,8 +2448,6 @@ int wmi_port_allocate(struct wil6210_priv *wil, u8 mid, return -EINVAL; } - reply.evt.status = WMI_FW_STATUS_FAILURE; - rc = wmi_call(wil, WMI_PORT_ALLOCATE_CMDID, mid, &cmd, sizeof(cmd), WMI_PORT_ALLOCATED_EVENTID, &reply, @@ -2449,12 +2474,12 @@ int wmi_port_delete(struct wil6210_priv *wil, u8 mid) struct { struct wmi_cmd_hdr wmi; struct wmi_port_deleted_event evt; - } __packed reply; + } __packed reply = { + .evt = {.status = WMI_FW_STATUS_FAILURE}, + }; wil_dbg_misc(wil, "port delete, mid %d\n", mid); - reply.evt.status = WMI_FW_STATUS_FAILURE; - rc = wmi_call(wil, WMI_PORT_DELETE_CMDID, mid, &cmd, sizeof(cmd), WMI_PORT_DELETED_EVENTID, &reply, @@ -2711,7 +2736,9 @@ int wmi_start_sched_scan(struct wil6210_priv *wil, struct { struct wmi_cmd_hdr wmi; struct wmi_start_sched_scan_event evt; - } __packed reply; + } __packed reply = { + .evt = {.result = WMI_PNO_REJECT}, + }; if (!test_bit(WMI_FW_CAPABILITY_PNO, wil->fw_capabilities)) return -ENOTSUPP; @@ -2727,8 +2754,6 @@ int wmi_start_sched_scan(struct wil6210_priv *wil, wmi_sched_scan_set_plans(wil, &cmd, request->scan_plans, request->n_scan_plans); - reply.evt.result = WMI_PNO_REJECT; - rc = wmi_call(wil, WMI_START_SCHED_SCAN_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_START_SCHED_SCAN_EVENTID, &reply, sizeof(reply), @@ -2752,13 +2777,13 @@ int wmi_stop_sched_scan(struct wil6210_priv *wil) struct { struct wmi_cmd_hdr wmi; struct wmi_stop_sched_scan_event evt; - } __packed reply; + } __packed reply = { + .evt = {.result = WMI_PNO_REJECT}, + }; if (!test_bit(WMI_FW_CAPABILITY_PNO, wil->fw_capabilities)) return -ENOTSUPP; - reply.evt.result = WMI_PNO_REJECT; - rc = wmi_call(wil, WMI_STOP_SCHED_SCAN_CMDID, vif->mid, NULL, 0, WMI_STOP_SCHED_SCAN_EVENTID, &reply, sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS); -- cgit v1.2.3 From 37f8d26d8347f659e4677b4e438708ce492262bf Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Wed, 9 May 2018 13:06:58 +0300 Subject: wil6210: remove unused rx_reorder members Remove unused members from struct wil_tid_ampdu_rx Signed-off-by: Dedy Lansky Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 3 +-- drivers/net/wireless/ath/wil6210/rx_reorder.c | 7 +------ drivers/net/wireless/ath/wil6210/wil6210.h | 10 ---------- 3 files changed, 2 insertions(+), 18 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index d3b1069ebf7a..524a7d689833 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1379,8 +1379,7 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size; unsigned long long drop_dup = r->drop_dup, drop_old = r->drop_old; - seq_printf(s, "([%2d] %3d TU) 0x%03x [", r->buf_size, r->timeout, - r->head_seq_num); + seq_printf(s, "([%2d]) 0x%03x [", r->buf_size, r->head_seq_num); for (i = 0; i < r->buf_size; i++) { if (i == index) seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|'); diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 14dcb0698dee..76f8084c1fd8 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -206,7 +206,6 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) /* put the frame in the reordering buffer */ r->reorder_buf[index] = skb; - r->reorder_time[index] = jiffies; r->stored_mpdu_num++; wil_reorder_release(ndev, r); @@ -252,11 +251,8 @@ struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, r->reorder_buf = kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL); - r->reorder_time = - kcalloc(size, sizeof(unsigned long), GFP_KERNEL); - if (!r->reorder_buf || !r->reorder_time) { + if (!r->reorder_buf) { kfree(r->reorder_buf); - kfree(r->reorder_time); kfree(r); return NULL; } @@ -286,7 +282,6 @@ void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, kfree_skb(r->reorder_buf[i]); kfree(r->reorder_buf); - kfree(r->reorder_time); kfree(r); } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index c9120dc8a435..b623510c6f6c 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -493,38 +493,28 @@ struct pci_dev; * struct tid_ampdu_rx - TID aggregation information (Rx). * * @reorder_buf: buffer to reorder incoming aggregated MPDUs - * @reorder_time: jiffies when skb was added - * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) - * @reorder_timer: releases expired frames from the reorder buffer. * @last_rx: jiffies of last rx activity * @head_seq_num: head sequence number in reordering buffer. * @stored_mpdu_num: number of MPDUs in reordering buffer * @ssn: Starting Sequence Number expected to be aggregated. * @buf_size: buffer size for incoming A-MPDUs - * @timeout: reset timer value (in TUs). * @ssn_last_drop: SSN of the last dropped frame * @total: total number of processed incoming frames * @drop_dup: duplicate frames dropped for this reorder buffer * @drop_old: old frames dropped for this reorder buffer - * @dialog_token: dialog token for aggregation session * @first_time: true when this buffer used 1-st time */ struct wil_tid_ampdu_rx { struct sk_buff **reorder_buf; - unsigned long *reorder_time; - struct timer_list session_timer; - struct timer_list reorder_timer; unsigned long last_rx; u16 head_seq_num; u16 stored_mpdu_num; u16 ssn; u16 buf_size; - u16 timeout; u16 ssn_last_drop; unsigned long long total; /* frames processed */ unsigned long long drop_dup; unsigned long long drop_old; - u8 dialog_token; bool first_time; /* is it 1-st time this buffer used? */ }; -- cgit v1.2.3 From 3d6b72729cc2933906de8d2c602ae05e920b2122 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Wed, 9 May 2018 13:06:59 +0300 Subject: wil6210: rate limit wil_rx_refill error wil_err inside wil_rx_refill can flood the log buffer. Replace it with wil_err_ratelimited. Signed-off-by: Dedy Lansky Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/txrx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 411130a4f2ed..b9a9fa828961 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -652,8 +652,8 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count) v->swtail = next_tail) { rc = wil_vring_alloc_skb(wil, v, v->swtail, headroom); if (unlikely(rc)) { - wil_err(wil, "Error %d in wil_rx_refill[%d]\n", - rc, v->swtail); + wil_err_ratelimited(wil, "Error %d in rx refill[%d]\n", + rc, v->swtail); break; } } -- cgit v1.2.3 From 1204aa17f3b4f63e67ac9b7c9afa9496485969c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 10 May 2018 15:21:39 +0200 Subject: brcmfmac: set WIPHY_FLAG_HAVE_AP_SME flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit brcmfmac is a FullMAC driver and it implements/uses cfg80211 interface for stations management. At the same time it doesn't receive or pass up management frames. This flag indicates that authenticator doesn't have to subscribe to or handle management frames. Some authenticators (e.g. hostapd) were working with brcmfmac thanks to some extra assumptions. This commit clears up the situation. Signed-off-by: RafaÅ‚ MiÅ‚ecki Acked-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 79a124d1aa23..84135dac49b3 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -6518,6 +6518,7 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) wiphy->flags |= WIPHY_FLAG_NETNS_OK | WIPHY_FLAG_PS_ON_BY_DEFAULT | + WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_OFFCHAN_TX | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) -- cgit v1.2.3 From 54b5172087aeae61150835c91e68f084a9644f1c Mon Sep 17 00:00:00 2001 From: Sanjay Kumar Konduri Date: Fri, 11 May 2018 20:27:51 +0530 Subject: rsi: Add null check for virtual interfaces in wowlan config When the "poweroff" command is executed after wowlan enabled, we have observed a system crash. In the system "poweroff" sequence, network-manager is sent to inactive state by cleaning up the network interfaces, using rsi_mac80211_remove_interface() and when driver tries to access those network interfaces in rsi_wowlan_config() which was invoked by SDIO shutdown, results in a crash. Added a NULL check before accessing the network interfaces in rsi_wowlan_config(). Signed-off-by: Sanjay Kumar Konduri Signed-off-by: Siva Rebbagondla Signed-off-by: Sushant Kumar Mishra Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 80e7f4f4f188..743706eeffa2 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -1804,10 +1804,15 @@ int rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan) struct rsi_common *common = adapter->priv; u16 triggers = 0; u16 rx_filter_word = 0; - struct ieee80211_bss_conf *bss = &adapter->vifs[0]->bss_conf; + struct ieee80211_bss_conf *bss = NULL; rsi_dbg(INFO_ZONE, "Config WoWLAN to device\n"); + if (!adapter->vifs[0]) + return -EINVAL; + + bss = &adapter->vifs[0]->bss_conf; + if (WARN_ON(!wowlan)) { rsi_dbg(ERR_ZONE, "WoW triggers not enabled\n"); return -EINVAL; -- cgit v1.2.3 From d76f8513fa9050b6fff477beb453828e5024ef4b Mon Sep 17 00:00:00 2001 From: Siva Rebbagondla Date: Fri, 11 May 2018 20:27:52 +0530 Subject: rsi: reset hibernate_resume flag to work hibernate resume in coex mode. In coex mode, observed hibernate resume is not working properly, as the hibernate_resume flag is not getting reset in rsi_coex_recv_pkt(), when common card ready indication received from firmware. Hence resetting hibernate_resume flag in this function. Signed-off-by: Siva Rebbagondla Signed-off-by: Sushant Kumar Mishra Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_coex.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_coex.c b/drivers/net/wireless/rsi/rsi_91x_coex.c index d055099dadf1..c8ba148f8c6c 100644 --- a/drivers/net/wireless/rsi/rsi_91x_coex.c +++ b/drivers/net/wireless/rsi/rsi_91x_coex.c @@ -73,6 +73,7 @@ int rsi_coex_recv_pkt(struct rsi_common *common, u8 *msg) switch (msg_type) { case COMMON_CARD_READY_IND: rsi_dbg(INFO_ZONE, "common card ready received\n"); + common->hibernate_resume = false; rsi_handle_card_ready(common, msg); break; case SLEEP_NOTIFY_IND: -- cgit v1.2.3 From 1d18c5584c05bb059a0ce2fca5bf3c523d6fa4d2 Mon Sep 17 00:00:00 2001 From: Siva Rebbagondla Date: Fri, 11 May 2018 20:27:53 +0530 Subject: rsi: Set wowlan flag while writing wowlan config parameters As wowlan enable flag did not set, while writing wowlan parameters to card using rsi_send_vap_dynamic_update, which results firmware is unable to set wowlan configurations. Hence, setting wowlan flag before sending parameters. Signed-off-by: Siva Rebbagondla Signed-off-by: Sushant Kumar Mishra Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 743706eeffa2..3faa0449a5ef 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -1818,6 +1818,7 @@ int rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan) return -EINVAL; } + common->wow_flags |= RSI_WOW_ENABLED; triggers = rsi_wow_map_triggers(common, wowlan); if (!triggers) { rsi_dbg(ERR_ZONE, "%s:No valid WoW triggers\n", __func__); @@ -1840,7 +1841,6 @@ int rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan) rx_filter_word = (ALLOW_DATA_ASSOC_PEER | DISALLOW_BEACONS); rsi_send_rx_filter_frame(common, rx_filter_word); - common->wow_flags |= RSI_WOW_ENABLED; return 0; } -- cgit v1.2.3 From 66cffd6daab76caebab26eb803b92182414fc182 Mon Sep 17 00:00:00 2001 From: Taketo Kabe Date: Sun, 13 May 2018 18:16:40 +0900 Subject: b43: fix transmit failure when VT is switched Setup: Using BCM4306 rev.03 chip based CardBus wireless card. IRQ is shared with yenta (cardbus bridge) and i915 (display) driver. For firmware, installed latest but dated openfwwf 5.2 (http://netweb.ing.unibs.it/~openfwwf/) How-to-reproduce: Do "ssh ", then "ls -lR /" to generate traffic, then repeatedly switch VTs by Alt-F1<>Alt-F2. Eventually (within a minute) the card stops working. You can receive traffic but no transmission. For unknown reason it doesn't occur when just generating traffic by "ssh ls -lR /". With CONFIG_B43_DEBUG=y kernel config, when it stops, the debug message shows kernel: b43-phy1 debug: Out of order TX status report on DMA ring 1. Expected 148, but got 180 The slot offset I observed so far was always 32. When err_out2 is not set to make error messages successive, the debug output will be like this: kernel: b43-phy1 debug: Out of order TX status report on DMA ring 1. Expected 116, but got 148 kernel: b43-phy1 debug: Out of order TX status report on DMA ring 1. Expected 116, but got 150 kernel: b43-phy1 debug: Out of order TX status report on DMA ring 1. Expected 116, but got 120 kernel: b43-phy1 debug: Out of order TX status report on DMA ring 1. Expected 116, but got 152 kernel: b43-phy1 debug: Out of order TX status report on DMA ring 1. Expected 116, but got 122 kernel: b43-phy1 debug: Out of order TX status report on DMA ring 1. Expected 116, but got 154 kernel: b43-phy1 debug: Out of order TX status report on DMA ring 1. Expected 116, but got 124 kernel: b43-phy1 debug: Out of order TX status report on DMA ring 1. Expected 116, but got 156 kernel: b43-phy1 debug: Out of order TX status report on DMA ring 1. Expected 116, but got 126 The TX ring alternates between 2 sequences; the ring seems to be completely confused. Controller restart is needed. Workaround(1): This problem doesn't occur when using propriatory firmware you will extract by b43-fwcutter, so it may be a bug in openfwwf firmware, as the comment in the b43_dma_handle_txstatus() suggests. I wasn't able to find a bug in the terse openfwwf code though. Workaround(2): Using "pio=1" option to not use DMA makes this problem to not occur. Description of the patch: This patch will forcibly reset the controller to make it work again. Very kludgy and doesn't look right, but the traffic will continue to flow. Signed-off-by: Taketo Kabe Reviewed-by: Michael Buesch Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/b43/dma.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/b43/dma.c b/drivers/net/wireless/broadcom/b43/dma.c index 6837064908be..6b0e1ec346cb 100644 --- a/drivers/net/wireless/broadcom/b43/dma.c +++ b/drivers/net/wireless/broadcom/b43/dma.c @@ -1484,7 +1484,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, int slot, firstused; bool frame_succeed; int skip; - static u8 err_out1, err_out2; + static u8 err_out1; ring = parse_cookie(dev, status->cookie, &slot); if (unlikely(!ring)) @@ -1518,13 +1518,13 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, } } else { /* More than a single header/data pair were missed. - * Report this error once. + * Report this error, and reset the controller to + * revive operation. */ - if (!err_out2) - b43dbg(dev->wl, - "Out of order TX status report on DMA ring %d. Expected %d, but got %d\n", - ring->index, firstused, slot); - err_out2 = 1; + b43dbg(dev->wl, + "Out of order TX status report on DMA ring %d. Expected %d, but got %d\n", + ring->index, firstused, slot); + b43_controller_restart(dev, "Out of order TX"); return; } } -- cgit v1.2.3 From 763ece85f45a6b93268e25a0abf02922f911dab4 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Tue, 15 May 2018 11:14:44 +0200 Subject: brcmfmac: fix initialization of struct cfg80211_inform_bss variable This patch fixes a sparse warning "Using plain integer as NULL pointer" about cfg80211_inform_bss structure initialization. Reported-by: kbuild test robot Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 84135dac49b3..f5b405c98047 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -2737,7 +2737,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, u16 notify_interval; u8 *notify_ie; size_t notify_ielen; - struct cfg80211_inform_bss bss_data = { 0 }; + struct cfg80211_inform_bss bss_data = {}; if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) { brcmf_err("Bss info is larger than buffer. Discarding\n"); -- cgit v1.2.3 From 0d45d3fe42efc76b6c4f5a62f8d110c7a2e6f83f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 15 May 2018 12:08:14 +0200 Subject: mt76x2: apply coverage class on slot time too According to 802.11-2007 17.3.8.6 (slot time), the slot time should be increased by 3 us * coverage class. Taking into account coverage class in slot time configuration allows to increase by an order of magnitude the throughput on a 4Km link in a noisy environment Tested-by: Luca Bisti Tested-by: Gaetano Catalli Signed-off-by: Lorenzo Bianconi Acked-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x2_init.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt76x2_main.c | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index dd4c1127797e..276c6b6bec95 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -482,7 +482,10 @@ void mt76x2_set_tx_ackto(struct mt76x2_dev *dev) { u8 ackto, sifs, slottime = dev->slottime; + /* As defined by IEEE 802.11-2007 17.3.8.6 */ slottime += 3 * dev->coverage_class; + mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG, + MT_BKOFF_SLOT_CFG_SLOTTIME, slottime); sifs = mt76_get_field(dev, MT_XIFS_TIME_CFG, MT_XIFS_TIME_CFG_OFDM_SIFS); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index 81c58f865c64..539dda8a59e2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -247,8 +247,7 @@ mt76x2_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int slottime = info->use_short_slot ? 9 : 20; dev->slottime = slottime; - mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG, - MT_BKOFF_SLOT_CFG_SLOTTIME, slottime); + mt76x2_set_tx_ackto(dev); } mutex_unlock(&dev->mutex); -- cgit v1.2.3 From d98fb328ad103d12c1ebaea92526e4f8670e0fec Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 15 May 2018 14:33:22 +0200 Subject: mt76: fix sending encrypted broadcast packets for secondary interfaces For encryption to work properly, the BSS index needs to be initialized for the WCID entry used for the interface. Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x2.h | 3 +++ drivers/net/wireless/mediatek/mt76/mt76x2_init.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt76x2_main.c | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2.h index a5d1255e4b9c..dc12bbdbb2ee 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2.h @@ -39,6 +39,9 @@ #define MT_CALIBRATE_INTERVAL HZ +#define MT_MAX_VIFS 8 +#define MT_VIF_WCID(_n) (254 - ((_n) & 7)) + #include "mt76.h" #include "mt76x2_regs.h" #include "mt76x2_mac.h" diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index 276c6b6bec95..b6f27b949566 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -296,6 +296,9 @@ static int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard) for (i = 0; i < 256; i++) mt76x2_mac_wcid_setup(dev, i, 0, NULL); + for (i = 0; i < MT_MAX_VIFS; i++) + mt76x2_mac_wcid_setup(dev, MT_VIF_WCID(i), i, NULL); + for (i = 0; i < 16; i++) for (k = 0; k < 4; k++) mt76x2_mac_shared_key_setup(dev, i, k, NULL); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index 539dda8a59e2..826c2431e31a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -104,7 +104,7 @@ mt76x2_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) idx += 8; mvif->idx = idx; - mvif->group_wcid.idx = 254 - idx; + mvif->group_wcid.idx = MT_VIF_WCID(idx); mvif->group_wcid.hw_key_idx = -1; mt76x2_txq_init(dev, vif->txq); -- cgit v1.2.3 From 66a77cbe63eb326513632cc88e1260e877be8123 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 15 May 2018 14:33:23 +0200 Subject: mt76: discard early received packets if not running yet If the radio was previously in running state, it can receive some packets before it is able to process them. This can lead to a crash if the channel is not initialized yet. Discard all rx packets until start() is called Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x2_mac.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c index dab713756004..b49aea4da2d6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c @@ -301,6 +301,9 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb, u8 wcid; int len; + if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) + return -EINVAL; + if (rxinfo & MT_RXINFO_L2PAD) pad_len += 2; -- cgit v1.2.3 From 89bc67e3a93ae6199ae02c9e4fe41833da9ba368 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 20 May 2018 07:43:45 +0200 Subject: mt76: only stop tx queues on offchannel, not during the entire scan During scans, mac80211 frequently switches back to the home channel to minimize interruption of ongoing traffic. Keep regular tx queues active during that time. Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mac80211.c | 5 +++++ drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/tx.c | 4 ++-- 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 915e61733131..d862e5efd094 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -366,6 +366,11 @@ void mt76_set_channel(struct mt76_dev *dev) struct mt76_channel_state *state; bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; + if (offchannel) + set_bit(MT76_OFFCHANNEL, &dev->state); + else + clear_bit(MT76_OFFCHANNEL, &dev->state); + if (dev->drv->update_survey) dev->drv->update_survey(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index a74e6eef51e9..2d098fac6147 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -189,6 +189,7 @@ enum { MT76_STATE_RUNNING, MT76_SCANNING, MT76_RESET, + MT76_OFFCHANNEL, }; struct mt76_hw_cap { diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 7ecd2d7c5db4..e96956710fb2 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -332,7 +332,7 @@ mt76_txq_send_burst(struct mt76_dev *dev, struct mt76_queue *hwq, if (probe) break; - if (test_bit(MT76_SCANNING, &dev->state) || + if (test_bit(MT76_OFFCHANNEL, &dev->state) || test_bit(MT76_RESET, &dev->state)) return -EBUSY; @@ -385,7 +385,7 @@ restart: bool empty = false; int cur; - if (test_bit(MT76_SCANNING, &dev->state) || + if (test_bit(MT76_OFFCHANNEL, &dev->state) || test_bit(MT76_RESET, &dev->state)) return -EBUSY; -- cgit v1.2.3 From a164a94212ceb606d40e92db7a58e9dbcb3ff74e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 20 May 2018 07:43:46 +0200 Subject: mt76: prevent tx scheduling during channel change Re-schedule tx afterwards Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x2_main.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index 826c2431e31a..ce90ff999b49 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -124,11 +124,14 @@ mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef) { int ret; + cancel_delayed_work_sync(&dev->cal_work); + + set_bit(MT76_RESET, &dev->mt76.state); + mt76_set_channel(&dev->mt76); tasklet_disable(&dev->pre_tbtt_tasklet); tasklet_disable(&dev->dfs_pd.dfs_tasklet); - cancel_delayed_work_sync(&dev->cal_work); mt76x2_mac_stop(dev, true); ret = mt76x2_phy_set_channel(dev, chandef); @@ -143,6 +146,10 @@ mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef) tasklet_enable(&dev->dfs_pd.dfs_tasklet); tasklet_enable(&dev->pre_tbtt_tasklet); + clear_bit(MT76_RESET, &dev->mt76.state); + + mt76_txq_schedule_all(&dev->mt76); + return ret; } @@ -452,7 +459,6 @@ mt76x2_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) clear_bit(MT76_SCANNING, &dev->mt76.state); tasklet_enable(&dev->pre_tbtt_tasklet); - mt76_txq_schedule_all(&dev->mt76); } static void -- cgit v1.2.3 From a85b590cf55f0789efcdd347b69c9e8ad6c3dcc7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 20 May 2018 07:43:47 +0200 Subject: mt76: move ieee80211_hw allocation to common core Allows it to be shared between different drivers and locks to be initialized earlier Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mac80211.c | 22 ++++++++++++++++++++-- drivers/net/wireless/mediatek/mt76/mt76.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x2_init.c | 14 ++++++-------- 3 files changed, 28 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index d862e5efd094..d1044e5b25db 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -268,6 +268,26 @@ mt76_check_sband(struct mt76_dev *dev, int band) dev->hw->wiphy->bands[band] = NULL; } +struct mt76_dev * +mt76_alloc_device(unsigned int size, const struct ieee80211_ops *ops) +{ + struct ieee80211_hw *hw; + struct mt76_dev *dev; + + hw = ieee80211_alloc_hw(size, ops); + if (!hw) + return NULL; + + dev = hw->priv; + dev->hw = hw; + spin_lock_init(&dev->rx_lock); + spin_lock_init(&dev->lock); + spin_lock_init(&dev->cc_lock); + + return dev; +} +EXPORT_SYMBOL_GPL(mt76_alloc_device); + int mt76_register_device(struct mt76_dev *dev, bool vht, struct ieee80211_rate *rates, int n_rates) { @@ -277,8 +297,6 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, dev_set_drvdata(dev->dev, dev); - spin_lock_init(&dev->lock); - spin_lock_init(&dev->cc_lock); INIT_LIST_HEAD(&dev->txwi_cache); SET_IEEE80211_DEV(hw, dev->dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 2d098fac6147..bb158f867d7c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -377,6 +377,8 @@ mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c) return &msband->chan[idx]; } +struct mt76_dev *mt76_alloc_device(unsigned int size, + const struct ieee80211_ops *ops); int mt76_register_device(struct mt76_dev *dev, bool vht, struct ieee80211_rate *rates, int n_rates); void mt76_unregister_device(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index b6f27b949566..ec1715639a04 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -638,20 +638,18 @@ struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev) .rx_poll_complete = mt76x2_rx_poll_complete, .sta_ps = mt76x2_sta_ps, }; - struct ieee80211_hw *hw; struct mt76x2_dev *dev; + struct mt76_dev *mdev; - hw = ieee80211_alloc_hw(sizeof(*dev), &mt76x2_ops); - if (!hw) + mdev = mt76_alloc_device(sizeof(*dev), &mt76x2_ops); + if (!mdev) return NULL; - dev = hw->priv; - dev->mt76.dev = pdev; - dev->mt76.hw = hw; - dev->mt76.drv = &drv_ops; + dev = container_of(mdev, struct mt76x2_dev, mt76); + mdev->dev = pdev; + mdev->drv = &drv_ops; mutex_init(&dev->mutex); spin_lock_init(&dev->irq_lock); - spin_lock_init(&dev->mt76.rx_lock); return dev; } -- cgit v1.2.3 From 26e40d4c0b52c60f13b074d9d6144eb3ac7fb61b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 20 May 2018 07:43:48 +0200 Subject: mt76: wait for pending tx to complete before switching channel Reduces interruption caused by scanning Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/dma.c | 4 ++++ drivers/net/wireless/mediatek/mt76/mac80211.c | 16 ++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 2 ++ 3 files changed, 22 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 3518703524e7..3dbedcedc2c4 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -178,6 +178,10 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush) mt76_dma_sync_idx(dev, q); wake = wake && qid < IEEE80211_NUM_ACS && q->queued < q->ndesc - 8; + + if (!q->queued) + wake_up(&dev->tx_wait); + spin_unlock_bh(&q->lock); if (wake) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index d1044e5b25db..fcd079a96782 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -283,6 +283,7 @@ mt76_alloc_device(unsigned int size, const struct ieee80211_ops *ops) spin_lock_init(&dev->rx_lock); spin_lock_init(&dev->lock); spin_lock_init(&dev->cc_lock); + init_waitqueue_head(&dev->tx_wait); return dev; } @@ -377,18 +378,33 @@ void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(mt76_rx); +static bool mt76_has_tx_pending(struct mt76_dev *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++) { + if (dev->q_tx[i].queued) + return true; + } + + return false; +} + void mt76_set_channel(struct mt76_dev *dev) { struct ieee80211_hw *hw = dev->hw; struct cfg80211_chan_def *chandef = &hw->conf.chandef; struct mt76_channel_state *state; bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; + int timeout = HZ / 5; if (offchannel) set_bit(MT76_OFFCHANNEL, &dev->state); else clear_bit(MT76_OFFCHANNEL, &dev->state); + wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), timeout); + if (dev->drv->update_survey) dev->drv->update_survey(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index bb158f867d7c..d2166fbf50ff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -251,6 +251,8 @@ struct mt76_dev { struct mt76_queue q_rx[__MT_RXQ_MAX]; const struct mt76_queue_ops *queue_ops; + wait_queue_head_t tx_wait; + u8 macaddr[ETH_ALEN]; u32 rev; unsigned long state; -- cgit v1.2.3 From cbec83d40cc79137b008d0dd44846c5f2146a83d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 20 May 2018 07:43:49 +0200 Subject: mt76: use udelay instead of usleep_range in mt76x2_mac_stop usleep_range can cause excessive latency on channel change if waiting for the MAC to stop fails. It will be forced to stop by the code following that loop anyway. Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt76x2_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c index ec1715639a04..79ab93613e06 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c @@ -376,7 +376,7 @@ void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force) if ((mt76_rr(dev, MT_MAC_STATUS) & (MT_MAC_STATUS_RX | MT_MAC_STATUS_TX)) || mt76_rr(dev, MT_BBP(IBI, 12))) { - usleep_range(10, 20); + udelay(1); continue; } -- cgit v1.2.3 From 30bfce0b63fa68c14ae1613eb9d259fa18644074 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Fri, 18 May 2018 15:38:54 +0800 Subject: mwifiex: correct histogram data with appropriate index Correct snr/nr/rssi data index to avoid possible buffer underflow. Signed-off-by: Xinming Hu Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/util.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c index 0cd68ffc2c74..51ccf10f4413 100644 --- a/drivers/net/wireless/marvell/mwifiex/util.c +++ b/drivers/net/wireless/marvell/mwifiex/util.c @@ -708,12 +708,14 @@ void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr, s8 nflr) { struct mwifiex_histogram_data *phist_data = priv->hist_data; + s8 nf = -nflr; + s8 rssi = snr - nflr; atomic_inc(&phist_data->num_samples); atomic_inc(&phist_data->rx_rate[rx_rate]); - atomic_inc(&phist_data->snr[snr]); - atomic_inc(&phist_data->noise_flr[128 + nflr]); - atomic_inc(&phist_data->sig_str[nflr - snr]); + atomic_inc(&phist_data->snr[snr + 128]); + atomic_inc(&phist_data->noise_flr[nf + 128]); + atomic_inc(&phist_data->sig_str[rssi + 128]); } /* function to reset histogram data during init/reset */ -- cgit v1.2.3 From 88001968245c42c26416476bf0ef960442371605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 14 May 2018 08:48:20 +0200 Subject: brcmfmac: add debugfs entry for reading firmware capabilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows reading all capabilities as reported by a firmware. They are printed using native (raw) names, just like developers like it the most. It's how firmware reports support for various features, e.g. supported modes, supported standards, power saving details, max BSS-es. Access to all that info is useful for trying new firmwares, comparing them and debugging features AKA bugs. Signed-off-by: RafaÅ‚ MiÅ‚ecki Reviewed-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../wireless/broadcom/brcm80211/brcmfmac/feature.c | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index 876731c57bf5..800a423c7bc2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -165,6 +165,41 @@ static void brcmf_feat_firmware_capabilities(struct brcmf_if *ifp) } } +/** + * brcmf_feat_fwcap_debugfs_read() - expose firmware capabilities to debugfs. + * + * @seq: sequence for debugfs entry. + * @data: raw data pointer. + */ +static int brcmf_feat_fwcap_debugfs_read(struct seq_file *seq, void *data) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(seq->private); + struct brcmf_if *ifp = brcmf_get_ifp(bus_if->drvr, 0); + char caps[MAX_CAPS_BUFFER_SIZE + 1] = { }; + char *tmp; + int err; + + err = brcmf_fil_iovar_data_get(ifp, "cap", caps, sizeof(caps)); + if (err) { + brcmf_err("could not get firmware cap (%d)\n", err); + return err; + } + + /* Put every capability in a new line */ + for (tmp = caps; *tmp; tmp++) { + if (*tmp == ' ') + *tmp = '\n'; + } + + /* Usually there is a space at the end of capabilities string */ + seq_printf(seq, "%s", caps); + /* So make sure we don't print two line breaks */ + if (tmp > caps && *(tmp - 1) != '\n') + seq_printf(seq, "\n"); + + return 0; +} + void brcmf_feat_attach(struct brcmf_pub *drvr) { struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0); @@ -233,6 +268,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) void brcmf_feat_debugfs_create(struct brcmf_pub *drvr) { brcmf_debugfs_add_entry(drvr, "features", brcmf_feat_debugfs_read); + brcmf_debugfs_add_entry(drvr, "fwcap", brcmf_feat_fwcap_debugfs_read); } bool brcmf_feat_is_enabled(struct brcmf_if *ifp, enum brcmf_feat_id id) -- cgit v1.2.3 From abd39c6ded9db53aa44c2540092bdd5fb6590fa8 Mon Sep 17 00:00:00 2001 From: Sanjay Konduri Date: Tue, 15 May 2018 14:34:30 +0530 Subject: rsi: add fix for crash during assertions Observed crash in some scenarios when assertion has occurred, this is because hw structure is freed and is tried to get accessed in some functions where null check is already present. So, avoided the crash by making the hw to NULL after freeing. Signed-off-by: Sanjay Konduri Signed-off-by: Sushant Kumar Mishra Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 3faa0449a5ef..bfa7569c85bb 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -245,6 +245,7 @@ void rsi_mac80211_detach(struct rsi_hw *adapter) ieee80211_stop_queues(hw); ieee80211_unregister_hw(hw); ieee80211_free_hw(hw); + adapter->hw = NULL; } for (band = 0; band < NUM_NL80211_BANDS; band++) { -- cgit v1.2.3 From eeed833aaa38712efc7c41d9d6bd5afc8c13c55b Mon Sep 17 00:00:00 2001 From: Sanjay Konduri Date: Tue, 15 May 2018 14:34:31 +0530 Subject: rsi: add fix for corruption of auto rate table Auto rate table sent to firmware is getting corrupted as memset to zeros is not done. Added memset to skb data before filling auto rate table. Signed-off-by: Sanjay Konduri Signed-off-by: Sushant Kumar Mishra Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 0757adcb3f4a..d0e5937cad6d 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -1190,6 +1190,7 @@ static int rsi_send_auto_rate_request(struct rsi_common *common, return -ENOMEM; } + memset(skb->data, 0, frame_len); selected_rates = kzalloc(2 * RSI_TBL_SZ, GFP_KERNEL); if (!selected_rates) { rsi_dbg(ERR_ZONE, "%s: Failed in allocation of mem\n", -- cgit v1.2.3 From d4e36e5554eb92f3ec7fedad3efb602570584df4 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Fri, 20 Apr 2018 13:49:25 +0300 Subject: mac80211: Support adding duration for prepare_tx() callback There are specific cases, such as SAE authentication exchange, that might require long duration to complete. For such cases, add support for indicating to the driver the required duration of the prepare_tx() operation, so the driver would still be able to complete the frame exchange. Currently, indicate the duration only for SAE authentication exchange, as SAE authentication can take up to 2000 msec (as defined in IEEE P802.11-REVmd D1.0 p. 3504). As the patch modified the prepare_tx() callback API, also modify the relevant code in iwlwifi. Signed-off-by: Ilan Peer Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath9k/main.c | 3 ++- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a3be8add56e1..b6663c80e7dd 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2544,7 +2544,8 @@ static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw, } static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + u16 duration) { struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 5f0701c992a4..ec91dd90acfd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2844,7 +2844,8 @@ static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw, } static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + u16 req_duration) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); u32 duration = IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS; @@ -2857,6 +2858,9 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PREPARE_TX)) return; + if (req_duration > duration) + duration = req_duration; + mutex_lock(&mvm->mutex); /* Try really hard to protect the session and hear a beacon */ iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500, false); -- cgit v1.2.3 From f8793c26fe586659d6da3fa277e63961a69d314b Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Wed, 16 May 2018 14:11:58 +0200 Subject: brcmfmac: move ALLFFMAC variable in flowring module The only user of ALLFFMAC is the flowring module so no need to expose it in a header file. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c | 2 -- drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h | 2 -- drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c | 2 ++ 3 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index 105b8774fca9..cd3651069d0c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -36,8 +36,6 @@ MODULE_AUTHOR("Broadcom Corporation"); MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); MODULE_LICENSE("Dual BSD/GPL"); -const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - #define BRCMF_DEFAULT_SCAN_CHANNEL_TIME 40 #define BRCMF_DEFAULT_SCAN_UNASSOC_TIME 40 diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h index ef914619e8e1..a34642cb4d2f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h @@ -19,8 +19,6 @@ #include #include "fwil_types.h" -extern const u8 ALLFFMAC[ETH_ALEN]; - #define BRCMF_FW_ALTPATH_LEN 256 /* Definitions for the module global and device specific settings are defined diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c index d0b738da2458..d0d8b32af7d0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c @@ -46,6 +46,8 @@ static const u8 brcmf_flowring_prio2fifo[] = { 3 }; +static const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + static bool brcmf_flowring_is_tdls_mac(struct brcmf_flowring *flow, u8 mac[ETH_ALEN]) -- cgit v1.2.3 From 8e072168f75ebce85b96cbcefea2b10ddbd5913f Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Wed, 16 May 2018 14:11:59 +0200 Subject: brcmfmac: add support for sysfs initiated coredump The driver already supports device coredump initiated by firmware event. Since commit 3c47d19ff4dc ("drivers: base: add coredump driver ops") it is also possible to initiate it from user-space through sysfs. This patch adds support for SDIO and PCIe devices. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 1 + drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h | 2 ++ drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 8 ++++++++ drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 1 + 4 files changed, 12 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index a1915411c280..d2f788d88668 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -1165,6 +1165,7 @@ static struct sdio_driver brcmf_sdmmc_driver = { #ifdef CONFIG_PM_SLEEP .pm = &brcmf_sdio_pm_ops, #endif /* CONFIG_PM_SLEEP */ + .coredump = brcmf_dev_coredump, }, }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h index 27e693e93f21..c4965184cdf3 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h @@ -250,6 +250,8 @@ int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings); void brcmf_detach(struct device *dev); /* Indication from bus module that dongle should be reset */ void brcmf_dev_reset(struct device *dev); +/* Request from bus module to initiate a coredump */ +void brcmf_dev_coredump(struct device *dev); /* Configure the "global" bus state used by upper layers */ void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index 8d4511eaa9b9..72954fd6df3b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -1180,6 +1180,14 @@ void brcmf_dev_reset(struct device *dev) brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1); } +void brcmf_dev_coredump(struct device *dev) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + + if (brcmf_debug_create_memdump(bus_if, NULL, 0) < 0) + brcmf_dbg(TRACE, "failed to create coredump\n"); +} + void brcmf_detach(struct device *dev) { s32 i; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index f0797aeada67..5baa8372371d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -2044,6 +2044,7 @@ static struct pci_driver brcmf_pciedrvr = { #ifdef CONFIG_PM .driver.pm = &brcmf_pciedrvr_pm, #endif + .driver.coredump = brcmf_dev_coredump, }; -- cgit v1.2.3 From 21c5c83ce83359f0ab930824c67984575c051550 Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Wed, 16 May 2018 14:12:00 +0200 Subject: mwifiex: support sysfs initiated device coredump Since commit 3c47d19ff4dc ("drivers: base: add coredump driver ops") it is possible to initiate a device coredump from user-space. This patch adds support for it adding the .coredump() driver callback. As there is no longer a need to initiate it through debugfs remove that code. Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cmdevt.c | 1 + drivers/net/wireless/marvell/mwifiex/debugfs.c | 31 +------------------------- drivers/net/wireless/marvell/mwifiex/pcie.c | 18 +++++++++++++-- drivers/net/wireless/marvell/mwifiex/sdio.c | 12 ++++++++++ drivers/net/wireless/marvell/mwifiex/usb.c | 13 +++++++++++ 5 files changed, 43 insertions(+), 32 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 9cfcdf6bec52..8be1e69657a7 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -674,6 +674,7 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no, return ret; } +EXPORT_SYMBOL_GPL(mwifiex_send_cmd); /* * This function queues a command to the command pending queue. diff --git a/drivers/net/wireless/marvell/mwifiex/debugfs.c b/drivers/net/wireless/marvell/mwifiex/debugfs.c index db2872daae97..07453932f703 100644 --- a/drivers/net/wireless/marvell/mwifiex/debugfs.c +++ b/drivers/net/wireless/marvell/mwifiex/debugfs.c @@ -153,34 +153,6 @@ free_and_exit: return ret; } -/* - * Proc device dump read handler. - * - * This function is called when the 'device_dump' file is opened for - * reading. - * This function dumps driver information and firmware memory segments - * (ex. DTCM, ITCM, SQRAM etc.) for - * debugging. - */ -static ssize_t -mwifiex_device_dump_read(struct file *file, char __user *ubuf, - size_t count, loff_t *ppos) -{ - struct mwifiex_private *priv = file->private_data; - - /* For command timeouts, USB firmware will automatically emit - * firmware dump events, so we don't implement device_dump(). - * For user-initiated dumps, we trigger it ourselves. - */ - if (priv->adapter->iface_type == MWIFIEX_USB) - mwifiex_send_cmd(priv, HostCmd_CMD_FW_DUMP_EVENT, - HostCmd_ACT_GEN_SET, 0, NULL, true); - else - priv->adapter->if_ops.device_dump(priv->adapter); - - return 0; -} - /* * Proc getlog file read handler. * @@ -980,7 +952,6 @@ static const struct file_operations mwifiex_dfs_##name##_fops = { \ MWIFIEX_DFS_FILE_READ_OPS(info); MWIFIEX_DFS_FILE_READ_OPS(debug); MWIFIEX_DFS_FILE_READ_OPS(getlog); -MWIFIEX_DFS_FILE_READ_OPS(device_dump); MWIFIEX_DFS_FILE_OPS(regrdwr); MWIFIEX_DFS_FILE_OPS(rdeeprom); MWIFIEX_DFS_FILE_OPS(memrw); @@ -1011,7 +982,7 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv) MWIFIEX_DFS_ADD_FILE(getlog); MWIFIEX_DFS_ADD_FILE(regrdwr); MWIFIEX_DFS_ADD_FILE(rdeeprom); - MWIFIEX_DFS_ADD_FILE(device_dump); + MWIFIEX_DFS_ADD_FILE(memrw); MWIFIEX_DFS_ADD_FILE(hscfg); MWIFIEX_DFS_ADD_FILE(histogram); diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 7538543d46fa..0c42b7296ddd 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -320,6 +320,19 @@ static void mwifiex_pcie_shutdown(struct pci_dev *pdev) return; } +static void mwifiex_pcie_coredump(struct device *dev) +{ + struct pci_dev *pdev; + struct pcie_service_card *card; + + pdev = container_of(dev, struct pci_dev, dev); + card = pci_get_drvdata(pdev); + + if (!test_and_set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, + &card->work_flags)) + schedule_work(&card->work); +} + static const struct pci_device_id mwifiex_ids[] = { { PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P, @@ -415,11 +428,12 @@ static struct pci_driver __refdata mwifiex_pcie = { .id_table = mwifiex_ids, .probe = mwifiex_pcie_probe, .remove = mwifiex_pcie_remove, -#ifdef CONFIG_PM_SLEEP .driver = { + .coredump = mwifiex_pcie_coredump, +#ifdef CONFIG_PM_SLEEP .pm = &mwifiex_pcie_pm_ops, - }, #endif + }, .shutdown = mwifiex_pcie_shutdown, .err_handler = &mwifiex_pcie_err_handler, }; diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index a82880132af4..47d2dcc3f28f 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -466,6 +466,17 @@ static int mwifiex_sdio_suspend(struct device *dev) return ret; } +static void mwifiex_sdio_coredump(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct sdio_mmc_card *card; + + card = sdio_get_drvdata(func); + if (!test_and_set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, + &card->work_flags)) + schedule_work(&card->work); +} + /* Device ID for SD8786 */ #define SDIO_DEVICE_ID_MARVELL_8786 (0x9116) /* Device ID for SD8787 */ @@ -515,6 +526,7 @@ static struct sdio_driver mwifiex_sdio = { .remove = mwifiex_sdio_remove, .drv = { .owner = THIS_MODULE, + .coredump = mwifiex_sdio_coredump, .pm = &mwifiex_sdio_pm_ops, } }; diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index 4bc244801636..7aa39878ce49 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -653,6 +653,16 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf) usb_put_dev(interface_to_usbdev(intf)); } +static void mwifiex_usb_coredump(struct device *dev) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_card_rec *card = usb_get_intfdata(intf); + + mwifiex_send_cmd(mwifiex_get_priv(card->adapter, MWIFIEX_BSS_ROLE_ANY), + HostCmd_CMD_FW_DUMP_EVENT, HostCmd_ACT_GEN_SET, 0, + NULL, true); +} + static struct usb_driver mwifiex_usb_driver = { .name = "mwifiex_usb", .probe = mwifiex_usb_probe, @@ -661,6 +671,9 @@ static struct usb_driver mwifiex_usb_driver = { .suspend = mwifiex_usb_suspend, .resume = mwifiex_usb_resume, .soft_unbind = 1, + .drvwrap.driver = { + .coredump = mwifiex_usb_coredump, + }, }; static int mwifiex_write_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf, -- cgit v1.2.3 From d2af9b566554e01f9ad67b330ce569dbc130e5d3 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Wed, 16 May 2018 14:12:01 +0200 Subject: brcmfmac: validate user provided data for memdump before copying In patch "brcmfmac: add support for sysfs initiated coredump", a new scenario of brcmf_debug_create_memdump was added in which the user of the function might not necessarily provide prefix data. Hence the function should not assume the data is always valid and should perform a check before copying. Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c index 504832084eca..489b5dfdf5b9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c @@ -40,7 +40,8 @@ int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data, if (!dump) return -ENOMEM; - memcpy(dump, data, len); + if (data && len > 0) + memcpy(dump, data, len); err = brcmf_bus_get_memdump(bus, dump + len, ramsize); if (err) { vfree(dump); -- cgit v1.2.3 From 8a3ab2f38f1669e3be6433a1f6b82a077b38c4c7 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Wed, 16 May 2018 14:12:02 +0200 Subject: brcmfmac: trigger memory dump upon firmware halt signal PCIe dongle firmware signals a halt/trap through mailbox interrupt. Trigger a memory dump upon receiving such signal could help to provide useful information for issue debug. Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 5baa8372371d..45928b5b8d97 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -182,6 +182,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { #define BRCMF_D2H_DEV_D3_ACK 0x00000001 #define BRCMF_D2H_DEV_DS_ENTER_REQ 0x00000002 #define BRCMF_D2H_DEV_DS_EXIT_NOTE 0x00000004 +#define BRCMF_D2H_DEV_FWHALT 0x10000000 #define BRCMF_H2D_HOST_D3_INFORM 0x00000001 #define BRCMF_H2D_HOST_DS_ACK 0x00000002 @@ -717,6 +718,10 @@ static void brcmf_pcie_handle_mb_data(struct brcmf_pciedev_info *devinfo) devinfo->mbdata_completed = true; wake_up(&devinfo->mbdata_resp_wait); } + if (dtoh_mb_data & BRCMF_D2H_DEV_FWHALT) { + brcmf_dbg(PCIE, "D2H_MB_DATA: FW HALT\n"); + brcmf_dev_coredump(&devinfo->pdev->dev); + } } -- cgit v1.2.3 From b8248236e92790ac635caeb4156e46ea2417e037 Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Wed, 16 May 2018 14:12:03 +0200 Subject: brcmfmac: trigger memory dump on SDIO firmware halt message Attempt to dump dongle memory for debug upon receiving firmware halt message through dongle to host mail box interrupt. Reviewed-by: Arend van Spriel Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 412a05b9a2b2..c99a191e8d69 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -1072,8 +1072,10 @@ static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus) bus->sdcnt.f1regdata += 2; /* dongle indicates the firmware has halted/crashed */ - if (hmb_data & HMB_DATA_FWHALT) + if (hmb_data & HMB_DATA_FWHALT) { brcmf_err("mailbox indicates firmware halted\n"); + brcmf_dev_coredump(&sdiod->func1->dev); + } /* Dongle recomposed rx frames, accept them again */ if (hmb_data & HMB_DATA_NAKHANDLED) { -- cgit v1.2.3 From 46dbf98c69f476a0928393310617f15a9c6469b5 Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Wed, 23 May 2018 11:09:02 +0300 Subject: ath10k: add memory dump support for QCA9888 and QCA99X0 This patch adds firmware crash memory dump support for QCA9888 and QCA99X0. Tested on: QCA9888 firmware 10.4-3.5.3-00053 QCA99X0 firmware 10.4.1.00030-1 Signed-off-by: Anilkumar Kolli Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/coredump.c | 98 ++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c index f90cec0ebb1c..4d28063052fe 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.c +++ b/drivers/net/wireless/ath/ath10k/coredump.c @@ -701,6 +701,89 @@ static const struct ath10k_mem_region qca988x_hw20_mem_regions[] = { }, }; +static const struct ath10k_mem_region qca99x0_hw20_mem_regions[] = { + { + .type = ATH10K_MEM_REGION_TYPE_DRAM, + .start = 0x400000, + .len = 0x60000, + .name = "DRAM", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_REG, + .start = 0x98000, + .len = 0x50000, + .name = "IRAM", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IOSRAM, + .start = 0xC0000, + .len = 0x40000, + .name = "SRAM", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IOREG, + .start = 0x30000, + .len = 0x7000, + .name = "APB REG 1", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IOREG, + .start = 0x3f000, + .len = 0x3000, + .name = "APB REG 2", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IOREG, + .start = 0x43000, + .len = 0x3000, + .name = "WIFI REG", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IOREG, + .start = 0x4A000, + .len = 0x5000, + .name = "CE REG", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IOREG, + .start = 0x80000, + .len = 0x6000, + .name = "SOC REG", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, +}; + static const struct ath10k_mem_region qca9984_hw10_mem_regions[] = { { .type = ATH10K_MEM_REGION_TYPE_DRAM, @@ -848,6 +931,21 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { .size = ARRAY_SIZE(qca9984_hw10_mem_regions), }, }, + { + .hw_id = QCA9888_HW_2_0_DEV_VERSION, + .region_table = { + .regions = qca9984_hw10_mem_regions, + .size = ARRAY_SIZE(qca9984_hw10_mem_regions), + }, + }, + { + .hw_id = QCA99X0_HW_2_0_DEV_VERSION, + .region_table = { + .regions = qca99x0_hw20_mem_regions, + .size = ARRAY_SIZE(qca99x0_hw20_mem_regions), + }, + }, + }; static u32 ath10k_coredump_get_ramdump_size(struct ath10k *ar) -- cgit v1.2.3 From be8cce96f14dc925ecfb702be0392a52cf78adb5 Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Wed, 23 May 2018 11:09:09 +0300 Subject: ath10k: add support to configure channel dwell time Configure channel dwell time from duration of the scan request received from mac80211 when the duration is non-zero. When the scan request does not have duration value, use the default ones, the current implementation. Corresponding flag NL80211_EXT_FEATURE_SET_SCAN_DWELL is advertized. Supported Chipsets: -QCA988X/QCA9887 PCI -QCA99X0/QCA9984/QCA9888/QCA4019 PCI -QCA6174/QCA9377 PCI/USB/SDIO -WCN3990 SNOC Tested on QCA9984 with firmware ver 10.4-3.6-0010 Signed-off-by: Pradeep Kumar Chitrapu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/mac.c | 23 ++++++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index e4ac8f2831fd..eb7ff1116442 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -44,6 +44,7 @@ #define WO(_f) ((_f##_OFFSET) >> 2) #define ATH10K_SCAN_ID 0 +#define ATH10K_SCAN_CHANNEL_SWITCH_WMI_EVT_OVERHEAD 10 /* msec */ #define WMI_READY_TIMEOUT (5 * HZ) #define ATH10K_FLUSH_TIMEOUT_HZ (5 * HZ) #define ATH10K_CONNECTION_LOSS_HZ (3 * HZ) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 487a7a7380fd..e3b67ffdab72 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -5675,6 +5675,7 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, struct wmi_start_scan_arg arg; int ret = 0; int i; + u32 scan_timeout; mutex_lock(&ar->conf_mutex); @@ -5736,6 +5737,22 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, arg.channels[i] = req->channels[i]->center_freq; } + /* if duration is set, default dwell times will be overwritten */ + if (req->duration) { + arg.dwell_time_active = req->duration; + arg.dwell_time_passive = req->duration; + arg.burst_duration_ms = req->duration; + + scan_timeout = min_t(u32, arg.max_rest_time * + (arg.n_channels - 1) + (req->duration + + ATH10K_SCAN_CHANNEL_SWITCH_WMI_EVT_OVERHEAD) * + arg.n_channels, arg.max_scan_time + 200); + + } else { + /* Add a 200ms margin to account for event/command processing */ + scan_timeout = arg.max_scan_time + 200; + } + ret = ath10k_start_scan(ar, &arg); if (ret) { ath10k_warn(ar, "failed to start hw scan: %d\n", ret); @@ -5744,10 +5761,8 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, spin_unlock_bh(&ar->data_lock); } - /* Add a 200ms margin to account for event/command processing */ ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout, - msecs_to_jiffies(arg.max_scan_time + - 200)); + msecs_to_jiffies(scan_timeout)); exit: mutex_unlock(&ar->conf_mutex); @@ -8364,6 +8379,8 @@ int ath10k_mac_register(struct ath10k *ar) } wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS); + wiphy_ext_feature_set(ar->hw->wiphy, + NL80211_EXT_FEATURE_SET_SCAN_DWELL); /* * on LL hardware queues are managed entirely by the FW -- cgit v1.2.3 From 699e2302c286a14afe7b7394151ce6c4e1790cc1 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:09:53 +0300 Subject: ath: Add regulatory mapping for Bahamas The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: ETSI * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd.h | 1 + drivers/net/wireless/ath/regd_common.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 5d80be213fac..f296ff838d2a 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -68,6 +68,7 @@ enum CountryCode { CTRY_AUSTRALIA = 36, CTRY_AUSTRIA = 40, CTRY_AZERBAIJAN = 31, + CTRY_BAHAMAS = 44, CTRY_BAHRAIN = 48, CTRY_BANGLADESH = 50, CTRY_BARBADOS = 52, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index bdd2b4d61f2f..cde0268cbed6 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -298,6 +298,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_AUSTRALIA2, FCC6_WORLD, "AU"}, {CTRY_AUSTRIA, ETSI1_WORLD, "AT"}, {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ"}, + {CTRY_BAHAMAS, FCC3_WORLD, "BS"}, {CTRY_BAHRAIN, APL6_WORLD, "BH"}, {CTRY_BANGLADESH, NULL1_WORLD, "BD"}, {CTRY_BARBADOS, FCC2_WORLD, "BB"}, -- cgit v1.2.3 From 9c790f2d234f65697e3b0948adbfdf36dbe63dd7 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:09:59 +0300 Subject: ath: Add regulatory mapping for Bermuda The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: FCC * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd.h | 1 + drivers/net/wireless/ath/regd_common.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index f296ff838d2a..e7b43901d195 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -75,6 +75,7 @@ enum CountryCode { CTRY_BELARUS = 112, CTRY_BELGIUM = 56, CTRY_BELIZE = 84, + CTRY_BERMUDA = 60, CTRY_BOLIVIA = 68, CTRY_BOSNIA_HERZ = 70, CTRY_BRAZIL = 76, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index cde0268cbed6..a8c7f306fd7b 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -306,6 +306,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_BELGIUM, ETSI1_WORLD, "BE"}, {CTRY_BELGIUM2, ETSI4_WORLD, "BL"}, {CTRY_BELIZE, APL1_ETSIC, "BZ"}, + {CTRY_BERMUDA, FCC3_FCCA, "BM"}, {CTRY_BOLIVIA, APL1_ETSIC, "BO"}, {CTRY_BOSNIA_HERZ, ETSI1_WORLD, "BA"}, {CTRY_BRAZIL, FCC3_WORLD, "BR"}, -- cgit v1.2.3 From b840fa9123086c485788f9c8e96dd4c18e1154cb Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:10:12 +0300 Subject: ath: Add regulatory mapping for Kenya The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: ETSI * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index a8c7f306fd7b..981f604758b0 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -411,6 +411,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_JORDAN, ETSI2_WORLD, "JO"}, {CTRY_KAZAKHSTAN, NULL1_WORLD, "KZ"}, + {CTRY_KENYA, APL1_WORLD, "KE"}, {CTRY_KOREA_NORTH, APL9_WORLD, "KP"}, {CTRY_KOREA_ROC, APL9_WORLD, "KR"}, {CTRY_KOREA_ROC2, APL2_WORLD, "K2"}, -- cgit v1.2.3 From a71c984bc4e5e4f1e94a4c362cce764834352d9a Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:10:19 +0300 Subject: ath: Add regulatory mapping for Mauritius The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: ETSI * 5GHz: ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd.h | 1 + drivers/net/wireless/ath/regd_common.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index e7b43901d195..8fbf0a684bc9 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -138,6 +138,7 @@ enum CountryCode { CTRY_MACEDONIA = 807, CTRY_MALAYSIA = 458, CTRY_MALTA = 470, + CTRY_MAURITIUS = 480, CTRY_MEXICO = 484, CTRY_MONACO = 492, CTRY_MOROCCO = 504, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 981f604758b0..3718bbcdd945 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -426,6 +426,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_MACEDONIA, NULL1_WORLD, "MK"}, {CTRY_MALAYSIA, APL8_WORLD, "MY"}, {CTRY_MALTA, ETSI1_WORLD, "MT"}, + {CTRY_MAURITIUS, ETSI1_WORLD, "MU"}, {CTRY_MEXICO, FCC1_FCCA, "MX"}, {CTRY_MONACO, ETSI4_WORLD, "MC"}, {CTRY_MOROCCO, APL4_WORLD, "MA"}, -- cgit v1.2.3 From a0a6f2a916dccc394404117534e9587866a7eefa Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:10:22 +0300 Subject: ath: Add regulatory mapping for Montenegro The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: ETSI * 5GHz: ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd.h | 1 + drivers/net/wireless/ath/regd_common.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 8fbf0a684bc9..8edf6d894519 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -141,6 +141,7 @@ enum CountryCode { CTRY_MAURITIUS = 480, CTRY_MEXICO = 484, CTRY_MONACO = 492, + CTRY_MONTENEGRO = 499, CTRY_MOROCCO = 504, CTRY_NEPAL = 524, CTRY_NETHERLANDS = 528, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 3718bbcdd945..ef636831812a 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -429,6 +429,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_MAURITIUS, ETSI1_WORLD, "MU"}, {CTRY_MEXICO, FCC1_FCCA, "MX"}, {CTRY_MONACO, ETSI4_WORLD, "MC"}, + {CTRY_MONTENEGRO, ETSI1_WORLD, "ME"}, {CTRY_MOROCCO, APL4_WORLD, "MA"}, {CTRY_NEPAL, APL1_WORLD, "NP"}, {CTRY_NETHERLANDS, ETSI1_WORLD, "NL"}, -- cgit v1.2.3 From a20f1338c5de7a62a9b9b4353618e2c336251b3a Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:10:26 +0300 Subject: ath: Add regulatory mapping for Nicaragua The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: FCC * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index ef636831812a..6a14049f8b8f 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -435,6 +435,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_NETHERLANDS, ETSI1_WORLD, "NL"}, {CTRY_NETHERLANDS_ANTILLES, ETSI1_WORLD, "AN"}, {CTRY_NEW_ZEALAND, FCC2_ETSIC, "NZ"}, + {CTRY_NICARAGUA, FCC3_FCCA, "NI"}, {CTRY_NORWAY, ETSI1_WORLD, "NO"}, {CTRY_OMAN, FCC3_WORLD, "OM"}, {CTRY_PAKISTAN, NULL1_WORLD, "PK"}, -- cgit v1.2.3 From 67a956682472c9fef28f1e171a10428c6e7a800f Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:10:29 +0300 Subject: ath: Add regulatory mapping for Paraguya The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: ETSI * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 6a14049f8b8f..ad085c795662 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -441,6 +441,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_PAKISTAN, NULL1_WORLD, "PK"}, {CTRY_PANAMA, FCC1_FCCA, "PA"}, {CTRY_PAPUA_NEW_GUINEA, FCC1_WORLD, "PG"}, + {CTRY_PARAGUAY, FCC3_WORLD, "PY"}, {CTRY_PERU, APL1_WORLD, "PE"}, {CTRY_PHILIPPINES, APL1_WORLD, "PH"}, {CTRY_POLAND, ETSI1_WORLD, "PL"}, -- cgit v1.2.3 From 2a3169a54bb53717928392a04fb84deb765b51f1 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:10:43 +0300 Subject: ath: Add regulatory mapping for Serbia The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: ETSI * 5GHz: ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd.h | 1 + drivers/net/wireless/ath/regd_common.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 8edf6d894519..58afd500bdb3 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -163,6 +163,7 @@ enum CountryCode { CTRY_ROMANIA = 642, CTRY_RUSSIA = 643, CTRY_SAUDI_ARABIA = 682, + CTRY_SERBIA = 688, CTRY_SERBIA_MONTENEGRO = 891, CTRY_SINGAPORE = 702, CTRY_SLOVAKIA = 703, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index ad085c795662..f3764ac9e4e3 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -451,6 +451,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_ROMANIA, NULL1_WORLD, "RO"}, {CTRY_RUSSIA, NULL1_WORLD, "RU"}, {CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"}, + {CTRY_SERBIA, ETSI1_WORLD, "RS"}, {CTRY_SERBIA_MONTENEGRO, ETSI1_WORLD, "CS"}, {CTRY_SINGAPORE, APL6_WORLD, "SG"}, {CTRY_SLOVAKIA, ETSI1_WORLD, "SK"}, -- cgit v1.2.3 From 667ddac5745fb9fddfe8f7fd2523070f50bd4442 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:10:48 +0300 Subject: ath: Add regulatory mapping for Tanzania The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: ETSI * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd.h | 1 + drivers/net/wireless/ath/regd_common.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 58afd500bdb3..894be37344aa 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -175,6 +175,7 @@ enum CountryCode { CTRY_SWITZERLAND = 756, CTRY_SYRIA = 760, CTRY_TAIWAN = 158, + CTRY_TANZANIA = 834, CTRY_THAILAND = 764, CTRY_TRINIDAD_Y_TOBAGO = 780, CTRY_TUNISIA = 788, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index f3764ac9e4e3..64f004ec0ef2 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -463,6 +463,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_SWITZERLAND, ETSI1_WORLD, "CH"}, {CTRY_SYRIA, NULL1_WORLD, "SY"}, {CTRY_TAIWAN, APL3_FCCA, "TW"}, + {CTRY_TANZANIA, APL1_WORLD, "TZ"}, {CTRY_THAILAND, FCC3_WORLD, "TH"}, {CTRY_TRINIDAD_Y_TOBAGO, FCC3_WORLD, "TT"}, {CTRY_TUNISIA, ETSI3_WORLD, "TN"}, -- cgit v1.2.3 From 1ea3986ad2bc72081c69f3fbc1e5e0eeb3c44f17 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:10:54 +0300 Subject: ath: Add regulatory mapping for Uganda The country code is used by the ath to detect the ISO 3166-1 alpha-2 name and to select the correct conformance test limits (CTL) for a country. If the country isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this country are: * 2.4GHz: ETSI * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd.h | 1 + drivers/net/wireless/ath/regd_common.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 894be37344aa..d73e45e26547 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -181,6 +181,7 @@ enum CountryCode { CTRY_TUNISIA = 788, CTRY_TURKEY = 792, CTRY_UAE = 784, + CTRY_UGANDA = 800, CTRY_UKRAINE = 804, CTRY_UNITED_KINGDOM = 826, CTRY_UNITED_STATES = 840, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 64f004ec0ef2..f7f0efd437b8 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -468,6 +468,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_TRINIDAD_Y_TOBAGO, FCC3_WORLD, "TT"}, {CTRY_TUNISIA, ETSI3_WORLD, "TN"}, {CTRY_TURKEY, ETSI3_WORLD, "TR"}, + {CTRY_UGANDA, FCC3_WORLD, "UG"}, {CTRY_UKRAINE, NULL1_WORLD, "UA"}, {CTRY_UAE, NULL1_WORLD, "AE"}, {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB"}, -- cgit v1.2.3 From 4f183687e3fad3ce0e06e38976cad81bc4541990 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:11:05 +0300 Subject: ath: Add regulatory mapping for APL2_FCCA The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this regdomain code are: * 2.4GHz: FCC * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index f7f0efd437b8..969dc12506ee 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -59,6 +59,7 @@ enum EnumRd { MKK1_MKKA1 = 0x4A, MKK1_MKKA2 = 0x4B, MKK1_MKKC = 0x4C, + APL2_FCCA = 0x4D, APL3_FCCA = 0x50, APL1_WORLD = 0x52, @@ -188,6 +189,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {FCC1_FCCA, CTL_FCC, CTL_FCC}, {APL1_WORLD, CTL_FCC, CTL_ETSI}, {APL2_WORLD, CTL_FCC, CTL_ETSI}, + {APL2_FCCA, CTL_FCC, CTL_FCC}, {APL3_WORLD, CTL_FCC, CTL_ETSI}, {APL4_WORLD, CTL_FCC, CTL_ETSI}, {APL5_WORLD, CTL_FCC, CTL_ETSI}, -- cgit v1.2.3 From 9ba8df0c52b3e6baa436374b429d3d73bd09a320 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:11:14 +0300 Subject: ath: Add regulatory mapping for APL13_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this regdomain code are: * 2.4GHz: ETSI * 5GHz: ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 969dc12506ee..f3969d05c816 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -68,6 +68,7 @@ enum EnumRd { APL1_ETSIC = 0x55, APL2_ETSIC = 0x56, APL5_WORLD = 0x58, + APL13_WORLD = 0x5A, APL6_WORLD = 0x5B, APL7_FCCA = 0x5C, APL8_WORLD = 0x5D, @@ -193,6 +194,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {APL3_WORLD, CTL_FCC, CTL_ETSI}, {APL4_WORLD, CTL_FCC, CTL_ETSI}, {APL5_WORLD, CTL_FCC, CTL_ETSI}, + {APL13_WORLD, CTL_ETSI, CTL_ETSI}, {APL6_WORLD, CTL_ETSI, CTL_ETSI}, {APL8_WORLD, CTL_ETSI, CTL_ETSI}, {APL9_WORLD, CTL_ETSI, CTL_ETSI}, -- cgit v1.2.3 From 45faf6e096da8bb80e1ddf8c08a26a9601d9469e Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:11:18 +0300 Subject: ath: Add regulatory mapping for ETSI8_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this regdomain code are: * 2.4GHz: ETSI * 5GHz: ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index f3969d05c816..95a378e6a88b 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -44,6 +44,7 @@ enum EnumRd { ETSI4_ETSIC = 0x38, ETSI5_WORLD = 0x39, ETSI6_WORLD = 0x34, + ETSI8_WORLD = 0x3D, ETSI_RESERVED = 0x33, MKK1_MKKA = 0x40, @@ -181,6 +182,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {ETSI4_WORLD, CTL_ETSI, CTL_ETSI}, {ETSI5_WORLD, CTL_ETSI, CTL_ETSI}, {ETSI6_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI8_WORLD, CTL_ETSI, CTL_ETSI}, /* XXX: For ETSI3_ETSIA, Was NO_CTL meant for the 2 GHz band ? */ {ETSI3_ETSIA, CTL_ETSI, CTL_ETSI}, -- cgit v1.2.3 From 897fab6c5d901398beaeb4d764b1816fbed9c488 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:11:24 +0300 Subject: ath: Add regulatory mapping for ETSI9_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this regdomain code are: * 2.4GHz: ETSI * 5GHz: ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 95a378e6a88b..66932c55d352 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -45,6 +45,7 @@ enum EnumRd { ETSI5_WORLD = 0x39, ETSI6_WORLD = 0x34, ETSI8_WORLD = 0x3D, + ETSI9_WORLD = 0x3E, ETSI_RESERVED = 0x33, MKK1_MKKA = 0x40, @@ -183,6 +184,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {ETSI5_WORLD, CTL_ETSI, CTL_ETSI}, {ETSI6_WORLD, CTL_ETSI, CTL_ETSI}, {ETSI8_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI9_WORLD, CTL_ETSI, CTL_ETSI}, /* XXX: For ETSI3_ETSIA, Was NO_CTL meant for the 2 GHz band ? */ {ETSI3_ETSIA, CTL_ETSI, CTL_ETSI}, -- cgit v1.2.3 From 01fb2994a98dc72c8818c274f7b5983d5dd885c7 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:11:30 +0300 Subject: ath: Add regulatory mapping for FCC3_ETSIC The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't available and it is still programmed in the EEPROM then it will cause an error and stop the initialization with: Invalid EEPROM contents The current CTL mappings for this regdomain code are: * 2.4GHz: ETSI * 5GHz: FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 66932c55d352..437f5dca015a 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -35,6 +35,7 @@ enum EnumRd { FRANCE_RES = 0x31, FCC3_FCCA = 0x3A, FCC3_WORLD = 0x3B, + FCC3_ETSIC = 0x3F, ETSI1_WORLD = 0x37, ETSI3_ETSIA = 0x32, @@ -172,6 +173,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {FCC2_ETSIC, CTL_FCC, CTL_ETSI}, {FCC3_FCCA, CTL_FCC, CTL_FCC}, {FCC3_WORLD, CTL_FCC, CTL_ETSI}, + {FCC3_ETSIC, CTL_FCC, CTL_ETSI}, {FCC4_FCCA, CTL_FCC, CTL_FCC}, {FCC5_FCCA, CTL_FCC, CTL_FCC}, {FCC6_FCCA, CTL_FCC, CTL_FCC}, -- cgit v1.2.3 From fed8f5e8303757dcd6b5a149eb6d6b23b3440e2d Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:11:36 +0300 Subject: ath: Map Albania to ETSI1_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. The CTL mappings for this regdomain code were now changed to: * 2.4GHz: ETSI * 5GHz: NO_CTL -> ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 437f5dca015a..ea0d53e21bae 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -299,7 +299,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { static struct country_code_to_enum_rd allCountries[] = { {CTRY_DEBUG, NO_ENUMRD, "DB"}, {CTRY_DEFAULT, FCC1_FCCA, "CO"}, - {CTRY_ALBANIA, NULL1_WORLD, "AL"}, + {CTRY_ALBANIA, ETSI1_WORLD, "AL"}, {CTRY_ALGERIA, NULL1_WORLD, "DZ"}, {CTRY_ARGENTINA, FCC3_WORLD, "AR"}, {CTRY_ARMENIA, ETSI4_WORLD, "AM"}, -- cgit v1.2.3 From 485daee92bde2b7ec85cb36ab6fdd0f8d2925af7 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:11:45 +0300 Subject: ath: Map Algeria to APL13_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. The CTL mappings for this regdomain code were now changed to: * 2.4GHz: ETSI * 5GHz: NO_CTL -> ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index ea0d53e21bae..37dfa164daf0 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -300,7 +300,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_DEBUG, NO_ENUMRD, "DB"}, {CTRY_DEFAULT, FCC1_FCCA, "CO"}, {CTRY_ALBANIA, ETSI1_WORLD, "AL"}, - {CTRY_ALGERIA, NULL1_WORLD, "DZ"}, + {CTRY_ALGERIA, APL13_WORLD, "DZ"}, {CTRY_ARGENTINA, FCC3_WORLD, "AR"}, {CTRY_ARMENIA, ETSI4_WORLD, "AM"}, {CTRY_ARUBA, ETSI1_WORLD, "AW"}, -- cgit v1.2.3 From 8120cc0b215c5100c10a1c9aef19532a28d83d62 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:11:49 +0300 Subject: ath: Map Australia to FCC3_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. This change itself doesn't change the selected CTL of this country and is only required to stay in sync with the QCA mappings. Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 37dfa164daf0..3a6110ba637d 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -304,7 +304,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_ARGENTINA, FCC3_WORLD, "AR"}, {CTRY_ARMENIA, ETSI4_WORLD, "AM"}, {CTRY_ARUBA, ETSI1_WORLD, "AW"}, - {CTRY_AUSTRALIA, FCC2_WORLD, "AU"}, + {CTRY_AUSTRALIA, FCC3_WORLD, "AU"}, {CTRY_AUSTRALIA2, FCC6_WORLD, "AU"}, {CTRY_AUSTRIA, ETSI1_WORLD, "AT"}, {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ"}, -- cgit v1.2.3 From 1507b32891c0f1b5041a61d3c41e93d54602f76d Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:11:55 +0300 Subject: ath: Map Bangladesh to APL1_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. The CTL mappings for this regdomain code were now changed to: * 2.4GHz: ETSI * 5GHz: NO_CTL -> FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 3a6110ba637d..d531ae0c9dd6 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -310,7 +310,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ"}, {CTRY_BAHAMAS, FCC3_WORLD, "BS"}, {CTRY_BAHRAIN, APL6_WORLD, "BH"}, - {CTRY_BANGLADESH, NULL1_WORLD, "BD"}, + {CTRY_BANGLADESH, APL1_WORLD, "BD"}, {CTRY_BARBADOS, FCC2_WORLD, "BB"}, {CTRY_BELARUS, ETSI1_WORLD, "BY"}, {CTRY_BELGIUM, ETSI1_WORLD, "BE"}, -- cgit v1.2.3 From 37090d9447050fa6234fa29ecea19165d0b41f64 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:12:01 +0300 Subject: ath: Map Brunei Darussalam to APL6_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. The CTL mappings for this regdomain code were now changed to: * 2.4GHz: ETSI * 5GHz: FCC -> ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index d531ae0c9dd6..b8f321664078 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -320,7 +320,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_BOLIVIA, APL1_ETSIC, "BO"}, {CTRY_BOSNIA_HERZ, ETSI1_WORLD, "BA"}, {CTRY_BRAZIL, FCC3_WORLD, "BR"}, - {CTRY_BRUNEI_DARUSSALAM, APL1_WORLD, "BN"}, + {CTRY_BRUNEI_DARUSSALAM, APL6_WORLD, "BN"}, {CTRY_BULGARIA, ETSI6_WORLD, "BG"}, {CTRY_CAMBODIA, ETSI1_WORLD, "KH"}, {CTRY_CANADA, FCC3_FCCA, "CA"}, -- cgit v1.2.3 From fed60f81a2d0839b2611929ab60b439e7d3d9714 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:12:05 +0300 Subject: ath: Map Bulgaria to ETSI1_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. This change itself doesn't change the selected CTL of this country and is only required to stay in sync with the QCA mappings. Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index b8f321664078..3039b9b50a8c 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -321,7 +321,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_BOSNIA_HERZ, ETSI1_WORLD, "BA"}, {CTRY_BRAZIL, FCC3_WORLD, "BR"}, {CTRY_BRUNEI_DARUSSALAM, APL6_WORLD, "BN"}, - {CTRY_BULGARIA, ETSI6_WORLD, "BG"}, + {CTRY_BULGARIA, ETSI1_WORLD, "BG"}, {CTRY_CAMBODIA, ETSI1_WORLD, "KH"}, {CTRY_CANADA, FCC3_FCCA, "CA"}, {CTRY_CANADA2, FCC6_FCCA, "CA"}, -- cgit v1.2.3 From 515e968624b2d9fd413dc7c90c24fb3c768a12a7 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:12:11 +0300 Subject: ath: Map Colombia to FCC1_FCCA The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. This change itself doesn't change the selected CTL of this country and is only required to stay in sync with the QCA mappings. Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 3039b9b50a8c..17f7e7768395 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -327,7 +327,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_CANADA2, FCC6_FCCA, "CA"}, {CTRY_CHILE, APL6_WORLD, "CL"}, {CTRY_CHINA, APL1_WORLD, "CN"}, - {CTRY_COLOMBIA, FCC1_FCCA, "CO"}, + {CTRY_COLOMBIA, FCC3_WORLD, "CO"}, {CTRY_COSTA_RICA, FCC1_WORLD, "CR"}, {CTRY_CROATIA, ETSI1_WORLD, "HR"}, {CTRY_CYPRUS, ETSI1_WORLD, "CY"}, -- cgit v1.2.3 From 0fa31a86998b558ce7ef21ef84bde175d9aba11d Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:12:15 +0300 Subject: ath: Map Czech to ETSI1_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. This change itself doesn't change the selected CTL of this country and is only required to stay in sync with the QCA mappings. Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 17f7e7768395..da0f958e927e 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -331,7 +331,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_COSTA_RICA, FCC1_WORLD, "CR"}, {CTRY_CROATIA, ETSI1_WORLD, "HR"}, {CTRY_CYPRUS, ETSI1_WORLD, "CY"}, - {CTRY_CZECH, ETSI3_WORLD, "CZ"}, + {CTRY_CZECH, ETSI1_WORLD, "CZ"}, {CTRY_DENMARK, ETSI1_WORLD, "DK"}, {CTRY_DOMINICAN_REPUBLIC, FCC1_FCCA, "DO"}, {CTRY_ECUADOR, FCC1_WORLD, "EC"}, -- cgit v1.2.3 From 143a9b9bd7ee9d63f216a164c04fe6e4ee129ed5 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:12:17 +0300 Subject: ath: Map Honduras to FCC3_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. The CTL mappings for this regdomain code were now changed to: * 2.4GHz: ETSI * 5GHz: NO_CTL -> FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index da0f958e927e..342f2625ad8a 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -348,7 +348,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_GUAM, FCC1_FCCA, "GU"}, {CTRY_GUATEMALA, FCC1_FCCA, "GT"}, {CTRY_HAITI, ETSI1_WORLD, "HT"}, - {CTRY_HONDURAS, NULL1_WORLD, "HN"}, + {CTRY_HONDURAS, FCC3_WORLD, "HN"}, {CTRY_HONG_KONG, FCC3_WORLD, "HK"}, {CTRY_HUNGARY, ETSI1_WORLD, "HU"}, {CTRY_ICELAND, ETSI1_WORLD, "IS"}, -- cgit v1.2.3 From 62ba2b22d12026a98557450753441aa9e2a9959d Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:12:32 +0300 Subject: ath: Map Isreal to ETSI3_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. The CTL mappings for this regdomain code were now changed to: * 2.4GHz: ETSI * 5GHz: NO_CTL -> ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 342f2625ad8a..44c7d5de900a 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -356,7 +356,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_INDONESIA, NULL1_WORLD, "ID"}, {CTRY_IRAN, APL1_WORLD, "IR"}, {CTRY_IRELAND, ETSI1_WORLD, "IE"}, - {CTRY_ISRAEL, NULL1_WORLD, "IL"}, + {CTRY_ISRAEL, ETSI3_WORLD, "IL"}, {CTRY_ITALY, ETSI1_WORLD, "IT"}, {CTRY_JAMAICA, FCC3_WORLD, "JM"}, -- cgit v1.2.3 From 64874ed2a73a4d743796ef103392606399a043cd Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:12:50 +0300 Subject: ath: Map Macedonia to ETSI1_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. The CTL mappings for this regdomain code were now changed to: * 2.4GHz: ETSI * 5GHz: NO_CTL -> ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 44c7d5de900a..dfe0754522a6 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -433,7 +433,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_LITHUANIA, ETSI1_WORLD, "LT"}, {CTRY_LUXEMBOURG, ETSI1_WORLD, "LU"}, {CTRY_MACAU, FCC2_WORLD, "MO"}, - {CTRY_MACEDONIA, NULL1_WORLD, "MK"}, + {CTRY_MACEDONIA, ETSI1_WORLD, "MK"}, {CTRY_MALAYSIA, APL8_WORLD, "MY"}, {CTRY_MALTA, ETSI1_WORLD, "MT"}, {CTRY_MAURITIUS, ETSI1_WORLD, "MU"}, -- cgit v1.2.3 From 823a64065adf27d94d27369bad5d2587821b0d98 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:12:56 +0300 Subject: ath: Map Malasia to FCC1_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. The CTL mappings for this regdomain code were now changed to: * 2.4GHz: ETSI * 5GHz: ETSI -> FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index dfe0754522a6..6d24c85dbdd7 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -434,7 +434,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_LUXEMBOURG, ETSI1_WORLD, "LU"}, {CTRY_MACAU, FCC2_WORLD, "MO"}, {CTRY_MACEDONIA, ETSI1_WORLD, "MK"}, - {CTRY_MALAYSIA, APL8_WORLD, "MY"}, + {CTRY_MALAYSIA, FCC1_WORLD, "MY"}, {CTRY_MALTA, ETSI1_WORLD, "MT"}, {CTRY_MAURITIUS, ETSI1_WORLD, "MU"}, {CTRY_MEXICO, FCC1_FCCA, "MX"}, -- cgit v1.2.3 From 9bfc2bb32e01c3a759dbef007cee938390157270 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:13:05 +0300 Subject: ath: Map New Zealand to FCC3_ETSIC The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. This change itself doesn't change the selected CTL of this country and is only required to stay in sync with the QCA mappings. Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 6d24c85dbdd7..035b023422e2 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -444,7 +444,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_NEPAL, APL1_WORLD, "NP"}, {CTRY_NETHERLANDS, ETSI1_WORLD, "NL"}, {CTRY_NETHERLANDS_ANTILLES, ETSI1_WORLD, "AN"}, - {CTRY_NEW_ZEALAND, FCC2_ETSIC, "NZ"}, + {CTRY_NEW_ZEALAND, FCC3_ETSIC, "NZ"}, {CTRY_NICARAGUA, FCC3_FCCA, "NI"}, {CTRY_NORWAY, ETSI1_WORLD, "NO"}, {CTRY_OMAN, FCC3_WORLD, "OM"}, -- cgit v1.2.3 From b5c11e4744062285acf6835c8bd123edb244a2f1 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:13:08 +0300 Subject: ath: Map Peru to APL1_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. This change itself doesn't change the selected CTL of this country and is only required to stay in sync with the QCA mappings. Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 035b023422e2..9ab23631d043 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -452,7 +452,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_PANAMA, FCC1_FCCA, "PA"}, {CTRY_PAPUA_NEW_GUINEA, FCC1_WORLD, "PG"}, {CTRY_PARAGUAY, FCC3_WORLD, "PY"}, - {CTRY_PERU, APL1_WORLD, "PE"}, + {CTRY_PERU, FCC3_WORLD, "PE"}, {CTRY_PHILIPPINES, APL1_WORLD, "PH"}, {CTRY_POLAND, ETSI1_WORLD, "PL"}, {CTRY_PORTUGAL, ETSI1_WORLD, "PT"}, -- cgit v1.2.3 From c454d4c258444522b1c07f59e989795d3c72cbac Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:13:15 +0300 Subject: ath: Map Philippines to FCC3_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. This change itself doesn't change the selected CTL of this country and is only required to stay in sync with the QCA mappings. Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 9ab23631d043..a10a1b8cb55b 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -453,7 +453,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_PAPUA_NEW_GUINEA, FCC1_WORLD, "PG"}, {CTRY_PARAGUAY, FCC3_WORLD, "PY"}, {CTRY_PERU, FCC3_WORLD, "PE"}, - {CTRY_PHILIPPINES, APL1_WORLD, "PH"}, + {CTRY_PHILIPPINES, FCC3_WORLD, "PH"}, {CTRY_POLAND, ETSI1_WORLD, "PL"}, {CTRY_PORTUGAL, ETSI1_WORLD, "PT"}, {CTRY_PUERTO_RICO, FCC1_FCCA, "PR"}, -- cgit v1.2.3 From 12f415566fb4487bd5ce6273ed15d1ab6340339c Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:13:22 +0300 Subject: ath: Map Romania to ETSI1_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. The CTL mappings for this regdomain code were now changed to: * 2.4GHz: ETSI * 5GHz: NO_CTL -> ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index a10a1b8cb55b..3afce206e049 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -458,7 +458,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_PORTUGAL, ETSI1_WORLD, "PT"}, {CTRY_PUERTO_RICO, FCC1_FCCA, "PR"}, {CTRY_QATAR, APL1_WORLD, "QA"}, - {CTRY_ROMANIA, NULL1_WORLD, "RO"}, + {CTRY_ROMANIA, ETSI1_WORLD, "RO"}, {CTRY_RUSSIA, NULL1_WORLD, "RU"}, {CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"}, {CTRY_SERBIA, ETSI1_WORLD, "RS"}, -- cgit v1.2.3 From b7e015132d85f511cfa242a6aa04644fea55fdbb Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:13:30 +0300 Subject: ath: Map Russia to ETSI8_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. The CTL mappings for this regdomain code were now changed to: * 2.4GHz: ETSI * 5GHz: NO_CTL -> ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 3afce206e049..4a70c52f2940 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -459,7 +459,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_PUERTO_RICO, FCC1_FCCA, "PR"}, {CTRY_QATAR, APL1_WORLD, "QA"}, {CTRY_ROMANIA, ETSI1_WORLD, "RO"}, - {CTRY_RUSSIA, NULL1_WORLD, "RU"}, + {CTRY_RUSSIA, ETSI8_WORLD, "RU"}, {CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"}, {CTRY_SERBIA, ETSI1_WORLD, "RS"}, {CTRY_SERBIA_MONTENEGRO, ETSI1_WORLD, "CS"}, -- cgit v1.2.3 From 054e077880027a469e44444dc9b18d4f2561dbf7 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:13:43 +0300 Subject: ath: Map Singapore to FCC3_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. The CTL mappings for this regdomain code were now changed to: * 2.4GHz: ETSI * 5GHz: ETSI -> FCC Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 4a70c52f2940..470fe45be3cd 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -463,7 +463,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"}, {CTRY_SERBIA, ETSI1_WORLD, "RS"}, {CTRY_SERBIA_MONTENEGRO, ETSI1_WORLD, "CS"}, - {CTRY_SINGAPORE, APL6_WORLD, "SG"}, + {CTRY_SINGAPORE, FCC3_WORLD, "SG"}, {CTRY_SLOVAKIA, ETSI1_WORLD, "SK"}, {CTRY_SLOVENIA, ETSI1_WORLD, "SI"}, {CTRY_SOUTH_AFRICA, FCC3_WORLD, "ZA"}, -- cgit v1.2.3 From 4e78075c48212aa5e17cf0d35ccc2cd077e6f09a Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:13:52 +0300 Subject: ath: Map Ukraine to ETSI9_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. The CTL mappings for this regdomain code were now changed to: * 2.4GHz: ETSI * 5GHz: NO_CTL -> ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 470fe45be3cd..44826f862cf7 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -479,7 +479,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_TUNISIA, ETSI3_WORLD, "TN"}, {CTRY_TURKEY, ETSI3_WORLD, "TR"}, {CTRY_UGANDA, FCC3_WORLD, "UG"}, - {CTRY_UKRAINE, NULL1_WORLD, "UA"}, + {CTRY_UKRAINE, ETSI9_WORLD, "UA"}, {CTRY_UAE, NULL1_WORLD, "AE"}, {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB"}, {CTRY_UNITED_STATES, FCC3_FCCA, "US"}, -- cgit v1.2.3 From f1abff21acc5c21bfba472c74d76f4430d06bdd3 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 23 May 2018 11:14:11 +0300 Subject: ath: Map Zimbabwe to ETSI1_WORLD The regdomain code is used to select the correct the correct conformance test limits (CTL) for a country. If the regdomain code isn't correctly mapped to the actual CTL entries in EEPROM then it could happen that the device violates the regulations. But it can also happen that the device is then not able to be used with its full txpower on all rates. The CTL mappings for this regdomain code were now changed to: * 2.4GHz: ETSI * 5GHz: NO_CTL -> ETSI Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 44826f862cf7..4021e37a225a 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -492,7 +492,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_VENEZUELA, APL2_ETSIC, "VE"}, {CTRY_VIET_NAM, NULL1_WORLD, "VN"}, {CTRY_YEMEN, NULL1_WORLD, "YE"}, - {CTRY_ZIMBABWE, NULL1_WORLD, "ZW"}, + {CTRY_ZIMBABWE, ETSI1_WORLD, "ZW"}, }; #endif -- cgit v1.2.3 From cf3c0ae6a32b5c3bb19b07d48dff646fc3896e51 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 23 May 2018 11:14:17 +0300 Subject: ath10k: remove useless test before clk_disable_unprepare clk_disable_unprepare() already checks that the clock pointer is valid. No need to test it before calling it. Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ahb.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index 35d10490f6c3..fa39ffffd34d 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -180,14 +180,11 @@ static void ath10k_ahb_clock_disable(struct ath10k *ar) { struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); - if (!IS_ERR_OR_NULL(ar_ahb->cmd_clk)) - clk_disable_unprepare(ar_ahb->cmd_clk); + clk_disable_unprepare(ar_ahb->cmd_clk); - if (!IS_ERR_OR_NULL(ar_ahb->ref_clk)) - clk_disable_unprepare(ar_ahb->ref_clk); + clk_disable_unprepare(ar_ahb->ref_clk); - if (!IS_ERR_OR_NULL(ar_ahb->rtc_clk)) - clk_disable_unprepare(ar_ahb->rtc_clk); + clk_disable_unprepare(ar_ahb->rtc_clk); } static int ath10k_ahb_rst_ctrl_init(struct ath10k *ar) -- cgit v1.2.3 From 9a81cc23dfef24e254d3ff15c52bf46f0736f4c2 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 23 May 2018 11:14:22 +0300 Subject: wcn36xx: fix buffer commit logic on TX path When wcn36xx_dxe_tx_frame() is entered while the device is still processing the queue asyncronously, we are racing against the firmware code with updates to the buffer descriptors. Presumably, the firmware scans the ring buffer that holds the descriptors and scans for a valid control descriptor, and then assumes that the next descriptor contains the payload. If, however, the control descriptor is marked valid, but the payload descriptor isn't, the packet is not sent out. Another issue with the current code is that is lacks memory barriers before descriptors are marked valid. This is important because the CPU may reorder writes to memory, even if it is allocated as coherent DMA area, and hence the device may see incompletely written data. To fix this, the code in wcn36xx_dxe_tx_frame() was restructured a bit so that the payload descriptor is made valid before the control descriptor. Memory barriers are added to ensure coherency of shared memory areas. Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/dxe.c | 75 +++++++++++++++++----------------- 1 file changed, 38 insertions(+), 37 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index bd2b946a65c9..3d1cf7dd1f8e 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -642,8 +642,8 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, struct sk_buff *skb, bool is_low) { - struct wcn36xx_dxe_ctl *ctl = NULL; - struct wcn36xx_dxe_desc *desc = NULL; + struct wcn36xx_dxe_desc *desc_bd, *desc_skb; + struct wcn36xx_dxe_ctl *ctl_bd, *ctl_skb; struct wcn36xx_dxe_ch *ch = NULL; unsigned long flags; int ret; @@ -651,74 +651,75 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, ch = is_low ? &wcn->dxe_tx_l_ch : &wcn->dxe_tx_h_ch; spin_lock_irqsave(&ch->lock, flags); - ctl = ch->head_blk_ctl; + ctl_bd = ch->head_blk_ctl; + ctl_skb = ctl_bd->next; /* * If skb is not null that means that we reached the tail of the ring * hence ring is full. Stop queues to let mac80211 back off until ring * has an empty slot again. */ - if (NULL != ctl->next->skb) { + if (NULL != ctl_skb->skb) { ieee80211_stop_queues(wcn->hw); wcn->queues_stopped = true; spin_unlock_irqrestore(&ch->lock, flags); return -EBUSY; } - ctl->skb = NULL; - desc = ctl->desc; + if (unlikely(ctl_skb->bd_cpu_addr)) { + wcn36xx_err("bd_cpu_addr cannot be NULL for skb DXE\n"); + ret = -EINVAL; + goto unlock; + } + + desc_bd = ctl_bd->desc; + desc_skb = ctl_skb->desc; + + ctl_bd->skb = NULL; /* write buffer descriptor */ - memcpy(ctl->bd_cpu_addr, bd, sizeof(*bd)); + memcpy(ctl_bd->bd_cpu_addr, bd, sizeof(*bd)); /* Set source address of the BD we send */ - desc->src_addr_l = ctl->bd_phy_addr; - - desc->dst_addr_l = ch->dxe_wq; - desc->fr_len = sizeof(struct wcn36xx_tx_bd); - desc->ctrl = ch->ctrl_bd; + desc_bd->src_addr_l = ctl_bd->bd_phy_addr; + desc_bd->dst_addr_l = ch->dxe_wq; + desc_bd->fr_len = sizeof(struct wcn36xx_tx_bd); wcn36xx_dbg(WCN36XX_DBG_DXE, "DXE TX\n"); wcn36xx_dbg_dump(WCN36XX_DBG_DXE_DUMP, "DESC1 >>> ", - (char *)desc, sizeof(*desc)); + (char *)desc_bd, sizeof(*desc_bd)); wcn36xx_dbg_dump(WCN36XX_DBG_DXE_DUMP, - "BD >>> ", (char *)ctl->bd_cpu_addr, + "BD >>> ", (char *)ctl_bd->bd_cpu_addr, sizeof(struct wcn36xx_tx_bd)); - /* Set source address of the SKB we send */ - ctl = ctl->next; - desc = ctl->desc; - if (ctl->bd_cpu_addr) { - wcn36xx_err("bd_cpu_addr cannot be NULL for skb DXE\n"); - ret = -EINVAL; - goto unlock; - } - - desc->src_addr_l = dma_map_single(wcn->dev, - skb->data, - skb->len, - DMA_TO_DEVICE); - if (dma_mapping_error(wcn->dev, desc->src_addr_l)) { + desc_skb->src_addr_l = dma_map_single(wcn->dev, + skb->data, + skb->len, + DMA_TO_DEVICE); + if (dma_mapping_error(wcn->dev, desc_skb->src_addr_l)) { dev_err(wcn->dev, "unable to DMA map src_addr_l\n"); ret = -ENOMEM; goto unlock; } - ctl->skb = skb; - desc->dst_addr_l = ch->dxe_wq; - desc->fr_len = ctl->skb->len; - - /* set dxe descriptor to VALID */ - desc->ctrl = ch->ctrl_skb; + ctl_skb->skb = skb; + desc_skb->dst_addr_l = ch->dxe_wq; + desc_skb->fr_len = ctl_skb->skb->len; wcn36xx_dbg_dump(WCN36XX_DBG_DXE_DUMP, "DESC2 >>> ", - (char *)desc, sizeof(*desc)); + (char *)desc_skb, sizeof(*desc_skb)); wcn36xx_dbg_dump(WCN36XX_DBG_DXE_DUMP, "SKB >>> ", - (char *)ctl->skb->data, ctl->skb->len); + (char *)ctl_skb->skb->data, ctl_skb->skb->len); /* Move the head of the ring to the next empty descriptor */ - ch->head_blk_ctl = ctl->next; + ch->head_blk_ctl = ctl_skb->next; + + /* Commit all previous writes and set descriptors to VALID */ + wmb(); + desc_skb->ctrl = ch->ctrl_skb; + wmb(); + desc_bd->ctrl = ch->ctrl_bd; /* * When connected and trying to send data frame chip can be in sleep -- cgit v1.2.3 From 57e06e0e2a862bd40df47c7ad752fcad1d04c259 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 23 May 2018 11:14:26 +0300 Subject: wcn36xx: set DMA mask explicitly The device takes 32-bit addresses only, so inform the DMA API about it. This is the default on msm8016, so that doesn't change anything, but it's best practice to be explicit. Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index e3b91b3b38ef..e6330ad372b3 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -1309,6 +1309,12 @@ static int wcn36xx_probe(struct platform_device *pdev) mutex_init(&wcn->hal_mutex); mutex_init(&wcn->scan_lock); + ret = dma_set_mask_and_coherent(wcn->dev, DMA_BIT_MASK(32)); + if (ret < 0) { + wcn36xx_err("failed to set DMA mask: %d\n", ret); + goto out_wq; + } + INIT_WORK(&wcn->scan_work, wcn36xx_hw_scan_worker); wcn->smd_channel = qcom_wcnss_open_channel(wcnss, "WLAN_CTRL", wcn36xx_smd_rsp_process, hw); -- cgit v1.2.3 From ba437e72378c91a2fd6766014cc02fa98b61f2dc Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 23 May 2018 11:14:30 +0300 Subject: wcn36xx: don't disable RX IRQ from handler There's no need to disable the IRQ from inside its handler. Instead just grab the spinlock of the channel that is being processed. Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/dxe.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index 3d1cf7dd1f8e..d6dd47b211ba 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -476,9 +476,8 @@ static irqreturn_t wcn36xx_irq_rx_ready(int irq, void *dev) { struct wcn36xx *wcn = (struct wcn36xx *)dev; - disable_irq_nosync(wcn->rx_irq); wcn36xx_dxe_rx_frame(wcn); - enable_irq(wcn->rx_irq); + return IRQ_HANDLED; } @@ -514,8 +513,8 @@ out_err: static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch) { - struct wcn36xx_dxe_ctl *ctl = ch->head_blk_ctl; - struct wcn36xx_dxe_desc *dxe = ctl->desc; + struct wcn36xx_dxe_desc *dxe; + struct wcn36xx_dxe_ctl *ctl; dma_addr_t dma_addr; struct sk_buff *skb; int ret = 0, int_mask; @@ -529,6 +528,11 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn, int_mask = WCN36XX_DXE_INT_CH3_MASK; } + spin_lock(&ch->lock); + + ctl = ch->head_blk_ctl; + dxe = ctl->desc; + while (!(READ_ONCE(dxe->ctrl) & WCN36xx_DXE_CTRL_VLD)) { skb = ctl->skb; dma_addr = dxe->dst_addr_l; @@ -549,6 +553,9 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn, wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_ENCH_ADDR, int_mask); ch->head_blk_ctl = ctl; + + spin_unlock(&ch->lock); + return 0; } -- cgit v1.2.3 From edd23ab403cf092a20ea185770f197f502ac32f0 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 23 May 2018 11:14:35 +0300 Subject: wcn36xx: clear all masks in RX interrupt Like on the TX side, check for the interrupt reason when the RX interrupt is latched and clear the ERR, DONE and ED masks. This seems to help with connection timeouts and network stream starvatations. And FWIW, the downstream driver does the same thing. Note that in analogy to the TX side, WCN36XX_DXE_0_INT_CLR should be set to WCN36XX_INT_MASK_CHAN_RX_{L,H} rather than WCN36XX_DXE_INT_CH{1,3}_MASK. It did the right thing however, as the defines happen to have identical values. Also, instead of determining register addresses and values inside wcn36xx_rx_handle_packets(), pass them as arguments. Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/dxe.c | 62 ++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index d6dd47b211ba..d11c9c536627 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -511,23 +511,40 @@ out_err: } static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn, - struct wcn36xx_dxe_ch *ch) + struct wcn36xx_dxe_ch *ch, + u32 ctrl, + u32 en_mask, + u32 int_mask, + u32 status_reg) { struct wcn36xx_dxe_desc *dxe; struct wcn36xx_dxe_ctl *ctl; dma_addr_t dma_addr; struct sk_buff *skb; - int ret = 0, int_mask; - u32 value; + u32 int_reason; + int ret; - if (ch->ch_type == WCN36XX_DXE_CH_RX_L) { - value = WCN36XX_DXE_CTRL_RX_L; - int_mask = WCN36XX_DXE_INT_CH1_MASK; - } else { - value = WCN36XX_DXE_CTRL_RX_H; - int_mask = WCN36XX_DXE_INT_CH3_MASK; + wcn36xx_dxe_read_register(wcn, status_reg, &int_reason); + wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_CLR, int_mask); + + if (int_reason & WCN36XX_CH_STAT_INT_ERR_MASK) { + wcn36xx_dxe_write_register(wcn, + WCN36XX_DXE_0_INT_ERR_CLR, + int_mask); + + wcn36xx_err("DXE IRQ reported error on RX channel\n"); } + if (int_reason & WCN36XX_CH_STAT_INT_DONE_MASK) + wcn36xx_dxe_write_register(wcn, + WCN36XX_DXE_0_INT_DONE_CLR, + int_mask); + + if (int_reason & WCN36XX_CH_STAT_INT_ED_MASK) + wcn36xx_dxe_write_register(wcn, + WCN36XX_DXE_0_INT_ED_CLR, + int_mask); + spin_lock(&ch->lock); ctl = ch->head_blk_ctl; @@ -546,11 +563,11 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn, wcn36xx_rx_skb(wcn, skb); } /* else keep old skb not submitted and use it for rx DMA */ - dxe->ctrl = value; + dxe->ctrl = ctrl; ctl = ctl->next; dxe = ctl->desc; } - wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_ENCH_ADDR, int_mask); + wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_ENCH_ADDR, en_mask); ch->head_blk_ctl = ctl; @@ -566,19 +583,20 @@ void wcn36xx_dxe_rx_frame(struct wcn36xx *wcn) wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_INT_SRC_RAW_REG, &int_src); /* RX_LOW_PRI */ - if (int_src & WCN36XX_DXE_INT_CH1_MASK) { - wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_CLR, - WCN36XX_DXE_INT_CH1_MASK); - wcn36xx_rx_handle_packets(wcn, &(wcn->dxe_rx_l_ch)); - } + if (int_src & WCN36XX_DXE_INT_CH1_MASK) + wcn36xx_rx_handle_packets(wcn, &wcn->dxe_rx_l_ch, + WCN36XX_DXE_CTRL_RX_L, + WCN36XX_DXE_INT_CH1_MASK, + WCN36XX_INT_MASK_CHAN_RX_L, + WCN36XX_DXE_CH_STATUS_REG_ADDR_RX_L); /* RX_HIGH_PRI */ - if (int_src & WCN36XX_DXE_INT_CH3_MASK) { - /* Clean up all the INT within this channel */ - wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_CLR, - WCN36XX_DXE_INT_CH3_MASK); - wcn36xx_rx_handle_packets(wcn, &(wcn->dxe_rx_h_ch)); - } + if (int_src & WCN36XX_DXE_INT_CH3_MASK) + wcn36xx_rx_handle_packets(wcn, &wcn->dxe_rx_h_ch, + WCN36XX_DXE_CTRL_RX_H, + WCN36XX_DXE_INT_CH3_MASK, + WCN36XX_INT_MASK_CHAN_RX_H, + WCN36XX_DXE_CH_STATUS_REG_ADDR_RX_H); if (!int_src) wcn36xx_warn("No DXE interrupt pending\n"); -- cgit v1.2.3 From ce1d4be82b1009374f7bea0229fb6758cb1afb84 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 23 May 2018 11:14:40 +0300 Subject: wcn36xx: only handle packets when ED or DONE bit is set On RX and TX interrupts, check for the WCN36XX_CH_STAT_INT_ED_MASK or WCN36XX_CH_STAT_INT_DONE_MASK in the interrupt reason register, and only handle packets when it is set. This way, reap_tx_dxes() is only invoked when needed. This brings the dequeing logic in line with what the prima downstream driver is doing. While at it, also log the interrupt reason. Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/dxe.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index d11c9c536627..8c64e05ca3b7 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -430,8 +430,12 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev) WCN36XX_INT_MASK_CHAN_TX_H); } - wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready high\n"); - reap_tx_dxes(wcn, &wcn->dxe_tx_h_ch); + wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready high, reason %08x\n", + int_reason); + + if (int_reason & (WCN36XX_CH_STAT_INT_DONE_MASK | + WCN36XX_CH_STAT_INT_ED_MASK)) + reap_tx_dxes(wcn, &wcn->dxe_tx_h_ch); } if (int_src & WCN36XX_INT_MASK_CHAN_TX_L) { @@ -465,8 +469,12 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev) WCN36XX_INT_MASK_CHAN_TX_L); } - wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready low\n"); - reap_tx_dxes(wcn, &wcn->dxe_tx_l_ch); + wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready low, reason %08x\n", + int_reason); + + if (int_reason & (WCN36XX_CH_STAT_INT_DONE_MASK | + WCN36XX_CH_STAT_INT_ED_MASK)) + reap_tx_dxes(wcn, &wcn->dxe_tx_l_ch); } return IRQ_HANDLED; @@ -545,6 +553,10 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn, WCN36XX_DXE_0_INT_ED_CLR, int_mask); + if (!(int_reason & (WCN36XX_CH_STAT_INT_DONE_MASK | + WCN36XX_CH_STAT_INT_ED_MASK))) + return 0; + spin_lock(&ch->lock); ctl = ch->head_blk_ctl; -- cgit v1.2.3 From 18c7ed138824119f2ef9c9019e222e3e750b42b8 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 23 May 2018 11:14:44 +0300 Subject: wcn36xx: consider CTRL_EOP bit when looking for valid descriptors In reap_tx_dxes(), when we iterate over the linked descriptors, only consider such valid that have WCN36xx_DXE_CTRL_EOP set. This is what the prima downstream driver is doing as well. Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/dxe.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index 8c64e05ca3b7..06cfe8d311f3 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -370,7 +370,9 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch) do { if (READ_ONCE(ctl->desc->ctrl) & WCN36xx_DXE_CTRL_VLD) break; - if (ctl->skb) { + + if (ctl->skb && + READ_ONCE(ctl->desc->ctrl) & WCN36xx_DXE_CTRL_EOP) { dma_unmap_single(wcn->dev, ctl->desc->src_addr_l, ctl->skb->len, DMA_TO_DEVICE); info = IEEE80211_SKB_CB(ctl->skb); -- cgit v1.2.3 From 2a46c829a9266bf2a2be1a3d25dbac5fcd4eb9c1 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 23 May 2018 11:14:50 +0300 Subject: wcn36xx: set PREASSOC and IDLE stated when BSS info changes When a BSSID is joined, set the link status to 'preassoc', and set it to 'idle' when the BSS is deleted. This is what the downstream driver is doing, and it seems to improve the reliability during connect/disconnect stress tests. Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/main.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index e6330ad372b3..662e50540b07 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -798,6 +798,8 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, if (!is_zero_ether_addr(bss_conf->bssid)) { vif_priv->is_joining = true; vif_priv->bss_index = WCN36XX_HAL_BSS_INVALID_IDX; + wcn36xx_smd_set_link_st(wcn, bss_conf->bssid, vif->addr, + WCN36XX_HAL_LINK_PREASSOC_STATE); wcn36xx_smd_join(wcn, bss_conf->bssid, vif->addr, WCN36XX_HW_CHANNEL(wcn)); wcn36xx_smd_config_bss(wcn, vif, NULL, @@ -805,6 +807,8 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, } else { vif_priv->is_joining = false; wcn36xx_smd_delete_bss(wcn, vif); + wcn36xx_smd_set_link_st(wcn, bss_conf->bssid, vif->addr, + WCN36XX_HAL_LINK_IDLE_STATE); vif_priv->encrypt_type = WCN36XX_HAL_ED_NONE; } } -- cgit v1.2.3 From 773f9a28bcdafd6cb77fb1afc545c62746d53990 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 23 May 2018 11:14:55 +0300 Subject: wcn36xx: drain pending indicator messages on shutdown When the interface is shut down, wcn36xx_smd_close() potentially races against the queue worker. Make sure to cancel the work, and then free all the remnants in hal_ind_queue manually. This is again just a theoretical issue, not something that was triggered in the wild. Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/smd.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index ea74f2b92df5..0a505b5e038b 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -2513,5 +2513,11 @@ out: void wcn36xx_smd_close(struct wcn36xx *wcn) { + struct wcn36xx_hal_ind_msg *msg, *tmp; + + cancel_work_sync(&wcn->hal_ind_work); destroy_workqueue(wcn->hal_ind_wq); + + list_for_each_entry_safe(msg, tmp, &wcn->hal_ind_queue, list) + kfree(msg); } -- cgit v1.2.3 From a50c6c8412f7114cbb0514dbea7a5a9a3d317479 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 23 May 2018 11:14:59 +0300 Subject: wcn36xx: simplify wcn36xx_smd_open() Drop the extra warning about failed allocations, both the core and the only caller of this function will warn loud enough in such cases. Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/smd.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 0a505b5e038b..43c8aa79fad4 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -2494,21 +2494,15 @@ static void wcn36xx_ind_smd_work(struct work_struct *work) } int wcn36xx_smd_open(struct wcn36xx *wcn) { - int ret = 0; wcn->hal_ind_wq = create_freezable_workqueue("wcn36xx_smd_ind"); - if (!wcn->hal_ind_wq) { - wcn36xx_err("failed to allocate wq\n"); - ret = -ENOMEM; - goto out; - } + if (!wcn->hal_ind_wq) + return -ENOMEM; + INIT_WORK(&wcn->hal_ind_work, wcn36xx_ind_smd_work); INIT_LIST_HEAD(&wcn->hal_ind_queue); spin_lock_init(&wcn->hal_ind_lock); return 0; - -out: - return ret; } void wcn36xx_smd_close(struct wcn36xx *wcn) -- cgit v1.2.3 From ffbc9197b4721634dc6c0fefa9b31e565fa89cee Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 23 May 2018 11:15:03 +0300 Subject: wcn36xx: improve debug and error messages for SMD Add a missing newline in wcn36xx_smd_send_and_wait() and also log the command request and response type that was processed. Signed-off-by: Daniel Mack Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/smd.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 43c8aa79fad4..b855a58d5aac 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -252,23 +252,29 @@ static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len) { int ret = 0; unsigned long start; + struct wcn36xx_hal_msg_header *hdr = + (struct wcn36xx_hal_msg_header *)wcn->hal_buf; + u16 req_type = hdr->msg_type; + wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "HAL >>> ", wcn->hal_buf, len); init_completion(&wcn->hal_rsp_compl); start = jiffies; ret = rpmsg_send(wcn->smd_channel, wcn->hal_buf, len); if (ret) { - wcn36xx_err("HAL TX failed\n"); + wcn36xx_err("HAL TX failed for req %d\n", req_type); goto out; } if (wait_for_completion_timeout(&wcn->hal_rsp_compl, msecs_to_jiffies(HAL_MSG_TIMEOUT)) <= 0) { - wcn36xx_err("Timeout! No SMD response in %dms\n", - HAL_MSG_TIMEOUT); + wcn36xx_err("Timeout! No SMD response to req %d in %dms\n", + req_type, HAL_MSG_TIMEOUT); ret = -ETIME; goto out; } - wcn36xx_dbg(WCN36XX_DBG_SMD, "SMD command completed in %dms", + wcn36xx_dbg(WCN36XX_DBG_SMD, + "SMD command (req %d, rsp %d) completed in %dms\n", + req_type, hdr->msg_type, jiffies_to_msecs(jiffies - start)); out: return ret; -- cgit v1.2.3 From f40105e6747892e8edab94020567c158c9bec0df Mon Sep 17 00:00:00 2001 From: Sriram R Date: Tue, 15 May 2018 14:39:48 +0530 Subject: ath: add support to get the detected radar specifications This enables ath10k/ath9k drivers to collect the specifications of the radar type once it is detected by the dfs pattern detector unit. Usage of the collected info is specific to driver implementation. For example, collected radar info could be used by the host driver to send to co-processors for additional processing/validation. Note: 'radar_detector_specs' data containing the specifications of different radar types which was private within dfs_pattern_detector/ dfs_pri_detector is now shared with drivers as well for making use of this information. Signed-off-by: Sriram R Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- drivers/net/wireless/ath/ath9k/dfs.c | 2 +- drivers/net/wireless/ath/dfs_pattern_detector.c | 5 ++++- drivers/net/wireless/ath/dfs_pattern_detector.h | 3 ++- drivers/net/wireless/ath/dfs_pri_detector.h | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 46fb96ee5852..1bccac002e97 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3757,7 +3757,7 @@ static void ath10k_dfs_radar_report(struct ath10k *ar, ATH10K_DFS_STAT_INC(ar, pulses_detected); - if (!ar->dfs_detector->add_pulse(ar->dfs_detector, &pe)) { + if (!ar->dfs_detector->add_pulse(ar->dfs_detector, &pe, NULL)) { ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs no pulse pattern detected, yet\n"); return; diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c index c8844f55574c..acb9602aa464 100644 --- a/drivers/net/wireless/ath/ath9k/dfs.c +++ b/drivers/net/wireless/ath/ath9k/dfs.c @@ -277,7 +277,7 @@ ath9k_dfs_process_radar_pulse(struct ath_softc *sc, struct pulse_event *pe) DFS_STAT_INC(sc, pulses_processed); if (pd == NULL) return; - if (!pd->add_pulse(pd, pe)) + if (!pd->add_pulse(pd, pe, NULL)) return; DFS_STAT_INC(sc, radar_detected); ieee80211_radar_detected(sc->hw); diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c index 448b83eea810..d52b31b45df7 100644 --- a/drivers/net/wireless/ath/dfs_pattern_detector.c +++ b/drivers/net/wireless/ath/dfs_pattern_detector.c @@ -268,7 +268,8 @@ static void dpd_exit(struct dfs_pattern_detector *dpd) } static bool -dpd_add_pulse(struct dfs_pattern_detector *dpd, struct pulse_event *event) +dpd_add_pulse(struct dfs_pattern_detector *dpd, struct pulse_event *event, + struct radar_detector_specs *rs) { u32 i; struct channel_detector *cd; @@ -294,6 +295,8 @@ dpd_add_pulse(struct dfs_pattern_detector *dpd, struct pulse_event *event) struct pri_detector *pd = cd->detectors[i]; struct pri_sequence *ps = pd->add_pulse(pd, event); if (ps != NULL) { + if (rs != NULL) + memcpy(rs, pd->rs, sizeof(*rs)); ath_dbg(dpd->common, DFS, "DFS: radar found on freq=%d: id=%d, pri=%d, " "count=%d, count_false=%d\n", diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.h b/drivers/net/wireless/ath/dfs_pattern_detector.h index 92be3530e9b5..18db6f4f3568 100644 --- a/drivers/net/wireless/ath/dfs_pattern_detector.h +++ b/drivers/net/wireless/ath/dfs_pattern_detector.h @@ -97,7 +97,8 @@ struct dfs_pattern_detector { bool (*set_dfs_domain)(struct dfs_pattern_detector *dpd, enum nl80211_dfs_regions region); bool (*add_pulse)(struct dfs_pattern_detector *dpd, - struct pulse_event *pe); + struct pulse_event *pe, + struct radar_detector_specs *rs); struct ath_dfs_pool_stats (*get_stats)(struct dfs_pattern_detector *dpd); enum nl80211_dfs_regions region; diff --git a/drivers/net/wireless/ath/dfs_pri_detector.h b/drivers/net/wireless/ath/dfs_pri_detector.h index 79f0fff4d1e6..86339f2b4d3a 100644 --- a/drivers/net/wireless/ath/dfs_pri_detector.h +++ b/drivers/net/wireless/ath/dfs_pri_detector.h @@ -62,8 +62,9 @@ struct pri_detector { (*add_pulse)(struct pri_detector *de, struct pulse_event *e); void (*reset) (struct pri_detector *de, u64 ts); -/* private: internal use only */ const struct radar_detector_specs *rs; + +/* private: internal use only */ u64 last_ts; struct list_head sequences; struct list_head pulses; -- cgit v1.2.3 From 6f6eb1bcbeff48c875617b800f00f1c5d1b12290 Mon Sep 17 00:00:00 2001 From: Sriram R Date: Tue, 15 May 2018 14:39:49 +0530 Subject: ath10k: DFS Host Confirmation In the 10.4-3.6 firmware branch there's a new DFS Host confirmation feature which is advertised using WMI_SERVICE_HOST_DFS_CHECK_SUPPORT flag. This new features enables the ath10k host to send information to the firmware on the specifications of detected radar type. This allows the firmware to validate if the host's radar pattern detector unit is operational and check if the radar information shared by host matches the radar pulses sent as phy error events from firmware. If the check fails the firmware won't allow use of DFS channels on AP mode when using FCC regulatory region. Hence this patch is mandatory when using a firmware from 10.4-3.6 branch. Else, DFS channels on FCC regions cannot be used. Supported Chipsets : QCA9984/QCA9888/QCA4019 Firmware Version : 10.4-3.6-00104 Signed-off-by: Sriram R Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 21 ++++ drivers/net/wireless/ath/ath10k/mac.c | 12 ++ drivers/net/wireless/ath/ath10k/wmi-ops.h | 32 +++++ drivers/net/wireless/ath/ath10k/wmi.c | 186 ++++++++++++++++++++++++++++-- drivers/net/wireless/ath/ath10k/wmi.h | 32 +++++ 5 files changed, 273 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index eb7ff1116442..951dbdd1c9eb 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -176,6 +176,7 @@ struct ath10k_wmi { struct completion service_ready; struct completion unified_ready; struct completion barrier; + struct completion radar_confirm; wait_queue_head_t tx_credits_wq; DECLARE_BITMAP(svc_map, WMI_SERVICE_MAX); struct wmi_cmd_map *cmd; @@ -378,6 +379,21 @@ struct ath10k_dfs_stats { u32 radar_detected; }; +enum ath10k_radar_confirmation_state { + ATH10K_RADAR_CONFIRMATION_IDLE = 0, + ATH10K_RADAR_CONFIRMATION_INPROGRESS, + ATH10K_RADAR_CONFIRMATION_STOPPED, +}; + +struct ath10k_radar_found_info { + u32 pri_min; + u32 pri_max; + u32 width_min; + u32 width_max; + u32 sidx_min; + u32 sidx_max; +}; + #define ATH10K_MAX_NUM_PEER_IDS (1 << 11) /* htt rx_desc limit */ struct ath10k_peer { @@ -1110,6 +1126,11 @@ struct ath10k { u32 sta_tid_stats_mask; + /* protected by data_lock */ + enum ath10k_radar_confirmation_state radar_conf_state; + struct ath10k_radar_found_info last_radar_info; + struct work_struct radar_confirmation_work; + /* must be last */ u8 drv_priv[0] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index e3b67ffdab72..e9c2fb318c03 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3217,6 +3217,15 @@ static void ath10k_reg_notifier(struct wiphy *wiphy, ar->hw->wiphy->bands[NL80211_BAND_5GHZ]); } +static void ath10k_stop_radar_confirmation(struct ath10k *ar) +{ + spin_lock_bh(&ar->data_lock); + ar->radar_conf_state = ATH10K_RADAR_CONFIRMATION_STOPPED; + spin_unlock_bh(&ar->data_lock); + + cancel_work_sync(&ar->radar_confirmation_work); +} + /***************/ /* TX handlers */ /***************/ @@ -4333,6 +4342,7 @@ void ath10k_halt(struct ath10k *ar) ath10k_scan_finish(ar); ath10k_peer_cleanup_all(ar); + ath10k_stop_radar_confirmation(ar); ath10k_core_stop(ar); ath10k_hif_power_down(ar); @@ -4758,6 +4768,8 @@ static int ath10k_start(struct ieee80211_hw *hw) ath10k_spectral_start(ar); ath10k_thermal_set_throttling(ar); + ar->radar_conf_state = ATH10K_RADAR_CONFIRMATION_IDLE; + mutex_unlock(&ar->conf_mutex); return 0; diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index e37d16b31afe..5ecce04005d2 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -55,6 +55,8 @@ struct wmi_ops { struct wmi_wow_ev_arg *arg); int (*pull_echo_ev)(struct ath10k *ar, struct sk_buff *skb, struct wmi_echo_ev_arg *arg); + int (*pull_dfs_status_ev)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_dfs_status_ev_arg *arg); int (*pull_svc_avail)(struct ath10k *ar, struct sk_buff *skb, struct wmi_svc_avail_ev_arg *arg); @@ -188,6 +190,9 @@ struct wmi_ops { const struct wmi_tdls_peer_update_cmd_arg *arg, const struct wmi_tdls_peer_capab_arg *cap, const struct wmi_channel_arg *chan); + struct sk_buff *(*gen_radar_found) + (struct ath10k *ar, + const struct ath10k_radar_found_info *arg); struct sk_buff *(*gen_adaptive_qcs)(struct ath10k *ar, bool enable); struct sk_buff *(*gen_pdev_get_tpc_config)(struct ath10k *ar, u32 param); @@ -395,6 +400,16 @@ ath10k_wmi_pull_echo_ev(struct ath10k *ar, struct sk_buff *skb, return ar->wmi.ops->pull_echo_ev(ar, skb, arg); } +static inline int +ath10k_wmi_pull_dfs_status(struct ath10k *ar, struct sk_buff *skb, + struct wmi_dfs_status_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_dfs_status_ev) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_dfs_status_ev(ar, skb, arg); +} + static inline enum wmi_txbf_conf ath10k_wmi_get_txbf_conf_scheme(struct ath10k *ar) { @@ -1511,4 +1526,21 @@ ath10k_wmi_pdev_get_tpc_table_cmdid(struct ath10k *ar, u32 param) ar->wmi.cmd->pdev_get_tpc_table_cmdid); } +static inline int +ath10k_wmi_report_radar_found(struct ath10k *ar, + const struct ath10k_radar_found_info *arg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_radar_found) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_radar_found(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->radar_found_cmdid); +} + #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 1bccac002e97..f97ab795cf2e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -34,6 +34,7 @@ #define ATH10K_WMI_BARRIER_ECHO_ID 0xBA991E9 #define ATH10K_WMI_BARRIER_TIMEOUT_HZ (3 * HZ) +#define ATH10K_WMI_DFS_CONF_TIMEOUT_HZ (HZ / 6) /* MAIN WMI cmd track */ static struct wmi_cmd_map wmi_cmd_map = { @@ -199,6 +200,7 @@ static struct wmi_cmd_map wmi_cmd_map = { .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, .pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED, .pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED, + .radar_found_cmdid = WMI_CMD_UNSUPPORTED, }; /* 10.X WMI cmd track */ @@ -367,6 +369,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = { .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, .pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED, .pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED, + .radar_found_cmdid = WMI_CMD_UNSUPPORTED, }; /* 10.2.4 WMI cmd track */ @@ -535,6 +538,7 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = { .pdev_bss_chan_info_request_cmdid = WMI_10_2_PDEV_BSS_CHAN_INFO_REQUEST_CMDID, .pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED, + .radar_found_cmdid = WMI_CMD_UNSUPPORTED, }; /* 10.4 WMI cmd track */ @@ -745,6 +749,7 @@ static struct wmi_cmd_map wmi_10_4_cmd_map = { .tdls_set_state_cmdid = WMI_10_4_TDLS_SET_STATE_CMDID, .tdls_peer_update_cmdid = WMI_10_4_TDLS_PEER_UPDATE_CMDID, .tdls_set_offchan_mode_cmdid = WMI_10_4_TDLS_SET_OFFCHAN_MODE_CMDID, + .radar_found_cmdid = WMI_10_4_RADAR_FOUND_CMDID, }; /* MAIN WMI VDEV param map */ @@ -1490,6 +1495,7 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = { .pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, .pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED, + .radar_found_cmdid = WMI_CMD_UNSUPPORTED, }; static struct wmi_pdev_param_map wmi_10_4_pdev_param_map = { @@ -3683,6 +3689,68 @@ void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb) ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n"); } +static void ath10k_radar_detected(struct ath10k *ar) +{ + ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs radar detected\n"); + ATH10K_DFS_STAT_INC(ar, radar_detected); + + /* Control radar events reporting in debugfs file + * dfs_block_radar_events + */ + if (ar->dfs_block_radar_events) + ath10k_info(ar, "DFS Radar detected, but ignored as requested\n"); + else + ieee80211_radar_detected(ar->hw); +} + +static void ath10k_radar_confirmation_work(struct work_struct *work) +{ + struct ath10k *ar = container_of(work, struct ath10k, + radar_confirmation_work); + struct ath10k_radar_found_info radar_info; + int ret, time_left; + + reinit_completion(&ar->wmi.radar_confirm); + + spin_lock_bh(&ar->data_lock); + memcpy(&radar_info, &ar->last_radar_info, sizeof(radar_info)); + spin_unlock_bh(&ar->data_lock); + + ret = ath10k_wmi_report_radar_found(ar, &radar_info); + if (ret) { + ath10k_warn(ar, "failed to send radar found %d\n", ret); + goto wait_complete; + } + + time_left = wait_for_completion_timeout(&ar->wmi.radar_confirm, + ATH10K_WMI_DFS_CONF_TIMEOUT_HZ); + if (time_left) { + /* DFS Confirmation status event received and + * necessary action completed. + */ + goto wait_complete; + } else { + /* DFS Confirmation event not received from FW.Considering this + * as real radar. + */ + ath10k_dbg(ar, ATH10K_DBG_REGULATORY, + "dfs confirmation not received from fw, considering as radar\n"); + goto radar_detected; + } + +radar_detected: + ath10k_radar_detected(ar); + + /* Reset state to allow sending confirmation on consecutive radar + * detections, unless radar confirmation is disabled/stopped. + */ +wait_complete: + spin_lock_bh(&ar->data_lock); + if (ar->radar_conf_state != ATH10K_RADAR_CONFIRMATION_STOPPED) + ar->radar_conf_state = ATH10K_RADAR_CONFIRMATION_IDLE; + spin_unlock_bh(&ar->data_lock); +} + static void ath10k_dfs_radar_report(struct ath10k *ar, struct wmi_phyerr_ev_arg *phyerr, const struct phyerr_radar_report *rr, @@ -3691,8 +3759,10 @@ static void ath10k_dfs_radar_report(struct ath10k *ar, u32 reg0, reg1, tsf32l; struct ieee80211_channel *ch; struct pulse_event pe; + struct radar_detector_specs rs; u64 tsf64; u8 rssi, width; + struct ath10k_radar_found_info *radar_info; reg0 = __le32_to_cpu(rr->reg0); reg1 = __le32_to_cpu(rr->reg1); @@ -3757,25 +3827,46 @@ static void ath10k_dfs_radar_report(struct ath10k *ar, ATH10K_DFS_STAT_INC(ar, pulses_detected); - if (!ar->dfs_detector->add_pulse(ar->dfs_detector, &pe, NULL)) { + if (!ar->dfs_detector->add_pulse(ar->dfs_detector, &pe, &rs)) { ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs no pulse pattern detected, yet\n"); return; } -radar_detected: - ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs radar detected\n"); - ATH10K_DFS_STAT_INC(ar, radar_detected); + if ((test_bit(WMI_SERVICE_HOST_DFS_CHECK_SUPPORT, ar->wmi.svc_map)) && + ar->dfs_detector->region == NL80211_DFS_FCC) { + /* Consecutive radar indications need not be + * sent to the firmware until we get confirmation + * for the previous detected radar. + */ + spin_lock_bh(&ar->data_lock); + if (ar->radar_conf_state != ATH10K_RADAR_CONFIRMATION_IDLE) { + spin_unlock_bh(&ar->data_lock); + return; + } + ar->radar_conf_state = ATH10K_RADAR_CONFIRMATION_INPROGRESS; + radar_info = &ar->last_radar_info; - /* Control radar events reporting in debugfs file - * dfs_block_radar_events - */ - if (ar->dfs_block_radar_events) { - ath10k_info(ar, "DFS Radar detected, but ignored as requested\n"); + radar_info->pri_min = rs.pri_min; + radar_info->pri_max = rs.pri_max; + radar_info->width_min = rs.width_min; + radar_info->width_max = rs.width_max; + /*TODO Find sidx_min and sidx_max */ + radar_info->sidx_min = MS(reg0, RADAR_REPORT_REG0_PULSE_SIDX); + radar_info->sidx_max = MS(reg0, RADAR_REPORT_REG0_PULSE_SIDX); + + ath10k_dbg(ar, ATH10K_DBG_REGULATORY, + "sending wmi radar found cmd pri_min %d pri_max %d width_min %d width_max %d sidx_min %d sidx_max %d\n", + radar_info->pri_min, radar_info->pri_max, + radar_info->width_min, radar_info->width_max, + radar_info->sidx_min, radar_info->sidx_max); + ieee80211_queue_work(ar->hw, &ar->radar_confirmation_work); + spin_unlock_bh(&ar->data_lock); return; } - ieee80211_radar_detected(ar->hw); +radar_detected: + ath10k_radar_detected(ar); } static int ath10k_dfs_fft_report(struct ath10k *ar, @@ -4125,6 +4216,47 @@ void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) } } +static int +ath10k_wmi_10_4_op_pull_dfs_status_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_dfs_status_ev_arg *arg) +{ + struct wmi_dfs_status_ev_arg *ev = (void *)skb->data; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + arg->status = ev->status; + + return 0; +} + +static void +ath10k_wmi_event_dfs_status_check(struct ath10k *ar, struct sk_buff *skb) +{ + struct wmi_dfs_status_ev_arg status_arg = {}; + int ret; + + ret = ath10k_wmi_pull_dfs_status(ar, skb, &status_arg); + + if (ret) { + ath10k_warn(ar, "failed to parse dfs status event: %d\n", ret); + return; + } + + ath10k_dbg(ar, ATH10K_DBG_REGULATORY, + "dfs status event received from fw: %d\n", + status_arg.status); + + /* Even in case of radar detection failure we follow the same + * behaviour as if radar is detected i.e to switch to a different + * channel. + */ + if (status_arg.status == WMI_HW_RADAR_DETECTED || + status_arg.status == WMI_RADAR_DETECTION_FAIL) + ath10k_radar_detected(ar); + complete(&ar->wmi.radar_confirm); +} + void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb) { struct wmi_roam_ev_arg arg = {}; @@ -5876,6 +6008,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_10_4_PDEV_TPC_TABLE_EVENTID: ath10k_wmi_event_tpc_final_table(ar, skb); break; + case WMI_10_4_DFS_STATUS_CHECK_EVENTID: + ath10k_wmi_event_dfs_status_check(ar, skb); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; @@ -8461,6 +8596,32 @@ ath10k_wmi_10_4_gen_tdls_peer_update(struct ath10k *ar, return skb; } +static struct sk_buff * +ath10k_wmi_10_4_gen_radar_found(struct ath10k *ar, + const struct ath10k_radar_found_info *arg) +{ + struct wmi_radar_found_info *cmd; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_radar_found_info *)skb->data; + cmd->pri_min = __cpu_to_le32(arg->pri_min); + cmd->pri_max = __cpu_to_le32(arg->pri_max); + cmd->width_min = __cpu_to_le32(arg->width_min); + cmd->width_max = __cpu_to_le32(arg->width_max); + cmd->sidx_min = __cpu_to_le32(arg->sidx_min); + cmd->sidx_max = __cpu_to_le32(arg->sidx_max); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi radar found pri_min %d pri_max %d width_min %d width_max %d sidx_min %d sidx_max %d\n", + arg->pri_min, arg->pri_max, arg->width_min, + arg->width_max, arg->sidx_min, arg->sidx_max); + return skb; +} + static struct sk_buff * ath10k_wmi_op_gen_echo(struct ath10k *ar, u32 value) { @@ -8798,6 +8959,7 @@ static const struct wmi_ops wmi_10_4_ops = { .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, .pull_rdy = ath10k_wmi_op_pull_rdy_ev, .pull_roam_ev = ath10k_wmi_op_pull_roam_ev, + .pull_dfs_status_ev = ath10k_wmi_10_4_op_pull_dfs_status_ev, .get_txbf_conf_scheme = ath10k_wmi_10_4_txbf_conf_scheme, .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, @@ -8844,6 +9006,7 @@ static const struct wmi_ops wmi_10_4_ops = { .gen_tdls_peer_update = ath10k_wmi_10_4_gen_tdls_peer_update, .gen_pdev_get_tpc_table_cmdid = ath10k_wmi_10_4_op_gen_pdev_get_tpc_table_cmdid, + .gen_radar_found = ath10k_wmi_10_4_gen_radar_found, /* shared with 10.2 */ .pull_echo_ev = ath10k_wmi_op_pull_echo_ev, @@ -8906,8 +9069,11 @@ int ath10k_wmi_attach(struct ath10k *ar) init_completion(&ar->wmi.service_ready); init_completion(&ar->wmi.unified_ready); init_completion(&ar->wmi.barrier); + init_completion(&ar->wmi.radar_confirm); INIT_WORK(&ar->svc_rdy_work, ath10k_wmi_event_service_ready_work); + INIT_WORK(&ar->radar_confirmation_work, + ath10k_radar_confirmation_work); return 0; } diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 700b12f46baf..b48db54e9865 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -969,6 +969,7 @@ struct wmi_cmd_map { u32 vdev_sifs_trigger_time_cmdid; u32 pdev_wds_entry_list_cmdid; u32 tdls_set_offchan_mode_cmdid; + u32 radar_found_cmdid; }; /* @@ -1803,6 +1804,11 @@ enum wmi_10_4_cmd_id { WMI_10_4_TDLS_SET_STATE_CMDID, WMI_10_4_TDLS_PEER_UPDATE_CMDID, WMI_10_4_TDLS_SET_OFFCHAN_MODE_CMDID, + WMI_10_4_PDEV_SEND_FD_CMDID, + WMI_10_4_ENABLE_FILS_CMDID, + WMI_10_4_PDEV_SET_BRIDGE_MACADDR_CMDID, + WMI_10_4_ATF_GROUP_WMM_AC_CONFIG_REQUEST_CMDID, + WMI_10_4_RADAR_FOUND_CMDID, WMI_10_4_PDEV_UTF_CMDID = WMI_10_4_END_CMDID - 1, }; @@ -1878,6 +1884,9 @@ enum wmi_10_4_event_id { WMI_10_4_PDEV_TPC_TABLE_EVENTID, WMI_10_4_PDEV_WDS_ENTRY_LIST_EVENTID, WMI_10_4_TDLS_PEER_EVENTID, + WMI_10_4_HOST_SWFDA_EVENTID, + WMI_10_4_ESP_ESTIMATE_EVENTID, + WMI_10_4_DFS_STATUS_CHECK_EVENTID, WMI_10_4_PDEV_UTF_EVENTID = WMI_10_4_END_EVENTID - 1, }; @@ -3398,6 +3407,25 @@ struct wmi_10_4_phyerr_event { u8 buf[0]; } __packed; +struct wmi_radar_found_info { + __le32 pri_min; + __le32 pri_max; + __le32 width_min; + __le32 width_max; + __le32 sidx_min; + __le32 sidx_max; +} __packed; + +enum wmi_radar_confirmation_status { + /* Detected radar was due to SW pulses */ + WMI_SW_RADAR_DETECTED = 0, + + WMI_RADAR_DETECTION_FAIL = 1, + + /* Real radar detected */ + WMI_HW_RADAR_DETECTED = 2, +}; + #define PHYERR_TLV_SIG 0xBB #define PHYERR_TLV_TAG_SEARCH_FFT_REPORT 0xFB #define PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY 0xF8 @@ -6631,6 +6659,10 @@ struct wmi_phyerr_hdr_arg { const void *phyerrs; }; +struct wmi_dfs_status_ev_arg { + u32 status; +}; + struct wmi_svc_rdy_ev_arg { __le32 min_tx_power; __le32 max_tx_power; -- cgit v1.2.3 From 87f825e6e246cee0cdeaafd5bba4ef8c6df2748d Mon Sep 17 00:00:00 2001 From: Eyal Ilsar Date: Tue, 22 May 2018 22:02:56 +0300 Subject: wcn36xx: Add support for Factory Test Mode (FTM) Introduce infrastructure for supporting Factory Test Mode (FTM) of the wireless LAN subsystem. In order for the user space to access the firmware in test mode the relevant netlink channel needs to be exposed from the kernel driver. The above is achieved as follows: 1) Register wcn36xx driver to testmode callback from netlink 2) Add testmode callback implementation to handle incoming FTM commands 3) Add FTM command packet structure 4) Add handling for GET_BUILD_RELEASE_NUMBER (msgid=0x32A2) 5) Add generic handling for all PTT_MSG packets Signed-off-by: Eyal Ilsar Signed-off-by: Ramon Fried Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/Makefile | 2 + drivers/net/wireless/ath/wcn36xx/hal.h | 16 +++ drivers/net/wireless/ath/wcn36xx/main.c | 3 + drivers/net/wireless/ath/wcn36xx/smd.c | 81 ++++++++++++++ drivers/net/wireless/ath/wcn36xx/smd.h | 4 + drivers/net/wireless/ath/wcn36xx/testmode.c | 149 ++++++++++++++++++++++++++ drivers/net/wireless/ath/wcn36xx/testmode.h | 46 ++++++++ drivers/net/wireless/ath/wcn36xx/testmode_i.h | 29 +++++ drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 2 + 9 files changed, 332 insertions(+) create mode 100644 drivers/net/wireless/ath/wcn36xx/testmode.c create mode 100644 drivers/net/wireless/ath/wcn36xx/testmode.h create mode 100644 drivers/net/wireless/ath/wcn36xx/testmode_i.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/wcn36xx/Makefile b/drivers/net/wireless/ath/wcn36xx/Makefile index 3b09435104eb..582049f65735 100644 --- a/drivers/net/wireless/ath/wcn36xx/Makefile +++ b/drivers/net/wireless/ath/wcn36xx/Makefile @@ -6,3 +6,5 @@ wcn36xx-y += main.o \ smd.o \ pmc.o \ debug.o + +wcn36xx-$(CONFIG_NL80211_TESTMODE) += testmode.o diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h index 2aed6c233508..8abda2760e04 100644 --- a/drivers/net/wireless/ath/wcn36xx/hal.h +++ b/drivers/net/wireless/ath/wcn36xx/hal.h @@ -2236,6 +2236,22 @@ struct wcn36xx_hal_switch_channel_rsp_msg { } __packed; +struct wcn36xx_hal_process_ptt_msg_req_msg { + struct wcn36xx_hal_msg_header header; + + /* Actual FTM Command body */ + u8 ptt_msg[0]; +} __packed; + +struct wcn36xx_hal_process_ptt_msg_rsp_msg { + struct wcn36xx_hal_msg_header header; + + /* FTM Command response status */ + u32 ptt_msg_resp_status; + /* Actual FTM Command body */ + u8 ptt_msg[0]; +} __packed; + struct update_edca_params_req_msg { struct wcn36xx_hal_msg_header header; diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 662e50540b07..aeb5e6e806be 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -26,6 +26,7 @@ #include #include #include "wcn36xx.h" +#include "testmode.h" unsigned int wcn36xx_dbg_mask; module_param_named(debug_mask, wcn36xx_dbg_mask, uint, 0644); @@ -1146,6 +1147,8 @@ static const struct ieee80211_ops wcn36xx_ops = { .sta_add = wcn36xx_sta_add, .sta_remove = wcn36xx_sta_remove, .ampdu_action = wcn36xx_ampdu_action, + + CFG80211_TESTMODE_CMD(wcn36xx_tm_cmd) }; static int wcn36xx_init_ieee80211(struct wcn36xx *wcn) diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index b855a58d5aac..b4dadf75d565 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -298,12 +298,26 @@ static void init_hal_msg(struct wcn36xx_hal_msg_header *hdr, msg_body.header.len = sizeof(msg_body); \ } while (0) \ +#define INIT_HAL_PTT_MSG(p_msg_body, ppt_msg_len) \ + do { \ + memset(p_msg_body, 0, sizeof(*p_msg_body) + ppt_msg_len); \ + p_msg_body->header.msg_type = WCN36XX_HAL_PROCESS_PTT_REQ; \ + p_msg_body->header.msg_version = WCN36XX_HAL_MSG_VERSION0; \ + p_msg_body->header.len = sizeof(*p_msg_body) + ppt_msg_len; \ + } while (0) + #define PREPARE_HAL_BUF(send_buf, msg_body) \ do { \ memset(send_buf, 0, msg_body.header.len); \ memcpy(send_buf, &msg_body, sizeof(msg_body)); \ } while (0) \ +#define PREPARE_HAL_PTT_MSG_BUF(send_buf, p_msg_body) \ + do { \ + memset(send_buf, 0, p_msg_body->header.len); \ + memcpy(send_buf, p_msg_body, p_msg_body->header.len); \ + } while (0) + static int wcn36xx_smd_rsp_status_check(void *buf, size_t len) { struct wcn36xx_fw_msg_status_rsp *rsp; @@ -760,6 +774,71 @@ out: return ret; } +static int wcn36xx_smd_process_ptt_msg_rsp(void *buf, size_t len, + void **p_ptt_rsp_msg) +{ + struct wcn36xx_hal_process_ptt_msg_rsp_msg *rsp; + int ret; + + ret = wcn36xx_smd_rsp_status_check(buf, len); + if (ret) + return ret; + + rsp = (struct wcn36xx_hal_process_ptt_msg_rsp_msg *)buf; + + wcn36xx_dbg(WCN36XX_DBG_HAL, "process ptt msg responded with length %d\n", + rsp->header.len); + wcn36xx_dbg_dump(WCN36XX_DBG_HAL_DUMP, "HAL_PTT_MSG_RSP:", rsp->ptt_msg, + rsp->header.len - sizeof(rsp->ptt_msg_resp_status)); + + if (rsp->header.len > 0) { + *p_ptt_rsp_msg = kmalloc(rsp->header.len, GFP_ATOMIC); + if (!*p_ptt_rsp_msg) + return -ENOMEM; + memcpy(*p_ptt_rsp_msg, rsp->ptt_msg, rsp->header.len); + } + return ret; +} + +int wcn36xx_smd_process_ptt_msg(struct wcn36xx *wcn, + struct ieee80211_vif *vif, void *ptt_msg, size_t len, + void **ptt_rsp_msg) +{ + struct wcn36xx_hal_process_ptt_msg_req_msg *p_msg_body; + int ret; + + mutex_lock(&wcn->hal_mutex); + p_msg_body = kmalloc( + sizeof(struct wcn36xx_hal_process_ptt_msg_req_msg) + len, + GFP_ATOMIC); + if (!p_msg_body) { + ret = -ENOMEM; + goto out_nomem; + } + INIT_HAL_PTT_MSG(p_msg_body, len); + + memcpy(&p_msg_body->ptt_msg, ptt_msg, len); + + PREPARE_HAL_PTT_MSG_BUF(wcn->hal_buf, p_msg_body); + + ret = wcn36xx_smd_send_and_wait(wcn, p_msg_body->header.len); + if (ret) { + wcn36xx_err("Sending hal_process_ptt_msg failed\n"); + goto out; + } + ret = wcn36xx_smd_process_ptt_msg_rsp(wcn->hal_buf, wcn->hal_rsp_len, + ptt_rsp_msg); + if (ret) { + wcn36xx_err("process_ptt_msg response failed err=%d\n", ret); + goto out; + } +out: + kfree(p_msg_body); +out_nomem: + mutex_unlock(&wcn->hal_mutex); + return ret; +} + static int wcn36xx_smd_update_scan_params_rsp(void *buf, size_t len) { struct wcn36xx_hal_update_scan_params_resp *rsp; @@ -2396,6 +2475,7 @@ int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev, case WCN36XX_HAL_JOIN_RSP: case WCN36XX_HAL_UPDATE_SCAN_PARAM_RSP: case WCN36XX_HAL_CH_SWITCH_RSP: + case WCN36XX_HAL_PROCESS_PTT_RSP: case WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_RSP: case WCN36XX_HAL_8023_MULTICAST_LIST_RSP: case WCN36XX_HAL_START_SCAN_OFFLOAD_RSP: @@ -2436,6 +2516,7 @@ int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev, return 0; } + static void wcn36xx_ind_smd_work(struct work_struct *work) { struct wcn36xx *wcn = diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h index 61bb8d43138c..ff15df8ab56f 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.h +++ b/drivers/net/wireless/ath/wcn36xx/smd.h @@ -86,6 +86,10 @@ int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif, u16 p2p_off); int wcn36xx_smd_switch_channel(struct wcn36xx *wcn, struct ieee80211_vif *vif, int ch); +int wcn36xx_smd_process_ptt_msg(struct wcn36xx *wcn, + struct ieee80211_vif *vif, + void *ptt_msg, size_t len, + void **ptt_rsp_msg); int wcn36xx_smd_update_proberesp_tmpl(struct wcn36xx *wcn, struct ieee80211_vif *vif, struct sk_buff *skb); diff --git a/drivers/net/wireless/ath/wcn36xx/testmode.c b/drivers/net/wireless/ath/wcn36xx/testmode.c new file mode 100644 index 000000000000..1279064a3b71 --- /dev/null +++ b/drivers/net/wireless/ath/wcn36xx/testmode.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include "wcn36xx.h" + +#include "testmode.h" +#include "testmode_i.h" +#include "hal.h" +#include "smd.h" + +static const struct nla_policy wcn36xx_tm_policy[WCN36XX_TM_ATTR_MAX + 1] = { + [WCN36XX_TM_ATTR_CMD] = { .type = NLA_U16 }, + [WCN36XX_TM_ATTR_DATA] = { .type = NLA_BINARY, + .len = WCN36XX_TM_DATA_MAX_LEN }, +}; + +struct build_release_number { + u16 drv_major; + u16 drv_minor; + u16 drv_patch; + u16 drv_build; + u16 ptt_max; + u16 ptt_min; + u16 fw_ver; +} __packed; + +static int wcn36xx_tm_cmd_ptt(struct wcn36xx *wcn, struct ieee80211_vif *vif, + struct nlattr *tb[]) +{ + int ret = 0, buf_len; + void *buf; + struct ftm_rsp_msg *msg, *rsp = NULL; + struct sk_buff *skb; + + if (!tb[WCN36XX_TM_ATTR_DATA]) + return -EINVAL; + + buf = nla_data(tb[WCN36XX_TM_ATTR_DATA]); + buf_len = nla_len(tb[WCN36XX_TM_ATTR_DATA]); + msg = (struct ftm_rsp_msg *)buf; + + wcn36xx_dbg(WCN36XX_DBG_TESTMODE, + "testmode cmd wmi msg_id 0x%04X msg_len %d buf %pK buf_len %d\n", + msg->msg_id, msg->msg_body_length, + buf, buf_len); + + wcn36xx_dbg_dump(WCN36XX_DBG_TESTMODE_DUMP, "REQ ", buf, buf_len); + + if (msg->msg_id == MSG_GET_BUILD_RELEASE_NUMBER) { + struct build_release_number *body = + (struct build_release_number *) + msg->msg_response; + + body->drv_major = wcn->fw_major; + body->drv_minor = wcn->fw_minor; + body->drv_patch = wcn->fw_version; + body->drv_build = wcn->fw_revision; + body->ptt_max = 10; + body->ptt_min = 0; + + rsp = msg; + rsp->resp_status = 0; + } else { + wcn36xx_dbg(WCN36XX_DBG_TESTMODE, + "PPT Request >> HAL size %d\n", + msg->msg_body_length); + + msg->resp_status = wcn36xx_smd_process_ptt_msg(wcn, vif, msg, + msg->msg_body_length, (void *)(&rsp)); + + wcn36xx_dbg(WCN36XX_DBG_TESTMODE, + "Response status = %d\n", + msg->resp_status); + if (rsp) + wcn36xx_dbg(WCN36XX_DBG_TESTMODE, + "PPT Response << HAL size %d\n", + rsp->msg_body_length); + } + + if (!rsp) { + rsp = msg; + wcn36xx_warn("No response! Echoing request with response status %d\n", + rsp->resp_status); + } + wcn36xx_dbg_dump(WCN36XX_DBG_TESTMODE_DUMP, "RSP ", + rsp, rsp->msg_body_length); + + skb = cfg80211_testmode_alloc_reply_skb(wcn->hw->wiphy, + nla_total_size(msg->msg_body_length)); + if (!skb) { + ret = -ENOMEM; + goto out; + } + + ret = nla_put(skb, WCN36XX_TM_ATTR_DATA, rsp->msg_body_length, rsp); + if (ret) { + kfree_skb(skb); + goto out; + } + + ret = cfg80211_testmode_reply(skb); + +out: + if (rsp != msg) + kfree(rsp); + + return ret; +} + +int wcn36xx_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + void *data, int len) +{ + struct wcn36xx *wcn = hw->priv; + struct nlattr *tb[WCN36XX_TM_ATTR_MAX + 1]; + int ret = 0; + unsigned short attr; + + wcn36xx_dbg_dump(WCN36XX_DBG_TESTMODE_DUMP, "Data:", data, len); + ret = nla_parse(tb, WCN36XX_TM_ATTR_MAX, data, len, + wcn36xx_tm_policy, NULL); + if (ret) + return ret; + + if (!tb[WCN36XX_TM_ATTR_CMD]) + return -EINVAL; + + attr = nla_get_u16(tb[WCN36XX_TM_ATTR_CMD]); + + if (attr != WCN36XX_TM_CMD_PTT) + return -EOPNOTSUPP; + + return wcn36xx_tm_cmd_ptt(wcn, vif, tb); +} diff --git a/drivers/net/wireless/ath/wcn36xx/testmode.h b/drivers/net/wireless/ath/wcn36xx/testmode.h new file mode 100644 index 000000000000..4c6cfdb46580 --- /dev/null +++ b/drivers/net/wireless/ath/wcn36xx/testmode.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "wcn36xx.h" + +struct ftm_rsp_msg { + u16 msg_id; + u16 msg_body_length; + u32 resp_status; + u8 msg_response[0]; +} __packed; + +/* The request buffer of FTM which contains a byte of command and the request */ +struct ftm_payload { + u16 ftm_cmd_type; + struct ftm_rsp_msg ftm_cmd_msg; +} __packed; + +#define MSG_GET_BUILD_RELEASE_NUMBER 0x32A2 + +#ifdef CONFIG_NL80211_TESTMODE +int wcn36xx_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + void *data, int len); + +#else +static inline int wcn36xx_tm_cmd(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + void *data, int len) +{ + return 0; +} + +#endif diff --git a/drivers/net/wireless/ath/wcn36xx/testmode_i.h b/drivers/net/wireless/ath/wcn36xx/testmode_i.h new file mode 100644 index 000000000000..8a1477ffd5a0 --- /dev/null +++ b/drivers/net/wireless/ath/wcn36xx/testmode_i.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define WCN36XX_TM_DATA_MAX_LEN 5000 + +enum wcn36xx_tm_attr { + __WCN36XX_TM_ATTR_INVALID = 0, + WCN36XX_TM_ATTR_CMD = 1, + WCN36XX_TM_ATTR_DATA = 2, + + /* keep last */ + __WCN36XX_TM_ATTR_AFTER_LAST, + WCN36XX_TM_ATTR_MAX = __WCN36XX_TM_ATTR_AFTER_LAST - 1, +}; + +#define WCN36XX_TM_CMD_PTT 3 diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index 9343989d1169..11e74015c79a 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -50,6 +50,8 @@ enum wcn36xx_debug_mask { WCN36XX_DBG_BEACON_DUMP = 0x00001000, WCN36XX_DBG_PMC = 0x00002000, WCN36XX_DBG_PMC_DUMP = 0x00004000, + WCN36XX_DBG_TESTMODE = 0x00008000, + WCN36XX_DBG_TESTMODE_DUMP = 0x00010000, WCN36XX_DBG_ANY = 0xffffffff, }; -- cgit v1.2.3 From 728a9dc61f132eb567f58c234e11ef80a3519cc0 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 17 May 2018 11:29:50 -0700 Subject: wlcore: sdio: Fix flakey SDIO runtime PM handling We can have pm_runtime_get_sync() return 1, and we can have pm_runtime_put_sync() return -EBUSY. See rpm_suspend() and rpm_resume() for more information. Fix the issue by returning 0 from wl12xx_sdio_power_on() on success. And use pm_runtime_put() instead of pm_runtime_put_sync() for wl12xx_sdio_power_off(), then the MMC subsystem will idle the bus when suitable. Otherwise wlcore can sometimes get confused and may report bogus errors and WLAN connection can fail. Note that while wlcore checks the return value for wl1271_power_on(), the return value is ignored for wl1271_power_off(). Let's fix them both though to avoid further confusion in the future. Fixes: 60f36637bbbd ("wlcore: sdio: allow pm to handle sdio power") Signed-off-by: Tony Lindgren Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/sdio.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 6dbe61d47dc3..15d5ac126061 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -159,28 +159,36 @@ static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue) pm_runtime_put_noidle(&card->dev); dev_err(glue->dev, "%s: failed to get_sync(%d)\n", __func__, ret); - goto out; + + return ret; } sdio_claim_host(func); sdio_enable_func(func); sdio_release_host(func); -out: - return ret; + return 0; } static int wl12xx_sdio_power_off(struct wl12xx_sdio_glue *glue) { struct sdio_func *func = dev_to_sdio_func(glue->dev); struct mmc_card *card = func->card; + int error; sdio_claim_host(func); sdio_disable_func(func); sdio_release_host(func); /* Let runtime PM know the card is powered off */ - return pm_runtime_put_sync(&card->dev); + error = pm_runtime_put(&card->dev); + if (error < 0 && error != -EBUSY) { + dev_err(&card->dev, "%s failed: %i\n", __func__, error); + + return error; + } + + return 0; } static int wl12xx_sdio_set_power(struct device *child, bool enable) -- cgit v1.2.3 From 6acfbb81ab0a800fd0ce0795103852255d671635 Mon Sep 17 00:00:00 2001 From: Tzu-En Huang Date: Fri, 18 May 2018 17:29:54 +0800 Subject: rtlwifi: support accurate nullfunc frame tx ack report In order to realize the keep-alive mechanism in mac80211 stack, reporting accurate tx ack status for nullfunc frame is added in this commit. If current frame is nullfunc frame, we ask firmware to report by filling TX report bit in TX descriptor. After this frame DMA done, TX interrupt is triggered but TX status is unknown at this moment, so enqueue this skb into tx_report->queue. Finally, C2H report will be received if the frame is transmitted successfully or retried over, and then we report to mac80211 with IEEE80211_TX_STAT_ACK flag only if it's successful. Otherwise, if failure or timeout (one second), we report to mac80211 without this flag. Signed-off-by: Tzu-En Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/base.c | 84 +++++++++++++++++++--- drivers/net/wireless/realtek/rtlwifi/base.h | 5 +- drivers/net/wireless/realtek/rtlwifi/pci.c | 13 ++-- .../net/wireless/realtek/rtlwifi/rtl8192ee/trx.c | 5 +- .../net/wireless/realtek/rtlwifi/rtl8723be/trx.c | 5 +- .../net/wireless/realtek/rtlwifi/rtl8821ae/trx.c | 5 +- drivers/net/wireless/realtek/rtlwifi/wifi.h | 16 +++++ 7 files changed, 112 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index 762a29cdf7ad..6620c6842b91 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -574,6 +574,7 @@ int rtl_init_core(struct ieee80211_hw *hw) INIT_LIST_HEAD(&rtlpriv->entry_list); INIT_LIST_HEAD(&rtlpriv->c2hcmd_list); INIT_LIST_HEAD(&rtlpriv->scan_list.list); + skb_queue_head_init(&rtlpriv->tx_report.queue); rtlmac->link_state = MAC80211_NOLINK; @@ -585,11 +586,14 @@ int rtl_init_core(struct ieee80211_hw *hw) EXPORT_SYMBOL_GPL(rtl_init_core); static void rtl_free_entries_from_scan_list(struct ieee80211_hw *hw); +static void rtl_free_entries_from_ack_queue(struct ieee80211_hw *hw, + bool timeout); void rtl_deinit_core(struct ieee80211_hw *hw) { rtl_c2hcmd_launcher(hw, 0); rtl_free_entries_from_scan_list(hw); + rtl_free_entries_from_ack_queue(hw, false); } EXPORT_SYMBOL_GPL(rtl_deinit_core); @@ -1575,22 +1579,52 @@ end: } EXPORT_SYMBOL_GPL(rtl_is_special_data); +void rtl_tx_ackqueue(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tx_report *tx_report = &rtlpriv->tx_report; + + __skb_queue_tail(&tx_report->queue, skb); +} +EXPORT_SYMBOL_GPL(rtl_tx_ackqueue); + +static void rtl_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, + bool ack) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_tx_info *info; + + info = IEEE80211_SKB_CB(skb); + ieee80211_tx_info_clear_status(info); + if (ack) { + RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_LOUD, + "tx report: ack\n"); + info->flags |= IEEE80211_TX_STAT_ACK; + } else { + RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_LOUD, + "tx report: not ack\n"); + info->flags &= ~IEEE80211_TX_STAT_ACK; + } + ieee80211_tx_status_irqsafe(hw, skb); +} + bool rtl_is_tx_report_skb(struct ieee80211_hw *hw, struct sk_buff *skb) { u16 ether_type; const u8 *ether_type_ptr; + __le16 fc = rtl_get_fc(skb); ether_type_ptr = rtl_skb_ether_type_ptr(hw, skb, true); ether_type = be16_to_cpup((__be16 *)ether_type_ptr); - /* EAPOL */ - if (ether_type == ETH_P_PAE) + if (ether_type == ETH_P_PAE || ieee80211_is_nullfunc(fc)) return true; return false; } -static u16 rtl_get_tx_report_sn(struct ieee80211_hw *hw) +static u16 rtl_get_tx_report_sn(struct ieee80211_hw *hw, + struct rtlwifi_tx_info *tx_info) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_tx_report *tx_report = &rtlpriv->tx_report; @@ -1604,29 +1638,33 @@ static u16 rtl_get_tx_report_sn(struct ieee80211_hw *hw) tx_report->last_sent_sn = sn; tx_report->last_sent_time = jiffies; - + tx_info->sn = sn; + tx_info->send_time = tx_report->last_sent_time; RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_DMESG, "Send TX-Report sn=0x%X\n", sn); return sn; } -void rtl_get_tx_report(struct rtl_tcb_desc *ptcb_desc, u8 *pdesc, - struct ieee80211_hw *hw) +void rtl_set_tx_report(struct rtl_tcb_desc *ptcb_desc, u8 *pdesc, + struct ieee80211_hw *hw, struct rtlwifi_tx_info *tx_info) { if (ptcb_desc->use_spe_rpt) { - u16 sn = rtl_get_tx_report_sn(hw); + u16 sn = rtl_get_tx_report_sn(hw, tx_info); SET_TX_DESC_SPE_RPT(pdesc, 1); SET_TX_DESC_SW_DEFINE(pdesc, sn); } } -EXPORT_SYMBOL_GPL(rtl_get_tx_report); +EXPORT_SYMBOL_GPL(rtl_set_tx_report); void rtl_tx_report_handler(struct ieee80211_hw *hw, u8 *tmp_buf, u8 c2h_cmd_len) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_tx_report *tx_report = &rtlpriv->tx_report; + struct rtlwifi_tx_info *tx_info; + struct sk_buff_head *queue = &tx_report->queue; + struct sk_buff *skb; u16 sn; u8 st, retry; @@ -1642,6 +1680,14 @@ void rtl_tx_report_handler(struct ieee80211_hw *hw, u8 *tmp_buf, u8 c2h_cmd_len) tx_report->last_recv_sn = sn; + skb_queue_walk(queue, skb) { + tx_info = rtl_tx_skb_cb_info(skb); + if (tx_info->sn == sn) { + skb_unlink(skb, queue); + rtl_tx_status(hw, skb, st == 0); + break; + } + } RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_DMESG, "Recv TX-Report st=0x%02X sn=0x%X retry=0x%X\n", st, sn, retry); @@ -1909,6 +1955,25 @@ static void rtl_free_entries_from_scan_list(struct ieee80211_hw *hw) } } +static void rtl_free_entries_from_ack_queue(struct ieee80211_hw *hw, + bool chk_timeout) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tx_report *tx_report = &rtlpriv->tx_report; + struct sk_buff_head *queue = &tx_report->queue; + struct sk_buff *skb, *tmp; + struct rtlwifi_tx_info *tx_info; + + skb_queue_walk_safe(queue, skb, tmp) { + tx_info = rtl_tx_skb_cb_info(skb); + if (chk_timeout && + time_after(tx_info->send_time + HZ, jiffies)) + continue; + skb_unlink(skb, queue); + rtl_tx_status(hw, skb, false); + } +} + void rtl_scan_list_expire(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -2173,6 +2238,9 @@ label_lps_done: /* <6> scan list */ rtl_scan_list_expire(hw); + + /* <7> check ack queue */ + rtl_free_entries_from_ack_queue(hw, true); } void rtl_watch_dog_timer_callback(struct timer_list *t) diff --git a/drivers/net/wireless/realtek/rtlwifi/base.h b/drivers/net/wireless/realtek/rtlwifi/base.h index acc924635818..19e7477839e4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.h +++ b/drivers/net/wireless/realtek/rtlwifi/base.h @@ -130,9 +130,10 @@ bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb); u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, bool is_enc); +void rtl_tx_ackqueue(struct ieee80211_hw *hw, struct sk_buff *skb); bool rtl_is_tx_report_skb(struct ieee80211_hw *hw, struct sk_buff *skb); -void rtl_get_tx_report(struct rtl_tcb_desc *ptcb_desc, u8 *pdesc, - struct ieee80211_hw *hw); +void rtl_set_tx_report(struct rtl_tcb_desc *ptcb_desc, u8 *pdesc, + struct ieee80211_hw *hw, struct rtlwifi_tx_info *info); void rtl_tx_report_handler(struct ieee80211_hw *hw, u8 *tmp_buf, u8 c2h_cmd_len); bool rtl_check_tx_report_acked(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 57bb8f049e59..d0c509ef790e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -619,12 +619,15 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) rtlpriv->link_info.tidtx_inperiod[tid]++; info = IEEE80211_SKB_CB(skb); - ieee80211_tx_info_clear_status(info); - info->flags |= IEEE80211_TX_STAT_ACK; - /*info->status.rates[0].count = 1; */ - - ieee80211_tx_status_irqsafe(hw, skb); + if (likely(!ieee80211_is_nullfunc(fc))) { + ieee80211_tx_info_clear_status(info); + info->flags |= IEEE80211_TX_STAT_ACK; + /*info->status.rates[0].count = 1; */ + ieee80211_tx_status_irqsafe(hw, skb); + } else { + rtl_tx_ackqueue(hw, skb); + } if ((ring->entries - skb_queue_len(&ring->queue)) <= 4) { RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c index 4f7444331b07..852a2701ef55 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c @@ -662,6 +662,7 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtlwifi_tx_info *tx_info = rtl_tx_skb_cb_info(skb); u8 *pdesc = (u8 *)pdesc_tx; u16 seq_number; __le16 fc = hdr->frame_control; @@ -723,8 +724,6 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); } - /* tx report */ - rtl_get_tx_report(ptcb_desc, pdesc, hw); SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); @@ -827,6 +826,8 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_HTC(pdesc, 1); } } + /* tx report */ + rtl_set_tx_report(ptcb_desc, pdesc, hw, tx_info); } SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0)); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c index fd9b38aa08a1..deb8f9501b51 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c @@ -431,6 +431,7 @@ void rtl8723be_tx_fill_desc(struct ieee80211_hw *hw, struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtlwifi_tx_info *tx_info = rtl_tx_skb_cb_info(skb); u8 *pdesc = (u8 *)pdesc_tx; u16 seq_number; __le16 fc = hdr->frame_control; @@ -488,8 +489,6 @@ void rtl8723be_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); } - /* tx report */ - rtl_get_tx_report(ptcb_desc, pdesc, hw); /* ptcb_desc->use_driver_rate = true; */ SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); @@ -578,6 +577,8 @@ void rtl8723be_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_HTC(pdesc, 1); } } + /* tx report */ + rtl_set_tx_report(ptcb_desc, pdesc, hw, tx_info); } SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0)); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c index 1e1bacf562f3..63fb80039f82 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c @@ -691,6 +691,7 @@ void rtl8821ae_tx_fill_desc(struct ieee80211_hw *hw, struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtlwifi_tx_info *tx_info = rtl_tx_skb_cb_info(skb); u8 *pdesc = (u8 *)pdesc_tx; u16 seq_number; __le16 fc = hdr->frame_control; @@ -740,8 +741,6 @@ void rtl8821ae_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); } - /* tx report */ - rtl_get_tx_report(ptcb_desc, pdesc, hw); /* ptcb_desc->use_driver_rate = true; */ SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); @@ -818,6 +817,8 @@ void rtl8821ae_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_HTC(pdesc, 1); } } + /* tx report */ + rtl_set_tx_report(ptcb_desc, pdesc, hw, tx_info); } SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0)); diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 208010fcde21..1259d2b66d17 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -1010,6 +1010,21 @@ enum dm_info_query { DM_INFO_SIZE, }; +struct rtlwifi_tx_info { + int sn; + unsigned long send_time; +}; + +static inline struct rtlwifi_tx_info *rtl_tx_skb_cb_info(struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + BUILD_BUG_ON(sizeof(struct rtlwifi_tx_info) > + sizeof(info->status.status_driver_data)); + + return (struct rtlwifi_tx_info *)(info->status.status_driver_data); +} + struct octet_string { u8 *octet; u16 length; @@ -1967,6 +1982,7 @@ struct rtl_tx_report { u16 last_sent_sn; unsigned long last_sent_time; u16 last_recv_sn; + struct sk_buff_head queue; }; struct rtl_ps_ctl { -- cgit v1.2.3 From faa2800653978d67ef6ee2121334d66271ba6789 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 18 May 2018 17:29:55 +0800 Subject: rtlwifi: remove CONNECTION_MONITOR flag To use keep-alive mechanism in mac80211 stack, since driver supports reporting accurate nullfunc frame tx ack now. Signed-off-by: Tzu-En Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/base.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index 6620c6842b91..759a802ccbee 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -396,7 +396,6 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) ieee80211_hw_set(hw, SIGNAL_DBM); ieee80211_hw_set(hw, RX_INCLUDES_FCS); ieee80211_hw_set(hw, AMPDU_AGGREGATION); - ieee80211_hw_set(hw, CONNECTION_MONITOR); ieee80211_hw_set(hw, MFP_CAPABLE); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); -- cgit v1.2.3 From c4528686d0ea222d0b29b4017ae227546bdbb7d7 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 18 May 2018 17:29:56 +0800 Subject: rtlwifi: remove duplicate rx_packet_type definition Move duplicate definitions from def.h of ic folder to wifi.h Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8188ee/def.h | 7 ------- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/def.h | 8 -------- drivers/net/wireless/realtek/rtlwifi/rtl8723be/def.h | 8 -------- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/def.h | 8 -------- drivers/net/wireless/realtek/rtlwifi/wifi.h | 8 ++++++++ 5 files changed, 8 insertions(+), 31 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/def.h b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/def.h index 0532b9852444..32492d64d685 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/def.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/def.h @@ -137,13 +137,6 @@ enum version_8188e { VERSION_UNKNOWN = 0xFF, }; -enum rx_packet_type { - NORMAL_RX, - TX_REPORT1, - TX_REPORT2, - HIS_REPORT, -}; - enum rtl819x_loopback_e { RTL819X_NO_LOOPBACK = 0, RTL819X_MAC_LOOPBACK = 1, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/def.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/def.h index 60f5728b4e2d..9f7e7bb8610b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/def.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/def.h @@ -47,14 +47,6 @@ enum version_8192e { VERSION_UNKNOWN = 0xFF, }; -enum rx_packet_type { - NORMAL_RX, - TX_REPORT1, - TX_REPORT2, - HIS_REPORT, - C2H_PACKET, -}; - enum rtl_desc_qsel { QSLT_BK = 0x2, QSLT_BE = 0x0, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/def.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/def.h index 025ea5c0f3f6..5e5403d69220 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/def.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/def.h @@ -38,14 +38,6 @@ /* Currently only for RTL8723B */ #define EXT_VENDOR_ID (BIT(18) | BIT(19)) -enum rx_packet_type { - NORMAL_RX, - TX_REPORT1, - TX_REPORT2, - HIS_REPORT, - C2H_PACKET, -}; - enum rtl_desc_qsel { QSLT_BK = 0x2, QSLT_BE = 0x0, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/def.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/def.h index dfbdf539de1a..498f716bfc73 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/def.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/def.h @@ -332,14 +332,6 @@ enum rtl_desc_qsel { QSLT_CMD = 0x13, }; -enum rx_packet_type { - NORMAL_RX, - TX_REPORT1, - TX_REPORT2, - HIS_REPORT, - C2H_PACKET, -}; - struct phy_sts_cck_8821ae_t { u8 adc_pwdb_X[4]; u8 sq_rpt; diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 1259d2b66d17..81ac036760fc 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -1010,6 +1010,14 @@ enum dm_info_query { DM_INFO_SIZE, }; +enum rx_packet_type { + NORMAL_RX, + TX_REPORT1, + TX_REPORT2, + HIS_REPORT, + C2H_PACKET, +}; + struct rtlwifi_tx_info { int sn; unsigned long send_time; -- cgit v1.2.3 From 249155973f524a284a86582ff9a915be045ab760 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 18 May 2018 17:29:57 +0800 Subject: rtlwifi: rename register-based C2H command IDs to V0 Current chips use packet-based C2H commands whose IDs differ from old ones, so this commit simply gives C2H_V0_ as prefix of command IDs. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtlwifi/rtl8723ae/hal_btc.c | 6 +++--- .../net/wireless/realtek/rtlwifi/rtl8723ae/hal_btc.h | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_btc.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_btc.c index ec9bcf32f0ab..788de88ab1ee 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_btc.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_btc.c @@ -1749,13 +1749,13 @@ void rtl_8723e_c2h_command_handle(struct ieee80211_hw *hw) switch (c2h_event.cmd_id) { - case C2H_BT_RSSI: + case C2H_V0_BT_RSSI: break; - case C2H_BT_OP_MODE: + case C2H_V0_BT_OP_MODE: break; - case BT_INFO: + case C2H_V0_BT_INFO: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "BT info Byte[0] (ID) is 0x%x\n", c2h_event.cmd_id); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_btc.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_btc.h index 3723d7476717..756868897d8b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_btc.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hal_btc.h @@ -130,17 +130,17 @@ enum bt_state { BT_INFO_STATE_MAX = 7 }; -enum rtl8723e_c2h_evt { - C2H_DBG = 0, - C2H_TSF = 1, - C2H_AP_RPT_RSP = 2, +enum rtl8723e_c2h_evt_v0 { + C2H_V0_DBG = 0, + C2H_V0_TSF = 1, + C2H_V0_AP_RPT_RSP = 2, /* The FW notify the report of the specific tx packet. */ - C2H_CCX_TX_RPT = 3, - C2H_BT_RSSI = 4, - C2H_BT_OP_MODE = 5, - C2H_HW_INFO_EXCH = 10, - C2H_C2H_H2C_TEST = 11, - BT_INFO = 12, + C2H_V0_CCX_TX_RPT = 3, + C2H_V0_BT_RSSI = 4, + C2H_V0_BT_OP_MODE = 5, + C2H_V0_HW_INFO_EXCH = 10, + C2H_V0_C2H_H2C_TEST = 11, + C2H_V0_BT_INFO = 12, MAX_C2HEVENT }; -- cgit v1.2.3 From 7aeb100b7d70973e1478f472b0a2fc569637ec8d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 18 May 2018 17:29:58 +0800 Subject: rtlwifi: remove duplicate C2H definition Move C2H definition to wifi.h, because the definitions of 8192ee, 8723be and 8821ae are the same. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c | 16 ++++++++-------- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h | 11 ----------- drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c | 12 ++++++------ drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.h | 10 ---------- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c | 12 ++++++------ drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h | 14 -------------- drivers/net/wireless/realtek/rtlwifi/wifi.h | 19 +++++++++++++++++++ 7 files changed, 39 insertions(+), 55 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c index f9563ae301ad..25d6c32f66c3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c @@ -892,34 +892,34 @@ void rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id, struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; switch (c2h_cmd_id) { - case C2H_8192E_DBG: + case C2H_DBG: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "[C2H], C2H_8723BE_DBG!!\n"); break; - case C2H_8192E_TXBF: + case C2H_TXBF: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "[C2H], C2H_8192E_TXBF!!\n"); break; - case C2H_8192E_TX_REPORT: + case C2H_TX_REPORT: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE , "[C2H], C2H_8723BE_TX_REPORT!\n"); rtl_tx_report_handler(hw, tmp_buf, c2h_cmd_len); break; - case C2H_8192E_BT_INFO: + case C2H_BT_INFO: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "[C2H], C2H_8723BE_BT_INFO!!\n"); if (rtlpriv->cfg->ops->get_btc_status()) btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf, c2h_cmd_len); break; - case C2H_8192E_BT_MP: + case C2H_BT_MP: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "[C2H], C2H_8723BE_BT_MP!!\n"); if (rtlpriv->cfg->ops->get_btc_status()) btc_ops->btc_btmpinfo_notify(rtlpriv, tmp_buf, c2h_cmd_len); break; - case C2H_8192E_RA_RPT: + case C2H_RA_RPT: _rtl92ee_c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len); break; default: @@ -948,8 +948,8 @@ void rtl92ee_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len) "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len); switch (c2h_cmd_id) { - case C2H_8192E_BT_INFO: - case C2H_8192E_BT_MP: + case C2H_BT_INFO: + case C2H_BT_MP: rtl_c2hcmd_enqueue(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf); break; default: diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h index b770f722daa6..8325adaa9663 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h @@ -128,17 +128,6 @@ enum rtl8192e_h2c_cmd { MAX_92E_H2CCMD }; -enum rtl8192e_c2h_evt { - C2H_8192E_DBG = 0, - C2H_8192E_LB = 1, - C2H_8192E_TXBF = 2, - C2H_8192E_TX_REPORT = 3, - C2H_8192E_BT_INFO = 9, - C2H_8192E_BT_MP = 11, - C2H_8192E_RA_RPT = 12, - MAX_8192E_C2HEVENT -}; - #define pagenum_128(_len) \ (u32)(((_len) >> 7) + ((_len) & 0x7F ? 1 : 0)) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c index 4b963fd27d64..34703b9cf5e8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c @@ -712,23 +712,23 @@ void rtl8723be_c2h_content_parsing(struct ieee80211_hw *hw, struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; switch (c2h_cmd_id) { - case C2H_8723B_DBG: + case C2H_DBG: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "[C2H], C2H_8723BE_DBG!!\n"); break; - case C2H_8723B_TX_REPORT: + case C2H_TX_REPORT: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "[C2H], C2H_8723BE_TX_REPORT!\n"); rtl_tx_report_handler(hw, tmp_buf, c2h_cmd_len); break; - case C2H_8723B_BT_INFO: + case C2H_BT_INFO: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "[C2H], C2H_8723BE_BT_INFO!!\n"); if (rtlpriv->cfg->ops->get_btc_status()) btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf, c2h_cmd_len); break; - case C2H_8723B_BT_MP: + case C2H_BT_MP: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "[C2H], C2H_8723BE_BT_MP!!\n"); if (rtlpriv->cfg->ops->get_btc_status()) @@ -761,8 +761,8 @@ void rtl8723be_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len) "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len); switch (c2h_cmd_id) { - case C2H_8723B_BT_INFO: - case C2H_8723B_BT_MP: + case C2H_BT_INFO: + case C2H_BT_MP: rtl_c2hcmd_enqueue(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf); break; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.h index 2de4edb62bca..8f49941028f4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.h @@ -100,16 +100,6 @@ enum rtl8723b_h2c_cmd { MAX_8723B_H2CCMD }; -enum rtl8723b_c2h_evt { - C2H_8723B_DBG = 0, - C2H_8723B_LB = 1, - C2H_8723B_TXBF = 2, - C2H_8723B_TX_REPORT = 3, - C2H_8723B_BT_INFO = 9, - C2H_8723B_BT_MP = 11, - MAX_8723B_C2HEVENT -}; - #define pagenum_128(_len) (u32)(((_len)>>7) + ((_len)&0x7F ? 1 : 0)) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c index f2b2c549e5b2..5c7e58fbc07e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c @@ -1926,23 +1926,23 @@ void rtl8821ae_c2h_content_parsing(struct ieee80211_hw *hw, struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; switch (c2h_cmd_id) { - case C2H_8812_DBG: + case C2H_DBG: RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "[C2H], C2H_8812_DBG!!\n"); break; - case C2H_8812_TX_REPORT: + case C2H_TX_REPORT: rtl_tx_report_handler(hw, tmp_buf, c2h_cmd_len); break; - case C2H_8812_RA_RPT: + case C2H_RA_RPT: rtl8821ae_c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len); break; - case C2H_8812_BT_INFO: + case C2H_BT_INFO: RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "[C2H], C2H_8812_BT_INFO!!\n"); if (rtlpriv->cfg->ops->get_btc_status()) btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf, c2h_cmd_len); break; - case C2H_8812_BT_MP: + case C2H_BT_MP: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "[C2H], C2H_8812_BT_MP!!\n"); if (rtlpriv->cfg->ops->get_btc_status()) @@ -1974,7 +1974,7 @@ void rtl8821ae_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len); switch (c2h_cmd_id) { - case C2H_8812_BT_INFO: + case C2H_BT_INFO: rtl_c2hcmd_enqueue(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf); break; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h index 32d46d7128f5..48c72a26c7e8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h @@ -137,20 +137,6 @@ #define FW_PWR_STATE_ACTIVE ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE)) #define FW_PWR_STATE_RF_OFF 0 -enum rtl8812_c2h_evt { - C2H_8812_DBG = 0, - C2H_8812_LB = 1, - C2H_8812_TXBF = 2, - C2H_8812_TX_REPORT = 3, - C2H_8812_BT_INFO = 9, - C2H_8812_BT_MP = 11, - C2H_8812_RA_RPT = 12, - - C2H_8812_FW_SWCHNL = 0x10, - C2H_8812_IQK_FINISH = 0x11, - MAX_8812_C2HEVENT -}; - enum rtl8821a_h2c_cmd { H2C_8821AE_RSVDPAGE = 0, H2C_8821AE_MSRRPT = 1, diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 81ac036760fc..3da8e2a6084a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -158,6 +158,25 @@ enum { H2C_BT_PORT_ID = 0x71, }; +enum rtl_c2h_evt_v1 { + C2H_DBG = 0, + C2H_LB = 1, + C2H_TXBF = 2, + C2H_TX_REPORT = 3, + C2H_BT_INFO = 9, + C2H_BT_MP = 11, + C2H_RA_RPT = 12, + + C2H_FW_SWCHNL = 0x10, + C2H_IQK_FINISH = 0x11, + + C2H_EXT_V2 = 0xFF, +}; + +enum rtl_c2h_evt_v2 { + C2H_V2_CCX_RPT = 0x0F, +}; + #define GET_TX_REPORT_SN_V1(c2h) (c2h[6]) #define GET_TX_REPORT_ST_V1(c2h) (c2h[0] & 0xC0) #define GET_TX_REPORT_RETRY_V1(c2h) (c2h[2] & 0x3F) -- cgit v1.2.3 From 16e78cb4a571129bbef5457c68856ff3d3895753 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 18 May 2018 17:29:59 +0800 Subject: rtlwifi: remove unused fw C2H command ID The IDs are defined by driver and map to the fw C2H IDs, but they aren't used now result in removal. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtlwifi/rtl8188ee/def.h | 25 ---------------------- .../net/wireless/realtek/rtlwifi/rtl8192ce/def.h | 25 ---------------------- .../net/wireless/realtek/rtlwifi/rtl8723ae/def.h | 25 ---------------------- .../net/wireless/realtek/rtlwifi/rtl8821ae/def.h | 25 ---------------------- 4 files changed, 100 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/def.h b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/def.h index 32492d64d685..45c866d3ca88 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/def.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/def.h @@ -176,31 +176,6 @@ enum interface_select_pci { INTF_SEL3_RSV = 3, }; -enum hal_fw_c2h_cmd_id { - HAL_FW_C2H_CMD_READ_MACREG = 0, - HAL_FW_C2H_CMD_READ_BBREG = 1, - HAL_FW_C2H_CMD_READ_RFREG = 2, - HAL_FW_C2H_CMD_READ_EEPROM = 3, - HAL_FW_C2H_CMD_READ_EFUSE = 4, - HAL_FW_C2H_CMD_READ_CAM = 5, - HAL_FW_C2H_CMD_GET_BASICRATE = 6, - HAL_FW_C2H_CMD_GET_DATARATE = 7, - HAL_FW_C2H_CMD_SURVEY = 8, - HAL_FW_C2H_CMD_SURVEYDONE = 9, - HAL_FW_C2H_CMD_JOINBSS = 10, - HAL_FW_C2H_CMD_ADDSTA = 11, - HAL_FW_C2H_CMD_DELSTA = 12, - HAL_FW_C2H_CMD_ATIMDONE = 13, - HAL_FW_C2H_CMD_TX_REPORT = 14, - HAL_FW_C2H_CMD_CCX_REPORT = 15, - HAL_FW_C2H_CMD_DTM_REPORT = 16, - HAL_FW_C2H_CMD_TX_RATE_STATISTICS = 17, - HAL_FW_C2H_CMD_C2HLBK = 18, - HAL_FW_C2H_CMD_C2HDBG = 19, - HAL_FW_C2H_CMD_C2HFEEDBACK = 20, - HAL_FW_C2H_CMD_MAX -}; - enum rtl_desc_qsel { QSLT_BK = 0x2, QSLT_BE = 0x0, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/def.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/def.h index b90aaf128072..d2005d7e9ad2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/def.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/def.h @@ -142,31 +142,6 @@ enum interface_select_pci { INTF_SEL3_RSV = 3, }; -enum hal_fw_c2h_cmd_id { - HAL_FW_C2H_CMD_Read_MACREG = 0, - HAL_FW_C2H_CMD_Read_BBREG = 1, - HAL_FW_C2H_CMD_Read_RFREG = 2, - HAL_FW_C2H_CMD_Read_EEPROM = 3, - HAL_FW_C2H_CMD_Read_EFUSE = 4, - HAL_FW_C2H_CMD_Read_CAM = 5, - HAL_FW_C2H_CMD_Get_BasicRate = 6, - HAL_FW_C2H_CMD_Get_DataRate = 7, - HAL_FW_C2H_CMD_Survey = 8, - HAL_FW_C2H_CMD_SurveyDone = 9, - HAL_FW_C2H_CMD_JoinBss = 10, - HAL_FW_C2H_CMD_AddSTA = 11, - HAL_FW_C2H_CMD_DelSTA = 12, - HAL_FW_C2H_CMD_AtimDone = 13, - HAL_FW_C2H_CMD_TX_Report = 14, - HAL_FW_C2H_CMD_CCX_Report = 15, - HAL_FW_C2H_CMD_DTM_Report = 16, - HAL_FW_C2H_CMD_TX_Rate_Statistics = 17, - HAL_FW_C2H_CMD_C2HLBK = 18, - HAL_FW_C2H_CMD_C2HDBG = 19, - HAL_FW_C2H_CMD_C2HFEEDBACK = 20, - HAL_FW_C2H_CMD_MAX -}; - enum rtl_desc_qsel { QSLT_BK = 0x2, QSLT_BE = 0x0, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/def.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/def.h index bcdf2273688e..847544817549 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/def.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/def.h @@ -152,31 +152,6 @@ enum interface_select_pci { INTF_SEL3_RSV = 3, }; -enum hal_fw_c2h_cmd_id { - HAL_FW_C2H_CMD_Read_MACREG = 0, - HAL_FW_C2H_CMD_Read_BBREG = 1, - HAL_FW_C2H_CMD_Read_RFREG = 2, - HAL_FW_C2H_CMD_Read_EEPROM = 3, - HAL_FW_C2H_CMD_Read_EFUSE = 4, - HAL_FW_C2H_CMD_Read_CAM = 5, - HAL_FW_C2H_CMD_Get_BasicRate = 6, - HAL_FW_C2H_CMD_Get_DataRate = 7, - HAL_FW_C2H_CMD_Survey = 8, - HAL_FW_C2H_CMD_SurveyDone = 9, - HAL_FW_C2H_CMD_JoinBss = 10, - HAL_FW_C2H_CMD_AddSTA = 11, - HAL_FW_C2H_CMD_DelSTA = 12, - HAL_FW_C2H_CMD_AtimDone = 13, - HAL_FW_C2H_CMD_TX_Report = 14, - HAL_FW_C2H_CMD_CCX_Report = 15, - HAL_FW_C2H_CMD_DTM_Report = 16, - HAL_FW_C2H_CMD_TX_Rate_Statistics = 17, - HAL_FW_C2H_CMD_C2HLBK = 18, - HAL_FW_C2H_CMD_C2HDBG = 19, - HAL_FW_C2H_CMD_C2HFEEDBACK = 20, - HAL_FW_C2H_CMD_MAX -}; - enum rtl_desc_qsel { QSLT_BK = 0x2, QSLT_BE = 0x0, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/def.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/def.h index 498f716bfc73..3fe3aaa5fe3c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/def.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/def.h @@ -296,31 +296,6 @@ enum interface_select_pci { INTF_SEL3_RSV = 3, }; -enum hal_fw_c2h_cmd_id { - HAL_FW_C2H_CMD_READ_MACREG = 0, - HAL_FW_C2H_CMD_READ_BBREG = 1, - HAL_FW_C2H_CMD_READ_RFREG = 2, - HAL_FW_C2H_CMD_READ_EEPROM = 3, - HAL_FW_C2H_CMD_READ_EFUSE = 4, - HAL_FW_C2H_CMD_READ_CAM = 5, - HAL_FW_C2H_CMD_GET_BASICRATE = 6, - HAL_FW_C2H_CMD_GET_DATARATE = 7, - HAL_FW_C2H_CMD_SURVEY = 8, - HAL_FW_C2H_CMD_SURVEYDONE = 9, - HAL_FW_C2H_CMD_JOINBSS = 10, - HAL_FW_C2H_CMD_ADDSTA = 11, - HAL_FW_C2H_CMD_DELSTA = 12, - HAL_FW_C2H_CMD_ATIMDONE = 13, - HAL_FW_C2H_CMD_TX_REPORT = 14, - HAL_FW_C2H_CMD_CCX_REPORT = 15, - HAL_FW_C2H_CMD_DTM_REPORT = 16, - HAL_FW_C2H_CMD_TX_RATE_STATISTICS = 17, - HAL_FW_C2H_CMD_C2HLBK = 18, - HAL_FW_C2H_CMD_C2HDBG = 19, - HAL_FW_C2H_CMD_C2HFEEDBACK = 20, - HAL_FW_C2H_CMD_MAX -}; - enum rtl_desc_qsel { QSLT_BK = 0x2, QSLT_BE = 0x0, -- cgit v1.2.3 From ff77960d62d220a0f16433e9c2664a8759f95c3a Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 18 May 2018 17:30:00 +0800 Subject: rtlwifi: remove dummy hal_op rx_command_packet from rtl8188ee and rtl8723ae The caller of hal_op rx_command_packet will assert function pointer before calling, so we can remove dummy functions safely. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c | 2 -- drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c | 7 ------- drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.h | 4 ---- drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c | 1 - drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c | 7 ------- drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.h | 3 --- 6 files changed, 24 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c index 82681b96ef93..8c15ffd3568b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c @@ -263,8 +263,6 @@ static struct rtl_hal_ops rtl8188ee_hal_ops = { .get_rfreg = rtl88e_phy_query_rf_reg, .set_rfreg = rtl88e_phy_set_rf_reg, .get_btc_status = rtl88e_get_btc_status, - .rx_command_packet = rtl88ee_rx_command_packet, - }; static struct rtl_mod_params rtl88ee_mod_params = { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c index 9670732b2bc6..4c1f8b08fc10 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c @@ -850,10 +850,3 @@ void rtl88ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) BIT(0) << (hw_queue)); } } - -u32 rtl88ee_rx_command_packet(struct ieee80211_hw *hw, - const struct rtl_stats *status, - struct sk_buff *skb) -{ - return 0; -} diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.h index f902d6769aa8..127ba977206f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.h @@ -790,8 +790,4 @@ void rtl88ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, bool lastseg, struct sk_buff *skb); -u32 rtl88ee_rx_command_packet(struct ieee80211_hw *hw, - const struct rtl_stats *status, - struct sk_buff *skb); - #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c index a545ea317323..07b82700d1de 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c @@ -260,7 +260,6 @@ static struct rtl_hal_ops rtl8723e_hal_ops = { .bt_coex_off_before_lps = rtl8723e_dm_bt_turn_off_bt_coexist_before_enter_lps, .get_btc_status = rtl8723e_get_btc_status, - .rx_command_packet = rtl8723e_rx_command_packet, .is_fw_header = is_fw_header, }; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c index 23485602a9a1..d461d0c9631f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c @@ -709,10 +709,3 @@ void rtl8723e_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) BIT(0) << (hw_queue)); } } - -u32 rtl8723e_rx_command_packet(struct ieee80211_hw *hw, - const struct rtl_stats *status, - struct sk_buff *skb) -{ - return 0; -} diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.h index 985ce0b77ea5..d592b08d4ac8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.h @@ -716,7 +716,4 @@ void rtl8723e_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); void rtl8723e_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, bool lastseg, struct sk_buff *skb); -u32 rtl8723e_rx_command_packet(struct ieee80211_hw *hw, - const struct rtl_stats *status, - struct sk_buff *skb); #endif -- cgit v1.2.3 From 16cefa449c9ced7006860d5427b9595782248ca4 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 18 May 2018 17:30:01 +0800 Subject: rtlwifi: Add hal_op c2h_ra_report_handler for special process We're going to merge C2H handler into one, but one special case is to handle RA_REPORT that implements in individual IC folder. So this commit adds a hal_op for caller in common code. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c | 7 ++++--- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h | 2 ++ drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c | 1 + drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c | 5 +++-- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h | 2 ++ drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c | 1 + drivers/net/wireless/realtek/rtlwifi/wifi.h | 2 ++ 7 files changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c index 25d6c32f66c3..a2d9e217bc65 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c @@ -876,8 +876,8 @@ void rtl92ee_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state) (u8 *)p2p_ps_offload); } -static void _rtl92ee_c2h_ra_report_handler(struct ieee80211_hw *hw, - u8 *cmd_buf, u8 cmd_len) +void rtl92ee_c2h_ra_report_handler(struct ieee80211_hw *hw, + u8 *cmd_buf, u8 cmd_len) { u8 rate = cmd_buf[0] & 0x3F; bool collision_state = cmd_buf[3] & BIT(0); @@ -889,6 +889,7 @@ void rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id, u8 c2h_cmd_len, u8 *tmp_buf) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal_ops *hal_ops = rtlpriv->cfg->ops; struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; switch (c2h_cmd_id) { @@ -920,7 +921,7 @@ void rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id, c2h_cmd_len); break; case C2H_RA_RPT: - _rtl92ee_c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len); + hal_ops->c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len); break; default: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h index 8325adaa9663..e5fae0a86a27 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h @@ -182,4 +182,6 @@ void rtl92ee_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state); void rtl92ee_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len); void rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id, u8 c2h_cmd_len, u8 *tmp_buf); +void rtl92ee_c2h_ra_report_handler(struct ieee80211_hw *hw, + u8 *cmd_buf, u8 cmd_len); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c index ef92a789871d..c5c26b537cd2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c @@ -252,6 +252,7 @@ static struct rtl_hal_ops rtl8192ee_hal_ops = { .get_btc_status = rtl92ee_get_btc_status, .rx_command_packet = rtl92ee_rx_command_packet, .c2h_content_parsing = rtl92ee_c2h_content_parsing, + .c2h_ra_report_handler = rtl92ee_c2h_ra_report_handler, }; static struct rtl_mod_params rtl92ee_mod_params = { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c index 5c7e58fbc07e..bf37c428c682 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c @@ -1907,7 +1907,7 @@ void rtl8821ae_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state) H2C_8821AE_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload); } -static void rtl8821ae_c2h_ra_report_handler(struct ieee80211_hw *hw, +void rtl8821ae_c2h_ra_report_handler(struct ieee80211_hw *hw, u8 *cmd_buf, u8 cmd_len) { struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); @@ -1923,6 +1923,7 @@ void rtl8821ae_c2h_content_parsing(struct ieee80211_hw *hw, u8 *tmp_buf) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal_ops *hal_ops = rtlpriv->cfg->ops; struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; switch (c2h_cmd_id) { @@ -1933,7 +1934,7 @@ void rtl8821ae_c2h_content_parsing(struct ieee80211_hw *hw, rtl_tx_report_handler(hw, tmp_buf, c2h_cmd_len); break; case C2H_RA_RPT: - rtl8821ae_c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len); + hal_ops->c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len); break; case C2H_BT_INFO: RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h index 48c72a26c7e8..a69448be7c26 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h @@ -322,4 +322,6 @@ void rtl8821ae_c2h_packet_handler(struct ieee80211_hw *hw, void rtl8821ae_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id, u8 c2h_cmd_len, u8 *tmp_buf); +void rtl8821ae_c2h_ra_report_handler(struct ieee80211_hw *hw, + u8 *cmd_buf, u8 cmd_len); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index 9bb3d9dfce79..4b2cb6bda4f1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -305,6 +305,7 @@ static struct rtl_hal_ops rtl8821ae_hal_ops = { .get_btc_status = rtl8821ae_get_btc_status, .rx_command_packet = rtl8821ae_rx_command_packet, .c2h_content_parsing = rtl8821ae_c2h_content_parsing, + .c2h_ra_report_handler = rtl8821ae_c2h_ra_report_handler, .add_wowlan_pattern = rtl8821ae_add_wowlan_pattern, }; diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 3da8e2a6084a..392b3e84db7e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2348,6 +2348,8 @@ struct rtl_hal_ops { u16 (*get_available_desc)(struct ieee80211_hw *hw, u8 q_idx); void (*c2h_content_parsing)(struct ieee80211_hw *hw, u8 tag, u8 len, u8 *val); + void (*c2h_ra_report_handler)(struct ieee80211_hw *hw, + u8 *cmd_buf, u8 cmd_len); }; struct rtl_intf_ops { -- cgit v1.2.3 From daf026ae5fbe094e63bb729d437b042a0a5fd798 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 18 May 2018 17:30:02 +0800 Subject: rtlwifi: remove duplicate C2H handler Merge duplicate C2H handler and implement the handler in base.c. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/base.c | 72 +++++++++++++++++++++ drivers/net/wireless/realtek/rtlwifi/base.h | 3 + .../net/wireless/realtek/rtlwifi/rtl8192ee/fw.c | 75 ---------------------- .../net/wireless/realtek/rtlwifi/rtl8192ee/fw.h | 3 - .../net/wireless/realtek/rtlwifi/rtl8192ee/sw.c | 2 +- .../net/wireless/realtek/rtlwifi/rtl8192ee/trx.c | 2 +- .../net/wireless/realtek/rtlwifi/rtl8723be/fw.c | 69 -------------------- .../net/wireless/realtek/rtlwifi/rtl8723be/fw.h | 3 - .../net/wireless/realtek/rtlwifi/rtl8723be/sw.c | 2 +- .../net/wireless/realtek/rtlwifi/rtl8723be/trx.c | 3 +- .../net/wireless/realtek/rtlwifi/rtl8821ae/fw.c | 68 -------------------- .../net/wireless/realtek/rtlwifi/rtl8821ae/fw.h | 5 -- .../net/wireless/realtek/rtlwifi/rtl8821ae/sw.c | 2 +- .../net/wireless/realtek/rtlwifi/rtl8821ae/trx.c | 2 +- 14 files changed, 81 insertions(+), 230 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index 759a802ccbee..0d03e98f9cb4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -2306,6 +2306,78 @@ label_err: } EXPORT_SYMBOL(rtl_c2hcmd_enqueue); +void rtl_c2h_content_parsing(struct ieee80211_hw *hw, u8 cmd_id, + u8 cmd_len, u8 *cmd_buf) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal_ops *hal_ops = rtlpriv->cfg->ops; + const struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; + + switch (cmd_id) { + case C2H_DBG: + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "[C2H], C2H_DBG!!\n"); + break; + case C2H_TXBF: + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + "[C2H], C2H_TXBF!!\n"); + break; + case C2H_TX_REPORT: + rtl_tx_report_handler(hw, cmd_buf, cmd_len); + break; + case C2H_RA_RPT: + if (hal_ops->c2h_ra_report_handler) + hal_ops->c2h_ra_report_handler(hw, cmd_buf, cmd_len); + break; + case C2H_BT_INFO: + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + "[C2H], C2H_BT_INFO!!\n"); + if (rtlpriv->cfg->ops->get_btc_status()) + btc_ops->btc_btinfo_notify(rtlpriv, cmd_buf, cmd_len); + break; + case C2H_BT_MP: + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + "[C2H], C2H_BT_MP!!\n"); + if (rtlpriv->cfg->ops->get_btc_status()) + btc_ops->btc_btmpinfo_notify(rtlpriv, cmd_buf, cmd_len); + break; + default: + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + "[C2H], Unknown packet!! cmd_id(%#X)!\n", cmd_id); + break; + } +} +EXPORT_SYMBOL_GPL(rtl_c2h_content_parsing); + +void rtl_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 c2h_cmd_id = 0, c2h_cmd_seq = 0, c2h_cmd_len = 0; + u8 *tmp_buf = NULL; + + c2h_cmd_id = buffer[0]; + c2h_cmd_seq = buffer[1]; + c2h_cmd_len = len - 2; + tmp_buf = buffer + 2; + + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + "[C2H packet], c2hCmdId=0x%x, c2hCmdSeq=0x%x, c2hCmdLen=%d\n", + c2h_cmd_id, c2h_cmd_seq, c2h_cmd_len); + + RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_TRACE, + "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len); + + switch (c2h_cmd_id) { + case C2H_BT_INFO: + case C2H_BT_MP: + rtl_c2hcmd_enqueue(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf); + break; + default: + rtl_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf); + break; + } +} +EXPORT_SYMBOL_GPL(rtl_c2h_packet_handler); + void rtl_c2hcmd_launcher(struct ieee80211_hw *hw, int exec) { struct rtl_priv *rtlpriv = rtl_priv(hw); diff --git a/drivers/net/wireless/realtek/rtlwifi/base.h b/drivers/net/wireless/realtek/rtlwifi/base.h index 19e7477839e4..3bf174e5b07e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.h +++ b/drivers/net/wireless/realtek/rtlwifi/base.h @@ -162,6 +162,9 @@ void rtl_fwevt_wq_callback(void *data); void rtl_c2hcmd_wq_callback(void *data); void rtl_c2hcmd_launcher(struct ieee80211_hw *hw, int exec); void rtl_c2hcmd_enqueue(struct ieee80211_hw *hw, u8 tag, u8 len, u8 *val); +void rtl_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id, + u8 c2h_cmd_len, u8 *tmp_buf); +void rtl_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len); u8 rtl_mrate_idx_to_arfr_id(struct ieee80211_hw *hw, u8 rate_index, enum wireless_mode wirelessmode); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c index a2d9e217bc65..84a0d0eb72e1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c @@ -884,78 +884,3 @@ void rtl92ee_c2h_ra_report_handler(struct ieee80211_hw *hw, rtl92ee_dm_dynamic_arfb_select(hw, rate, collision_state); } - -void rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id, - u8 c2h_cmd_len, u8 *tmp_buf) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal_ops *hal_ops = rtlpriv->cfg->ops; - struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; - - switch (c2h_cmd_id) { - case C2H_DBG: - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, - "[C2H], C2H_8723BE_DBG!!\n"); - break; - case C2H_TXBF: - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, - "[C2H], C2H_8192E_TXBF!!\n"); - break; - case C2H_TX_REPORT: - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE , - "[C2H], C2H_8723BE_TX_REPORT!\n"); - rtl_tx_report_handler(hw, tmp_buf, c2h_cmd_len); - break; - case C2H_BT_INFO: - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, - "[C2H], C2H_8723BE_BT_INFO!!\n"); - if (rtlpriv->cfg->ops->get_btc_status()) - btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf, - c2h_cmd_len); - break; - case C2H_BT_MP: - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, - "[C2H], C2H_8723BE_BT_MP!!\n"); - if (rtlpriv->cfg->ops->get_btc_status()) - btc_ops->btc_btmpinfo_notify(rtlpriv, tmp_buf, - c2h_cmd_len); - break; - case C2H_RA_RPT: - hal_ops->c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len); - break; - default: - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, - "[C2H], Unknown packet!! CmdId(%#X)!\n", c2h_cmd_id); - break; - } -} - -void rtl92ee_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - u8 c2h_cmd_id = 0, c2h_cmd_seq = 0, c2h_cmd_len = 0; - u8 *tmp_buf = NULL; - - c2h_cmd_id = buffer[0]; - c2h_cmd_seq = buffer[1]; - c2h_cmd_len = len - 2; - tmp_buf = buffer + 2; - - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, - "[C2H packet], c2hCmdId=0x%x, c2hCmdSeq=0x%x, c2hCmdLen=%d\n", - c2h_cmd_id, c2h_cmd_seq, c2h_cmd_len); - - RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_TRACE, - "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len); - - switch (c2h_cmd_id) { - case C2H_BT_INFO: - case C2H_BT_MP: - rtl_c2hcmd_enqueue(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf); - break; - default: - rtl92ee_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len, - tmp_buf); - break; - } -} diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h index e5fae0a86a27..6a2fbf20d579 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h @@ -179,9 +179,6 @@ void rtl92ee_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); void rtl92ee_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw, u8 mstatus); void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); void rtl92ee_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state); -void rtl92ee_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len); -void rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id, - u8 c2h_cmd_len, u8 *tmp_buf); void rtl92ee_c2h_ra_report_handler(struct ieee80211_hw *hw, u8 *cmd_buf, u8 cmd_len); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c index c5c26b537cd2..fd028274c593 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c @@ -251,7 +251,7 @@ static struct rtl_hal_ops rtl8192ee_hal_ops = { .fill_h2c_cmd = rtl92ee_fill_h2c_cmd, .get_btc_status = rtl92ee_get_btc_status, .rx_command_packet = rtl92ee_rx_command_packet, - .c2h_content_parsing = rtl92ee_c2h_content_parsing, + .c2h_content_parsing = rtl_c2h_content_parsing, .c2h_ra_report_handler = rtl92ee_c2h_ra_report_handler, }; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c index 852a2701ef55..e525c2bb4457 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c @@ -1085,7 +1085,7 @@ u32 rtl92ee_rx_command_packet(struct ieee80211_hw *hw, result = 0; break; case C2H_PACKET: - rtl92ee_c2h_packet_handler(hw, skb->data, (u8)skb->len); + rtl_c2h_packet_handler(hw, skb->data, (u8)skb->len); result = 1; break; default: diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c index 34703b9cf5e8..f2441fbb92f1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c @@ -703,72 +703,3 @@ void rtl8723be_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, rtl8723be_fill_h2c_cmd(hw, H2C_8723B_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload); } - -void rtl8723be_c2h_content_parsing(struct ieee80211_hw *hw, - u8 c2h_cmd_id, - u8 c2h_cmd_len, u8 *tmp_buf) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; - - switch (c2h_cmd_id) { - case C2H_DBG: - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, - "[C2H], C2H_8723BE_DBG!!\n"); - break; - case C2H_TX_REPORT: - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, - "[C2H], C2H_8723BE_TX_REPORT!\n"); - rtl_tx_report_handler(hw, tmp_buf, c2h_cmd_len); - break; - case C2H_BT_INFO: - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, - "[C2H], C2H_8723BE_BT_INFO!!\n"); - if (rtlpriv->cfg->ops->get_btc_status()) - btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf, - c2h_cmd_len); - break; - case C2H_BT_MP: - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, - "[C2H], C2H_8723BE_BT_MP!!\n"); - if (rtlpriv->cfg->ops->get_btc_status()) - btc_ops->btc_btmpinfo_notify(rtlpriv, tmp_buf, - c2h_cmd_len); - break; - default: - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, - "[C2H], Unknown packet!! CmdId(%#X)!\n", c2h_cmd_id); - break; - } -} - -void rtl8723be_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - u8 c2h_cmd_id = 0, c2h_cmd_seq = 0, c2h_cmd_len = 0; - u8 *tmp_buf = NULL; - - c2h_cmd_id = buffer[0]; - c2h_cmd_seq = buffer[1]; - c2h_cmd_len = len - 2; - tmp_buf = buffer + 2; - - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, - "[C2H packet], c2hCmdId=0x%x, c2hCmdSeq=0x%x, c2hCmdLen=%d\n", - c2h_cmd_id, c2h_cmd_seq, c2h_cmd_len); - - RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_TRACE, - "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len); - - switch (c2h_cmd_id) { - case C2H_BT_INFO: - case C2H_BT_MP: - rtl_c2hcmd_enqueue(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf); - break; - - default: - rtl8723be_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len, - tmp_buf); - break; - } -} diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.h index 8f49941028f4..948d28646364 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.h @@ -143,7 +143,4 @@ void rtl8723be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); void rtl8723be_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw, u8 mstatus); void rtl8723be_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); void rtl8723be_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state); -void rtl8723be_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len); -void rtl8723be_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id, - u8 c2h_cmd_len, u8 *tmp_buf); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c index 6a42988aad65..9df994965c4a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c @@ -263,7 +263,7 @@ static struct rtl_hal_ops rtl8723be_hal_ops = { .get_btc_status = rtl8723be_get_btc_status, .rx_command_packet = rtl8723be_rx_command_packet, .is_fw_header = is_fw_header, - .c2h_content_parsing = rtl8723be_c2h_content_parsing, + .c2h_content_parsing = rtl_c2h_content_parsing, }; static struct rtl_mod_params rtl8723be_mod_params = { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c index deb8f9501b51..0c0cece9d5f9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c @@ -774,8 +774,7 @@ u32 rtl8723be_rx_command_packet(struct ieee80211_hw *hw, result = 0; break; case C2H_PACKET: - rtl8723be_c2h_packet_handler(hw, skb->data, - (u8)skb->len); + rtl_c2h_packet_handler(hw, skb->data, (u8)skb->len); result = 1; break; default: diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c index bf37c428c682..d868a034659f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c @@ -1917,71 +1917,3 @@ void rtl8821ae_c2h_ra_report_handler(struct ieee80211_hw *hw, rtl8821ae_dm_update_init_rate(hw, rate); } - -void rtl8821ae_c2h_content_parsing(struct ieee80211_hw *hw, - u8 c2h_cmd_id, u8 c2h_cmd_len, - u8 *tmp_buf) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal_ops *hal_ops = rtlpriv->cfg->ops; - struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; - - switch (c2h_cmd_id) { - case C2H_DBG: - RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "[C2H], C2H_8812_DBG!!\n"); - break; - case C2H_TX_REPORT: - rtl_tx_report_handler(hw, tmp_buf, c2h_cmd_len); - break; - case C2H_RA_RPT: - hal_ops->c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len); - break; - case C2H_BT_INFO: - RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, - "[C2H], C2H_8812_BT_INFO!!\n"); - if (rtlpriv->cfg->ops->get_btc_status()) - btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf, - c2h_cmd_len); - break; - case C2H_BT_MP: - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, - "[C2H], C2H_8812_BT_MP!!\n"); - if (rtlpriv->cfg->ops->get_btc_status()) - btc_ops->btc_btmpinfo_notify(rtlpriv, tmp_buf, - c2h_cmd_len); - break; - default: - break; - } -} - -void rtl8821ae_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, - u8 length) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - u8 c2h_cmd_id = 0, c2h_cmd_seq = 0, c2h_cmd_len = 0; - u8 *tmp_buf = NULL; - - c2h_cmd_id = buffer[0]; - c2h_cmd_seq = buffer[1]; - c2h_cmd_len = length - 2; - tmp_buf = buffer + 2; - - RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, - "[C2H packet], c2hCmdId=0x%x, c2hCmdSeq=0x%x, c2hCmdLen=%d\n", - c2h_cmd_id, c2h_cmd_seq, c2h_cmd_len); - - RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_LOUD, - "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len); - - switch (c2h_cmd_id) { - case C2H_BT_INFO: - rtl_c2hcmd_enqueue(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf); - break; - - default: - rtl8821ae_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len, - tmp_buf); - break; - } -} diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h index a69448be7c26..99c902ff0b84 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h @@ -317,11 +317,6 @@ void rtl8821ae_set_fw_keep_alive_cmd(struct ieee80211_hw *hw, bool func_en); void rtl8821ae_set_fw_disconnect_decision_ctrl_cmd(struct ieee80211_hw *hw, bool enabled); void rtl8821ae_set_fw_global_info_cmd(struct ieee80211_hw *hw); -void rtl8821ae_c2h_packet_handler(struct ieee80211_hw *hw, - u8 *buffer, u8 length); -void rtl8821ae_c2h_content_parsing(struct ieee80211_hw *hw, - u8 c2h_cmd_id, u8 c2h_cmd_len, - u8 *tmp_buf); void rtl8821ae_c2h_ra_report_handler(struct ieee80211_hw *hw, u8 *cmd_buf, u8 cmd_len); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index 4b2cb6bda4f1..bcabf4dc6353 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -304,7 +304,7 @@ static struct rtl_hal_ops rtl8821ae_hal_ops = { .fill_h2c_cmd = rtl8821ae_fill_h2c_cmd, .get_btc_status = rtl8821ae_get_btc_status, .rx_command_packet = rtl8821ae_rx_command_packet, - .c2h_content_parsing = rtl8821ae_c2h_content_parsing, + .c2h_content_parsing = rtl_c2h_content_parsing, .c2h_ra_report_handler = rtl8821ae_c2h_ra_report_handler, .add_wowlan_pattern = rtl8821ae_add_wowlan_pattern, }; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c index 63fb80039f82..a93d8569c186 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c @@ -1018,7 +1018,7 @@ u32 rtl8821ae_rx_command_packet(struct ieee80211_hw *hw, result = 0; break; case C2H_PACKET: - rtl8821ae_c2h_packet_handler(hw, skb->data, (u8)skb->len); + rtl_c2h_packet_handler(hw, skb->data, (u8)skb->len); result = 1; RT_TRACE(rtlpriv, COMP_RECV, DBG_LOUD, "skb->len=%d\n\n", skb->len); -- cgit v1.2.3 From 23ffab177b1da1564c14214f290925a77f0b3592 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 18 May 2018 17:30:03 +0800 Subject: rtlwifi: remove hal_op rx_command_packet Because the hal_op rx_command_packet does C2H handler if rx packet type is C2H, and the handler have been moved to base.c so we can call the handler directly. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/pci.c | 4 ++-- .../net/wireless/realtek/rtlwifi/rtl8192ee/sw.c | 1 - .../net/wireless/realtek/rtlwifi/rtl8192ee/trx.c | 24 -------------------- .../net/wireless/realtek/rtlwifi/rtl8192ee/trx.h | 3 --- .../net/wireless/realtek/rtlwifi/rtl8723be/sw.c | 1 - .../net/wireless/realtek/rtlwifi/rtl8723be/trx.c | 24 -------------------- .../net/wireless/realtek/rtlwifi/rtl8723be/trx.h | 3 --- .../net/wireless/realtek/rtlwifi/rtl8821ae/sw.c | 1 - .../net/wireless/realtek/rtlwifi/rtl8821ae/trx.c | 26 ---------------------- .../net/wireless/realtek/rtlwifi/rtl8821ae/trx.h | 3 --- drivers/net/wireless/realtek/rtlwifi/wifi.h | 2 -- 11 files changed, 2 insertions(+), 90 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index d0c509ef790e..dd51c67c09fa 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -830,8 +830,8 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) goto new_trx_end; } /* handle command packet here */ - if (rtlpriv->cfg->ops->rx_command_packet && - rtlpriv->cfg->ops->rx_command_packet(hw, &stats, skb)) { + if (stats.packet_report_type == C2H_PACKET) { + rtl_c2h_packet_handler(hw, skb->data, (u8)skb->len); dev_kfree_skb_any(skb); goto new_trx_end; } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c index fd028274c593..5b67ad748d67 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c @@ -250,7 +250,6 @@ static struct rtl_hal_ops rtl8192ee_hal_ops = { .set_rfreg = rtl92ee_phy_set_rf_reg, .fill_h2c_cmd = rtl92ee_fill_h2c_cmd, .get_btc_status = rtl92ee_get_btc_status, - .rx_command_packet = rtl92ee_rx_command_packet, .c2h_content_parsing = rtl_c2h_content_parsing, .c2h_ra_report_handler = rtl92ee_c2h_ra_report_handler, }; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c index e525c2bb4457..14d6e3fc5767 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c @@ -1072,27 +1072,3 @@ bool rtl92ee_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, u16 index) void rtl92ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) { } - -u32 rtl92ee_rx_command_packet(struct ieee80211_hw *hw, - const struct rtl_stats *status, - struct sk_buff *skb) -{ - u32 result = 0; - struct rtl_priv *rtlpriv = rtl_priv(hw); - - switch (status->packet_report_type) { - case NORMAL_RX: - result = 0; - break; - case C2H_PACKET: - rtl_c2h_packet_handler(hw, skb->data, (u8)skb->len); - result = 1; - break; - default: - RT_TRACE(rtlpriv, COMP_RECV, DBG_TRACE, - "Unknown packet type %d\n", status->packet_report_type); - break; - } - - return result; -} diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h index 48c16fff20c6..45df3e79f490 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h @@ -762,7 +762,4 @@ void rtl92ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); void rtl92ee_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, bool lastseg, struct sk_buff *skb); -u32 rtl92ee_rx_command_packet(struct ieee80211_hw *hw, - const struct rtl_stats *status, - struct sk_buff *skb); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c index 9df994965c4a..a41e67b3f38b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c @@ -261,7 +261,6 @@ static struct rtl_hal_ops rtl8723be_hal_ops = { .set_rfreg = rtl8723be_phy_set_rf_reg, .fill_h2c_cmd = rtl8723be_fill_h2c_cmd, .get_btc_status = rtl8723be_get_btc_status, - .rx_command_packet = rtl8723be_rx_command_packet, .is_fw_header = is_fw_header, .c2h_content_parsing = rtl_c2h_content_parsing, }; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c index 0c0cece9d5f9..9f8dfb5af774 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c @@ -761,27 +761,3 @@ void rtl8723be_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) BIT(0) << (hw_queue)); } } - -u32 rtl8723be_rx_command_packet(struct ieee80211_hw *hw, - const struct rtl_stats *status, - struct sk_buff *skb) -{ - u32 result = 0; - struct rtl_priv *rtlpriv = rtl_priv(hw); - - switch (status->packet_report_type) { - case NORMAL_RX: - result = 0; - break; - case C2H_PACKET: - rtl_c2h_packet_handler(hw, skb->data, (u8)skb->len); - result = 1; - break; - default: - RT_TRACE(rtlpriv, COMP_RECV, DBG_TRACE, - "No this packet type!!\n"); - break; - } - - return result; -} diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h index 988bf0586674..609f7ad7f787 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h @@ -632,7 +632,4 @@ void rtl8723be_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); void rtl8723be_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, bool lastseg, struct sk_buff *skb); -u32 rtl8723be_rx_command_packet(struct ieee80211_hw *hw, - const struct rtl_stats *status, - struct sk_buff *skb); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index bcabf4dc6353..8ff8a406db52 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -303,7 +303,6 @@ static struct rtl_hal_ops rtl8821ae_hal_ops = { .set_rfreg = rtl8821ae_phy_set_rf_reg, .fill_h2c_cmd = rtl8821ae_fill_h2c_cmd, .get_btc_status = rtl8821ae_get_btc_status, - .rx_command_packet = rtl8821ae_rx_command_packet, .c2h_content_parsing = rtl_c2h_content_parsing, .c2h_ra_report_handler = rtl8821ae_c2h_ra_report_handler, .add_wowlan_pattern = rtl8821ae_add_wowlan_pattern, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c index a93d8569c186..d7960dd5bf1a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c @@ -1005,29 +1005,3 @@ void rtl8821ae_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) BIT(0) << (hw_queue)); } } - -u32 rtl8821ae_rx_command_packet(struct ieee80211_hw *hw, - const struct rtl_stats *status, - struct sk_buff *skb) -{ - u32 result = 0; - struct rtl_priv *rtlpriv = rtl_priv(hw); - - switch (status->packet_report_type) { - case NORMAL_RX: - result = 0; - break; - case C2H_PACKET: - rtl_c2h_packet_handler(hw, skb->data, (u8)skb->len); - result = 1; - RT_TRACE(rtlpriv, COMP_RECV, DBG_LOUD, - "skb->len=%d\n\n", skb->len); - break; - default: - RT_TRACE(rtlpriv, COMP_RECV, DBG_LOUD, - "No this packet type!!\n"); - break; - } - - return result; -} diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h index 221dd2b29d3b..4ff0968dba81 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h @@ -628,7 +628,4 @@ void rtl8821ae_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); void rtl8821ae_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, bool lastseg, struct sk_buff *skb); -u32 rtl8821ae_rx_command_packet(struct ieee80211_hw *hw, - const struct rtl_stats *status, - struct sk_buff *skb); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 392b3e84db7e..b40d8f5bbdce 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2340,8 +2340,6 @@ struct rtl_hal_ops { void (*set_default_port_id_cmd)(struct ieee80211_hw *hw); bool (*get_btc_status) (void); bool (*is_fw_header)(struct rtlwifi_firmware_header *hdr); - u32 (*rx_command_packet)(struct ieee80211_hw *hw, - const struct rtl_stats *status, struct sk_buff *skb); void (*add_wowlan_pattern)(struct ieee80211_hw *hw, struct rtl_wow_pattern *rtl_pattern, u8 index); -- cgit v1.2.3 From b4f6ee489cff1e9c8637996b7c1079e8bdd979df Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 18 May 2018 17:30:04 +0800 Subject: rtlwifi: remove hal_op c2h_content_parsing Similar to rx_command_packet, we can call rtl_c2h_content_parsing so the hal_op isn't necessary. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/base.c | 7 +++---- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c | 1 - drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c | 1 - drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c | 1 - drivers/net/wireless/realtek/rtlwifi/wifi.h | 2 -- 5 files changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index 0d03e98f9cb4..927b7d231576 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -2346,7 +2346,6 @@ void rtl_c2h_content_parsing(struct ieee80211_hw *hw, u8 cmd_id, break; } } -EXPORT_SYMBOL_GPL(rtl_c2h_content_parsing); void rtl_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len) { @@ -2401,9 +2400,9 @@ void rtl_c2hcmd_launcher(struct ieee80211_hw *hw, int exec) if (!c2hcmd) break; - if (rtlpriv->cfg->ops->c2h_content_parsing && exec) - rtlpriv->cfg->ops->c2h_content_parsing(hw, - c2hcmd->tag, c2hcmd->len, c2hcmd->val); + if (exec) + rtl_c2h_content_parsing(hw, c2hcmd->tag, + c2hcmd->len, c2hcmd->val); /* free */ kfree(c2hcmd->val); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c index 5b67ad748d67..9ea62599ecbb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c @@ -250,7 +250,6 @@ static struct rtl_hal_ops rtl8192ee_hal_ops = { .set_rfreg = rtl92ee_phy_set_rf_reg, .fill_h2c_cmd = rtl92ee_fill_h2c_cmd, .get_btc_status = rtl92ee_get_btc_status, - .c2h_content_parsing = rtl_c2h_content_parsing, .c2h_ra_report_handler = rtl92ee_c2h_ra_report_handler, }; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c index a41e67b3f38b..c9f7b042d9c6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c @@ -262,7 +262,6 @@ static struct rtl_hal_ops rtl8723be_hal_ops = { .fill_h2c_cmd = rtl8723be_fill_h2c_cmd, .get_btc_status = rtl8723be_get_btc_status, .is_fw_header = is_fw_header, - .c2h_content_parsing = rtl_c2h_content_parsing, }; static struct rtl_mod_params rtl8723be_mod_params = { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index 8ff8a406db52..77f6401021c9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -303,7 +303,6 @@ static struct rtl_hal_ops rtl8821ae_hal_ops = { .set_rfreg = rtl8821ae_phy_set_rf_reg, .fill_h2c_cmd = rtl8821ae_fill_h2c_cmd, .get_btc_status = rtl8821ae_get_btc_status, - .c2h_content_parsing = rtl_c2h_content_parsing, .c2h_ra_report_handler = rtl8821ae_c2h_ra_report_handler, .add_wowlan_pattern = rtl8821ae_add_wowlan_pattern, }; diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index b40d8f5bbdce..930e1ec2280f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2344,8 +2344,6 @@ struct rtl_hal_ops { struct rtl_wow_pattern *rtl_pattern, u8 index); u16 (*get_available_desc)(struct ieee80211_hw *hw, u8 q_idx); - void (*c2h_content_parsing)(struct ieee80211_hw *hw, u8 tag, u8 len, - u8 *val); void (*c2h_ra_report_handler)(struct ieee80211_hw *hw, u8 *cmd_buf, u8 cmd_len); }; -- cgit v1.2.3 From 9ae6ed271a60f0e4476fe94f0efc5aba184a9c57 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 18 May 2018 17:30:05 +0800 Subject: rtlwifi: use sk_buff to queue C2H commands We use 'struct rtl_c2hcmd' to store C2H commands originally, and the code is slightly complex to enqueue and dequeue and also wastes time to allocate and memcpy data. Since C2H commands are asynchronous events, they can be processed in work queue, so RX ISR enqueues C2H result in removal of rtl_c2h_packet_handler(). Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/base.c | 96 +++++++---------------------- drivers/net/wireless/realtek/rtlwifi/base.h | 5 +- drivers/net/wireless/realtek/rtlwifi/pci.c | 3 +- drivers/net/wireless/realtek/rtlwifi/wifi.h | 2 +- 4 files changed, 25 insertions(+), 81 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index 927b7d231576..61f12f86fcd4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -571,9 +571,9 @@ int rtl_init_core(struct ieee80211_hw *hw) spin_lock_init(&rtlpriv->locks.iqk_lock); /* <5> init list */ INIT_LIST_HEAD(&rtlpriv->entry_list); - INIT_LIST_HEAD(&rtlpriv->c2hcmd_list); INIT_LIST_HEAD(&rtlpriv->scan_list.list); skb_queue_head_init(&rtlpriv->tx_report.queue); + skb_queue_head_init(&rtlpriv->c2hcmd_queue); rtlmac->link_state = MAC80211_NOLINK; @@ -2262,56 +2262,36 @@ void rtl_fwevt_wq_callback(void *data) rtlpriv->cfg->ops->c2h_command_handle(hw); } -void rtl_c2hcmd_enqueue(struct ieee80211_hw *hw, u8 tag, u8 len, u8 *val) +void rtl_c2hcmd_enqueue(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rtl_priv *rtlpriv = rtl_priv(hw); unsigned long flags; - struct rtl_c2hcmd *c2hcmd; - - c2hcmd = kmalloc(sizeof(*c2hcmd), - in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); - - if (!c2hcmd) - goto label_err; - - c2hcmd->val = kmalloc(len, - in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); - - if (!c2hcmd->val) - goto label_err2; - - /* fill data */ - c2hcmd->tag = tag; - c2hcmd->len = len; - memcpy(c2hcmd->val, val, len); /* enqueue */ spin_lock_irqsave(&rtlpriv->locks.c2hcmd_lock, flags); - list_add_tail(&c2hcmd->list, &rtlpriv->c2hcmd_list); + __skb_queue_tail(&rtlpriv->c2hcmd_queue, skb); spin_unlock_irqrestore(&rtlpriv->locks.c2hcmd_lock, flags); /* wake up wq */ queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.c2hcmd_wq, 0); - - return; - -label_err2: - kfree(c2hcmd); - -label_err: - RT_TRACE(rtlpriv, COMP_CMD, DBG_WARNING, - "C2H cmd enqueue fail.\n"); } EXPORT_SYMBOL(rtl_c2hcmd_enqueue); -void rtl_c2h_content_parsing(struct ieee80211_hw *hw, u8 cmd_id, - u8 cmd_len, u8 *cmd_buf) +static void rtl_c2h_content_parsing(struct ieee80211_hw *hw, + struct sk_buff *skb) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal_ops *hal_ops = rtlpriv->cfg->ops; const struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; + u8 cmd_id, cmd_seq, cmd_len; + u8 *cmd_buf = NULL; + + cmd_id = skb->data[0]; + cmd_seq = skb->data[1]; + cmd_len = skb->len - 2; + cmd_buf = skb->data + 2; switch (cmd_id) { case C2H_DBG: @@ -2347,67 +2327,35 @@ void rtl_c2h_content_parsing(struct ieee80211_hw *hw, u8 cmd_id, } } -void rtl_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - u8 c2h_cmd_id = 0, c2h_cmd_seq = 0, c2h_cmd_len = 0; - u8 *tmp_buf = NULL; - - c2h_cmd_id = buffer[0]; - c2h_cmd_seq = buffer[1]; - c2h_cmd_len = len - 2; - tmp_buf = buffer + 2; - - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, - "[C2H packet], c2hCmdId=0x%x, c2hCmdSeq=0x%x, c2hCmdLen=%d\n", - c2h_cmd_id, c2h_cmd_seq, c2h_cmd_len); - - RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_TRACE, - "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len); - - switch (c2h_cmd_id) { - case C2H_BT_INFO: - case C2H_BT_MP: - rtl_c2hcmd_enqueue(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf); - break; - default: - rtl_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf); - break; - } -} -EXPORT_SYMBOL_GPL(rtl_c2h_packet_handler); - void rtl_c2hcmd_launcher(struct ieee80211_hw *hw, int exec) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct sk_buff *skb; unsigned long flags; - struct rtl_c2hcmd *c2hcmd; int i; for (i = 0; i < 200; i++) { /* dequeue a task */ spin_lock_irqsave(&rtlpriv->locks.c2hcmd_lock, flags); - c2hcmd = list_first_entry_or_null(&rtlpriv->c2hcmd_list, - struct rtl_c2hcmd, list); - - if (c2hcmd) - list_del(&c2hcmd->list); + skb = __skb_dequeue(&rtlpriv->c2hcmd_queue); spin_unlock_irqrestore(&rtlpriv->locks.c2hcmd_lock, flags); /* do it */ - if (!c2hcmd) + if (!skb) break; + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, "C2H rx_desc_shift=%d\n", + *((u8 *)skb->cb)); + RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_DMESG, + "C2H data: ", skb->data, skb->len); + if (exec) - rtl_c2h_content_parsing(hw, c2hcmd->tag, - c2hcmd->len, c2hcmd->val); + rtl_c2h_content_parsing(hw, skb); /* free */ - kfree(c2hcmd->val); - - kfree(c2hcmd); + dev_kfree_skb_any(skb); } } diff --git a/drivers/net/wireless/realtek/rtlwifi/base.h b/drivers/net/wireless/realtek/rtlwifi/base.h index 3bf174e5b07e..912f205779c3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.h +++ b/drivers/net/wireless/realtek/rtlwifi/base.h @@ -161,10 +161,7 @@ void rtl_watchdog_wq_callback(void *data); void rtl_fwevt_wq_callback(void *data); void rtl_c2hcmd_wq_callback(void *data); void rtl_c2hcmd_launcher(struct ieee80211_hw *hw, int exec); -void rtl_c2hcmd_enqueue(struct ieee80211_hw *hw, u8 tag, u8 len, u8 *val); -void rtl_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id, - u8 c2h_cmd_len, u8 *tmp_buf); -void rtl_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len); +void rtl_c2hcmd_enqueue(struct ieee80211_hw *hw, struct sk_buff *skb); u8 rtl_mrate_idx_to_arfr_id(struct ieee80211_hw *hw, u8 rate_index, enum wireless_mode wirelessmode); diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index dd51c67c09fa..ae13bcfb3bf0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -831,8 +831,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) } /* handle command packet here */ if (stats.packet_report_type == C2H_PACKET) { - rtl_c2h_packet_handler(hw, skb->data, (u8)skb->len); - dev_kfree_skb_any(skb); + rtl_c2hcmd_enqueue(hw, skb); goto new_trx_end; } diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 930e1ec2280f..9e620b943f8c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2791,7 +2791,7 @@ struct rtl_priv { struct list_head entry_list; /* c2hcmd list for kthread level access */ - struct list_head c2hcmd_list; + struct sk_buff_head c2hcmd_queue; struct rtl_debug dbg; int max_fw_size; -- cgit v1.2.3 From 9644032e307022ecb1a436537cacedb91d569d98 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 18 May 2018 17:30:06 +0800 Subject: rtlwifi: access skb->data to get C2H data by macro The format of C2H data is ID(1 byte) + Length(1 byte) + value, and it is more readable to use macros to access C2H data. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/base.c | 8 ++++---- drivers/net/wireless/realtek/rtlwifi/wifi.h | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index 61f12f86fcd4..a5939ddfa9cb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -2288,10 +2288,10 @@ static void rtl_c2h_content_parsing(struct ieee80211_hw *hw, u8 cmd_id, cmd_seq, cmd_len; u8 *cmd_buf = NULL; - cmd_id = skb->data[0]; - cmd_seq = skb->data[1]; - cmd_len = skb->len - 2; - cmd_buf = skb->data + 2; + cmd_id = GET_C2H_CMD_ID(skb->data); + cmd_seq = GET_C2H_SEQ(skb->data); + cmd_len = skb->len - C2H_DATA_OFFSET; + cmd_buf = GET_C2H_DATA_PTR(skb->data); switch (cmd_id) { case C2H_DBG: diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 9e620b943f8c..0f3b98c5227f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -177,6 +177,11 @@ enum rtl_c2h_evt_v2 { C2H_V2_CCX_RPT = 0x0F, }; +#define GET_C2H_CMD_ID(c2h) ({u8 *__c2h = c2h; __c2h[0]; }) +#define GET_C2H_SEQ(c2h) ({u8 *__c2h = c2h; __c2h[1]; }) +#define C2H_DATA_OFFSET 2 +#define GET_C2H_DATA_PTR(c2h) ({u8 *__c2h = c2h; &__c2h[C2H_DATA_OFFSET]; }) + #define GET_TX_REPORT_SN_V1(c2h) (c2h[6]) #define GET_TX_REPORT_ST_V1(c2h) (c2h[0] & 0xC0) #define GET_TX_REPORT_RETRY_V1(c2h) (c2h[2] & 0x3F) -- cgit v1.2.3 From 0a9f8f0a1ba9688a9ff5f6b83c4cc1eecd2fc9f2 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 18 May 2018 17:30:07 +0800 Subject: rtlwifi: fix btmpinfo timeout while processing C2H_BT_INFO In former patch, I enqueu all C2H commands and processed by a workqueue. In case C2H_BT_INFO will issue a H2C command to set BT reg, and wait for a C2H ack. But it is totally impossible that C2H workqueue waits for a C2H command, so kernel log warn rtlwifi: :<0> btmpinfo wait (req_num=0) timeout Since the C2H ack command C2H_BT_MP can be safely processed in interrupt context, add a fast command path to deal with the command. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/base.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index a5939ddfa9cb..39c817eddd78 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -2262,11 +2262,33 @@ void rtl_fwevt_wq_callback(void *data) rtlpriv->cfg->ops->c2h_command_handle(hw); } +static void rtl_c2h_content_parsing(struct ieee80211_hw *hw, + struct sk_buff *skb); + +static bool rtl_c2h_fast_cmd(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + u8 cmd_id = GET_C2H_CMD_ID(skb->data); + + switch (cmd_id) { + case C2H_BT_MP: + return true; + default: + break; + } + + return false; +} + void rtl_c2hcmd_enqueue(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rtl_priv *rtlpriv = rtl_priv(hw); unsigned long flags; + if (rtl_c2h_fast_cmd(hw, skb)) { + rtl_c2h_content_parsing(hw, skb); + return; + } + /* enqueue */ spin_lock_irqsave(&rtlpriv->locks.c2hcmd_lock, flags); -- cgit v1.2.3 From 88027c8ff0a3f87d5d06d53ee25a41b90d8bccec Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 23 May 2018 18:34:45 +0800 Subject: atmel: Add missing call to pci_disable_device() add pci_disable_device in error handling while init_atmel_card failed. Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- drivers/net/wireless/atmel/atmel_pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/atmel/atmel_pci.c b/drivers/net/wireless/atmel/atmel_pci.c index bcf1f274a251..30df58a41a83 100644 --- a/drivers/net/wireless/atmel/atmel_pci.c +++ b/drivers/net/wireless/atmel/atmel_pci.c @@ -61,8 +61,10 @@ static int atmel_pci_probe(struct pci_dev *pdev, dev = init_atmel_card(pdev->irq, pdev->resource[1].start, ATMEL_FW_TYPE_506, &pdev->dev, NULL, NULL); - if (!dev) + if (!dev) { + pci_disable_device(pdev); return -ENODEV; + } pci_set_drvdata(pdev, dev); return 0; -- cgit v1.2.3 From 6e91d48371e79862ea2c05867aaebe4afe55a865 Mon Sep 17 00:00:00 2001 From: Eyal Reizer Date: Mon, 28 May 2018 11:36:42 +0300 Subject: wlcore: sdio: check for valid platform device data before suspend the wl pointer can be null In case only wlcore_sdio is probed while no WiLink module is successfully probed, as in the case of mounting a wl12xx module while using a device tree file configured with wl18xx related settings. In this case the system was crashing in wl1271_suspend() as platform device data is not set. Make sure wl the pointer is valid before using it. Signed-off-by: Eyal Reizer Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/sdio.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 15d5ac126061..750bea3574ee 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -399,6 +399,11 @@ static int wl1271_suspend(struct device *dev) mmc_pm_flag_t sdio_flags; int ret = 0; + if (!wl) { + dev_err(dev, "no wilink module was probed\n"); + goto out; + } + dev_dbg(dev, "wl1271 suspend. wow_enabled: %d\n", wl->wow_enabled); -- cgit v1.2.3 From a53e8f3edaa0f28458f37dc5654e1912a8a00f26 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 26 May 2018 16:00:19 +0100 Subject: rsi: fix spelling mistake "Uknown" -> "Unknown" Trivial fix to spelling mistake in rsi_dbg message text Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index bfa7569c85bb..2ca7464b7fa3 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -1103,7 +1103,7 @@ static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, break; default: - rsi_dbg(ERR_ZONE, "%s: Uknown AMPDU action\n", __func__); + rsi_dbg(ERR_ZONE, "%s: Unknown AMPDU action\n", __func__); break; } -- cgit v1.2.3 From 618fd1ed17d4cf193d85747c04a8b836b8fc107e Mon Sep 17 00:00:00 2001 From: Ganapathi Bhat Date: Thu, 24 May 2018 16:36:28 +0530 Subject: mwifiex: avoid exporting mwifiex_send_cmd This is a follow-up patch for commit 21c5c83ce833 ("mwifiex: support sysfs initiated device coredump"). Let us avoid exporting mwifiex_send_cmd and instead use a utility function mwifiex_fw_dump_event to achive the work. Signed-off-by: Ganapathi Bhat Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cmdevt.c | 1 - drivers/net/wireless/marvell/mwifiex/main.h | 1 + drivers/net/wireless/marvell/mwifiex/usb.c | 5 ++--- drivers/net/wireless/marvell/mwifiex/util.c | 7 +++++++ 4 files changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 8be1e69657a7..9cfcdf6bec52 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -674,7 +674,6 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no, return ret; } -EXPORT_SYMBOL_GPL(mwifiex_send_cmd); /* * This function queues a command to the command pending queue. diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 8ae74ed78805..69ac0a22c28c 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -1691,6 +1691,7 @@ void mwifiex_drv_info_dump(struct mwifiex_adapter *adapter); void mwifiex_prepare_fw_dump_info(struct mwifiex_adapter *adapter); void mwifiex_upload_device_dump(struct mwifiex_adapter *adapter); void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags); +void mwifiex_fw_dump_event(struct mwifiex_private *priv); void mwifiex_queue_main_work(struct mwifiex_adapter *adapter); int mwifiex_get_wakeup_reason(struct mwifiex_private *priv, u16 action, int cmd_type, diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index 7aa39878ce49..bc475b83bb15 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -658,9 +658,8 @@ static void mwifiex_usb_coredump(struct device *dev) struct usb_interface *intf = to_usb_interface(dev); struct usb_card_rec *card = usb_get_intfdata(intf); - mwifiex_send_cmd(mwifiex_get_priv(card->adapter, MWIFIEX_BSS_ROLE_ANY), - HostCmd_CMD_FW_DUMP_EVENT, HostCmd_ACT_GEN_SET, 0, - NULL, true); + mwifiex_fw_dump_event(mwifiex_get_priv(card->adapter, + MWIFIEX_BSS_ROLE_ANY)); } static struct usb_driver mwifiex_usb_driver = { diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c index 51ccf10f4413..6dd212898117 100644 --- a/drivers/net/wireless/marvell/mwifiex/util.c +++ b/drivers/net/wireless/marvell/mwifiex/util.c @@ -757,3 +757,10 @@ void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags) return skb; } EXPORT_SYMBOL_GPL(mwifiex_alloc_dma_align_buf); + +void mwifiex_fw_dump_event(struct mwifiex_private *priv) +{ + mwifiex_send_cmd(priv, HostCmd_CMD_FW_DUMP_EVENT, HostCmd_ACT_GEN_SET, + 0, NULL, true); +} +EXPORT_SYMBOL_GPL(mwifiex_fw_dump_event); -- cgit v1.2.3 From b817047ae70c0bd67b677b65d0d69d72cd6e9728 Mon Sep 17 00:00:00 2001 From: Ganapathi Bhat Date: Thu, 24 May 2018 19:18:27 +0530 Subject: mwifiex: handle race during mwifiex_usb_disconnect Race condition is observed during rmmod of mwifiex_usb: 1. The rmmod thread will call mwifiex_usb_disconnect(), download SHUTDOWN command and do wait_event_interruptible_timeout(), waiting for response. 2. The main thread will handle the response and will do a wake_up_interruptible(), unblocking rmmod thread. 3. On getting unblocked, rmmod thread will make rx_cmd.urb = NULL in mwifiex_usb_free(). 4. The main thread will try to resubmit rx_cmd.urb in mwifiex_usb_submit_rx_urb(), which is NULL. To fix, wait for main thread to complete before calling mwifiex_usb_free(). Signed-off-by: Ganapathi Bhat Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/usb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index bc475b83bb15..6e3cf9817730 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -644,6 +644,9 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf) MWIFIEX_FUNC_SHUTDOWN); } + if (adapter->workqueue) + flush_workqueue(adapter->workqueue); + mwifiex_usb_free(card); mwifiex_dbg(adapter, FATAL, -- cgit v1.2.3 From ae30bdaa4c2747e96c880d909b48484f41bfd51d Mon Sep 17 00:00:00 2001 From: Ganapathi Bhat Date: Sat, 26 May 2018 02:09:22 +0530 Subject: mwifiex: skip sending GT_REKEY_OFFLOAD_CFG if firmware has no support If firmware does not support embedded supplicant, then it in turn will not support GT rekey offloading. If this is the case, then driver must not advertise WOWLAN flags related to GTK rekey and it must also skip sending the GT_REKEY_OFFLOAD_CFG command. Signed-off-by: Shrenik Shikhare Signed-off-by: Cathy Luo Signed-off-by: Ganapathi Bhat Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 18 +++++++++++++++++- drivers/net/wireless/marvell/mwifiex/fw.h | 1 + drivers/net/wireless/marvell/mwifiex/sta_event.c | 3 +++ 3 files changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 54a2297010d2..d04a59903e82 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -3555,6 +3555,9 @@ static int mwifiex_set_rekey_data(struct wiphy *wiphy, struct net_device *dev, { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + if (!ISSUPP_FIRMWARE_SUPPLICANT(priv->adapter->fw_cap_info)) + return -EOPNOTSUPP; + return mwifiex_send_cmd(priv, HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG, HostCmd_ACT_GEN_SET, 0, data, true); } @@ -4190,6 +4193,16 @@ static const struct wiphy_wowlan_support mwifiex_wowlan_support = { .max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN, .max_nd_match_sets = MWIFIEX_MAX_ND_MATCH_SETS, }; + +static const struct wiphy_wowlan_support mwifiex_wowlan_support_no_gtk = { + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_NET_DETECT, + .n_patterns = MWIFIEX_MEF_MAX_FILTERS, + .pattern_min_len = 1, + .pattern_max_len = MWIFIEX_MAX_PATTERN_LEN, + .max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN, + .max_nd_match_sets = MWIFIEX_MAX_ND_MATCH_SETS, +}; #endif static bool mwifiex_is_valid_alpha2(const char *alpha2) @@ -4308,7 +4321,10 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) WIPHY_FLAG_TDLS_EXTERNAL_SETUP; #ifdef CONFIG_PM - wiphy->wowlan = &mwifiex_wowlan_support; + if (ISSUPP_FIRMWARE_SUPPLICANT(priv->adapter->fw_cap_info)) + wiphy->wowlan = &mwifiex_wowlan_support; + else + wiphy->wowlan = &mwifiex_wowlan_support_no_gtk; #endif wiphy->coalesce = &mwifiex_coalesce_support; diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index c5dc518f768b..b73f99dc5a72 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -249,6 +249,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define ISSUPP_SDIO_SPA_ENABLED(FwCapInfo) (FwCapInfo & BIT(16)) #define ISSUPP_ADHOC_ENABLED(FwCapInfo) (FwCapInfo & BIT(25)) #define ISSUPP_RANDOM_MAC(FwCapInfo) (FwCapInfo & BIT(27)) +#define ISSUPP_FIRMWARE_SUPPLICANT(FwCapInfo) (FwCapInfo & BIT(21)) #define MWIFIEX_DEF_HT_CAP (IEEE80211_HT_CAP_DSSSCCK40 | \ (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) | \ diff --git a/drivers/net/wireless/marvell/mwifiex/sta_event.c b/drivers/net/wireless/marvell/mwifiex/sta_event.c index 93dfb76cd8a6..03a6492662ca 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_event.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_event.c @@ -241,6 +241,9 @@ void mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code, if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); + if (!ISSUPP_FIRMWARE_SUPPLICANT(priv->adapter->fw_cap_info)) + return; + mwifiex_send_cmd(priv, HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG, HostCmd_ACT_GEN_REMOVE, 0, NULL, false); } -- cgit v1.2.3 From 666cc438f36918fb4ed5cab37f0cfaf14586b85e Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 25 May 2018 16:38:54 -0500 Subject: mwifiex: mark expected switch fall-throughs In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 4 ++++ drivers/net/wireless/marvell/mwifiex/scan.c | 1 + 2 files changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index d04a59903e82..4cc58d79d837 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -1158,6 +1158,7 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, case NL80211_IFTYPE_UNSPECIFIED: mwifiex_dbg(priv->adapter, INFO, "%s: kept type as IBSS\n", dev->name); + /* fall through */ case NL80211_IFTYPE_ADHOC: /* This shouldn't happen */ return 0; default: @@ -1188,6 +1189,7 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, case NL80211_IFTYPE_UNSPECIFIED: mwifiex_dbg(priv->adapter, INFO, "%s: kept type as STA\n", dev->name); + /* fall through */ case NL80211_IFTYPE_STATION: /* This shouldn't happen */ return 0; default: @@ -1210,6 +1212,7 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, case NL80211_IFTYPE_UNSPECIFIED: mwifiex_dbg(priv->adapter, INFO, "%s: kept type as AP\n", dev->name); + /* fall through */ case NL80211_IFTYPE_AP: /* This shouldn't happen */ return 0; default: @@ -1249,6 +1252,7 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, case NL80211_IFTYPE_UNSPECIFIED: mwifiex_dbg(priv->adapter, INFO, "%s: kept type as P2P\n", dev->name); + /* fall through */ case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: return 0; diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index d7ce7f75ae38..19df92b6668d 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -1308,6 +1308,7 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, case WLAN_EID_CHANNEL_SWITCH: bss_entry->chan_sw_ie_present = true; + /* fall through */ case WLAN_EID_PWR_CAPABILITY: case WLAN_EID_TPC_REPORT: case WLAN_EID_QUIET: -- cgit v1.2.3 From 788f4e4cf063173c25e3f3ad81e7cee923686ab1 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 29 May 2018 09:42:08 +0800 Subject: mwifiex: increase log level for internal scan fail result Signed-off-by: Xinming Hu Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 4cc58d79d837..a67e2d66ac9d 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -2262,7 +2262,7 @@ done: if (!bss) { if (is_scanning_required) { - mwifiex_dbg(priv->adapter, WARN, + mwifiex_dbg(priv->adapter, MSG, "assoc: requested bss not found in scan results\n"); break; } -- cgit v1.2.3 From db69f4e05bd5c83ea66b156fddd7cfc562092bbc Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 29 May 2018 09:42:09 +0800 Subject: mwifiex: reserve passive scan time for radar channel Active scan is not allowed on radar channel, instead using passvie scan with more time. Signed-off-by: Xinming Hu Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/scan.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index 19df92b6668d..895b806cdb03 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -482,7 +482,8 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv, scan_chan_list[chan_idx].max_scan_time = cpu_to_le16((u16) user_scan_in-> chan_list[0].scan_time); - else if (ch->flags & IEEE80211_CHAN_NO_IR) + else if ((ch->flags & IEEE80211_CHAN_NO_IR) || + (ch->flags & IEEE80211_CHAN_RADAR)) scan_chan_list[chan_idx].max_scan_time = cpu_to_le16(adapter->passive_scan_time); else @@ -502,10 +503,12 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv, scan_chan_list[chan_idx].chan_scan_mode_bitmap |= MWIFIEX_DISABLE_CHAN_FILT; - if (filtered_scan) { + if (filtered_scan && + !((ch->flags & IEEE80211_CHAN_NO_IR) || + (ch->flags & IEEE80211_CHAN_RADAR))) scan_chan_list[chan_idx].max_scan_time = cpu_to_le16(adapter->specific_scan_time); - } + chan_idx++; } -- cgit v1.2.3 From 06895b1627fe36f0bea49d4c9fd0e27f0f7498b1 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 24 May 2018 13:54:50 -0500 Subject: rtlwifi: remove duplicate code Remove and refactor some code in order to avoid having identical code for different branches. Notice that the logic has been there since 2014. Addresses-Coverity-ID: 1426199 ("Identical code for different branches") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b2ant.c | 23 ++++------------------ 1 file changed, 4 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 279fe01bb55e..df3facc8e5a4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -2876,25 +2876,10 @@ static void btc8723b2ant_action_hid(struct btc_coexist *btcoexist) btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); /* sw mechanism */ - if (BTC_WIFI_BW_HT40 == wifi_bw) { - if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || - (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - btc8723b2ant_sw_mechanism(btcoexist, true, true, - false, false); - } else { - btc8723b2ant_sw_mechanism(btcoexist, true, true, - false, false); - } - } else { - if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || - (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - btc8723b2ant_sw_mechanism(btcoexist, false, true, - false, false); - } else { - btc8723b2ant_sw_mechanism(btcoexist, false, true, - false, false); - } - } + if (wifi_bw == BTC_WIFI_BW_HT40) + btc8723b2ant_sw_mechanism(btcoexist, true, true, false, false); + else + btc8723b2ant_sw_mechanism(btcoexist, false, true, false, false); } /* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ -- cgit v1.2.3 From 0513c083d1f460c30eae67867c0add557f7ca1b9 Mon Sep 17 00:00:00 2001 From: Golan Ben Ami Date: Mon, 28 May 2018 12:15:44 +0300 Subject: iwlwifi: add csr configuration for 6300 devices Recently we have switched the csr addresses and values configuration from a single configuration to all devices to a per-device configuration. Doing that, the configuration for 6300 devices wasn't set. This missing definition introduced a kernel panic once trying to access the csr's. Add the missing 6300 csr configuration. While at it, add a checker that the csr values were indeed configured, and bail out more gracefully if not. Fixes: a8cbb46f831d ("iwlwifi: allow different csr flags for different device families") Signed-off-by: Golan Ben Ami Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/cfg/6000.c | 1 + drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/6000.c b/drivers/net/wireless/intel/iwlwifi/cfg/6000.c index 51cec0bb75fc..dbcec7ce7863 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/6000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/6000.c @@ -373,6 +373,7 @@ const struct iwl_cfg iwl6000_3agn_cfg = { .eeprom_params = &iwl6000_eeprom_params, .ht_params = &iwl6000_ht_params, .led_mode = IWL_LED_BLINK, + .csr = &iwl_csr_v1, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 959de2f8bb28..38234bda9017 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -836,6 +836,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct iwl_trans *iwl_trans; int ret; + if (WARN_ONCE(!cfg->csr, "CSR addresses aren't configured\n")) + return -EINVAL; + iwl_trans = iwl_trans_pcie_alloc(pdev, ent, cfg); if (IS_ERR(iwl_trans)) return PTR_ERR(iwl_trans); -- cgit v1.2.3 From c1c9a3c9663b2e15176758626278792862f1ed32 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 26 May 2018 19:15:48 +0800 Subject: net: remove unnecessary genlmsg_cancel() calls the message be freed immediately, no need to trim it back to the previous size. Inspired by commit 7a9b3ec1e19f ("nl80211: remove unnecessary genlmsg_cancel() calls") Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/wireless/mac80211_hwsim.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 89fc22520d40..9825bfd42abc 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2514,7 +2514,6 @@ static void hwsim_mcast_new_radio(int id, struct genl_info *info, return; out_err: - genlmsg_cancel(mcast_skb, data); nlmsg_free(mcast_skb); } -- cgit v1.2.3 From fabdcc2ecd58500689f4fb73dc77283623d9ab7e Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 26 Mar 2018 13:07:03 +0300 Subject: iwlwifi: mvm: drop UNKNOWN security type frames In some cases we may get from FW errored frames with UNKNOWN security type. This may happen in unsecured aggregation flow, where the first packet had a CRC error in the WEP bit, which was followed by a failure to decrypt and was dropped. The next frames in the aggregation "inherit" the bad metadata of the first packet. Make sure to drop such frames since RADA and other offloads will not operate correctly which may have unexpected results. In case of AP it also causes to TX AMSDU frames to the peers, resulting with assert 0x104B. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/rx.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index e7565f37ece9..7e570c4a9df0 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -295,6 +295,7 @@ enum iwl_rx_mpdu_status { IWL_RX_MPDU_STATUS_MIC_OK = BIT(6), IWL_RX_MPDU_RES_STATUS_TTAK_OK = BIT(7), IWL_RX_MPDU_STATUS_SEC_MASK = 0x7 << 8, + IWL_RX_MPDU_STATUS_SEC_UNKNOWN = IWL_RX_MPDU_STATUS_SEC_MASK, IWL_RX_MPDU_STATUS_SEC_NONE = 0x0 << 8, IWL_RX_MPDU_STATUS_SEC_WEP = 0x1 << 8, IWL_RX_MPDU_STATUS_SEC_CCM = 0x2 << 8, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index bb63e75a9b7f..2b1f0dc73c25 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -227,12 +227,24 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, } static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, - struct ieee80211_rx_status *stats, - struct iwl_rx_mpdu_desc *desc, u32 pkt_flags, - int queue, u8 *crypt_len) + struct ieee80211_rx_status *stats, u16 phy_info, + struct iwl_rx_mpdu_desc *desc, + u32 pkt_flags, int queue, u8 *crypt_len) { u16 status = le16_to_cpu(desc->status); + /* + * Drop UNKNOWN frames in aggregation, unless in monitor mode + * (where we don't have the keys). + * We limit this to aggregation because in TKIP this is a valid + * scenario, since we may not have the (correct) TTAK (phase 1 + * key) in the firmware. + */ + if (phy_info & IWL_RX_MPDU_PHY_AMPDU && + (status & IWL_RX_MPDU_STATUS_SEC_MASK) == + IWL_RX_MPDU_STATUS_SEC_UNKNOWN && !mvm->monitor_on) + return -1; + if (!ieee80211_has_protected(hdr->frame_control) || (status & IWL_RX_MPDU_STATUS_SEC_MASK) == IWL_RX_MPDU_STATUS_SEC_NONE) @@ -870,7 +882,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, rx_status = IEEE80211_SKB_RXCB(skb); - if (iwl_mvm_rx_crypto(mvm, hdr, rx_status, desc, + if (iwl_mvm_rx_crypto(mvm, hdr, rx_status, phy_info, desc, le32_to_cpu(pkt->len_n_flags), queue, &crypt_len)) { kfree_skb(skb); -- cgit v1.2.3 From 15c4e33030d172ac0d2a03ebbae4c3687a80ac7d Mon Sep 17 00:00:00 2001 From: Aviya Erenfeld Date: Mon, 26 Mar 2018 14:35:32 +0300 Subject: iwlmvm: tdls: Check TDLS channel switch support Some versions of the FW don't support channel switch in TDLS. Add a condition that checks it. Fixes: 307e47235a10 ("iwlwifi: mvm: configure TDLS peers to FW") Signed-off-by: Aviya Erenfeld Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tdls.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c index 3d97436bbdf5..67f360c0d17e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c @@ -7,6 +7,7 @@ * * Copyright(c) 2014 Intel Mobile Communications GmbH * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -18,9 +19,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA + * along with this program. * * The full GNU General Public License is included in this distribution * in the file called COPYING. @@ -33,6 +32,7 @@ * * Copyright(c) 2014 Intel Mobile Communications GmbH * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(C) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -188,8 +188,14 @@ void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (tdls_sta_cnt == 1 && sta_added) iwl_mvm_power_update_mac(mvm); - /* configure the FW with TDLS peer info */ - iwl_mvm_tdls_config(mvm, vif); + /* Configure the FW with TDLS peer info only if TDLS channel switch + * capability is set. + * TDLS config data is used currently only in TDLS channel switch code. + * Supposed to serve also TDLS buffer station which is not implemneted + * yet in FW*/ + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH)) + iwl_mvm_tdls_config(mvm, vif); /* when the last peer leaves, send a power update last */ if (tdls_sta_cnt == 0 && !sta_added) -- cgit v1.2.3 From 0eac9abace1629c20420d9122d6edc80d292b0ec Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 8 Apr 2018 12:33:31 +0300 Subject: iwlwifi: mvm: fix TSO with highly fragmented SKBs Our hardware has a limited amount of buffer descriptors for each Tx packet. Because of that, there is a short piece of code that makes sure that that we don't push too many subframes in an A-MSDU because of subframes needs 2 buffer descriptors. This code also takes into account the number of fragment of the skb since we also need a buffer descriptor for each fragment in the skb. This piece of code though didn't check that the resulting number of subframes wasn't 0. A user reported that using NFS client, he could get skbs that are so fragmented that the code mentioned above returned 0 for the number of subframes making skb_gso_segment fail and subconsequently iwlwifi would WARN. Fix this by make sure that num_subframes is at least 1. This fixes: https://bugzilla.kernel.org/show_bug.cgi?id=199209 Fixes: a6d5e32f247c ("iwlwifi: mvm: send large SKBs to the transport") Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index df4c60496f72..0b7f98d00298 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -843,8 +843,6 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, * N * subf_len + (N - 1) * pad. */ num_subframes = (max_amsdu_len + pad) / (subf_len + pad); - if (num_subframes > 1) - *ieee80211_get_qos_ctl(hdr) |= IEEE80211_QOS_CTL_A_MSDU_PRESENT; tcp_payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) - tcp_hdrlen(skb) + skb->data_len; @@ -855,10 +853,12 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, * 1 more for each fragment * 1 more for the potential data in the header */ - num_subframes = - min_t(unsigned int, num_subframes, - (mvm->trans->max_skb_frags - 1 - - skb_shinfo(skb)->nr_frags) / 2); + if ((num_subframes * 2 + skb_shinfo(skb)->nr_frags + 1) > + mvm->trans->max_skb_frags) + num_subframes = 1; + + if (num_subframes > 1) + *ieee80211_get_qos_ctl(hdr) |= IEEE80211_QOS_CTL_A_MSDU_PRESENT; /* This skb fits in one single A-MSDU */ if (num_subframes * mss >= tcp_payload_len) { -- cgit v1.2.3 From 0f22e40053bd5378ad1e3250e65c574fd61c0cd6 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Thu, 22 Mar 2018 14:14:45 +0200 Subject: iwlwifi: pcie: fix race in Rx buffer allocator Make sure the rx_allocator worker is canceled before running the rx_init routine. rx_init frees and re-allocates all rxb's pages. The rx_allocator worker also allocates pages for the used rxb's. Running rx_init and rx_allocator simultaniously causes a kernel panic. Fix that by canceling the work in rx_init. Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index f772d70a65e4..d15f5ba2dc77 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -902,6 +902,8 @@ static int _iwl_pcie_rx_init(struct iwl_trans *trans) } def_rxq = trans_pcie->rxq; + cancel_work_sync(&rba->rx_alloc); + spin_lock(&rba->lock); atomic_set(&rba->req_pending, 0); atomic_set(&rba->req_ready, 0); -- cgit v1.2.3 From b38c395f16562423f438065ad8d88c20ad92cab3 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 11 Apr 2018 14:05:33 +0100 Subject: iwlwifi: mvm: remove division by size of sizeof(struct ieee80211_wmm_rule) The subtraction of two struct ieee80211_wmm_rule pointers leaves a result that is automatically scaled down by the size of the size of pointed-to type, hence the division by sizeof(struct ieee80211_wmm_rule) is bogus and should be removed. Detected by CoverityScan, CID#1467777 ("Extra sizeof expression") Fixes: 77e30e10ee28 ("iwlwifi: mvm: query regdb for wmm rule if needed") Signed-off-by: Colin Ian King Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 0f9d56420c42..b815ba38dbdb 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -1025,8 +1025,7 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, continue; copy_rd->reg_rules[i].wmm_rule = d_wmm + - (regd->reg_rules[i].wmm_rule - s_wmm) / - sizeof(struct ieee80211_wmm_rule); + (regd->reg_rules[i].wmm_rule - s_wmm); } out: -- cgit v1.2.3 From d94c5a820d107fdde711ec72c16848876027713d Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Tue, 24 Apr 2018 06:26:41 +0300 Subject: iwlwifi: mvm: open BA session only when sta is authorized Currently, a BA session is opened when the tx traffic exceeds 10 frames per second. As a result of inter-op problems with some APs, add a condition to open BA session only when station is already authorized. Fixes: 482e48440a0e ("iwlwifi: mvm: change open and close criteria of a BA session") Signed-off-by: Gregory Greenman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 8 ++--- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 38 +++++++++++------------ drivers/net/wireless/intel/iwlwifi/mvm/rs.h | 7 ++--- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 10 +++--- 5 files changed, 29 insertions(+), 36 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 5f0701c992a4..f3cab26f81b5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2685,7 +2685,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); /* track whether or not the station is associated */ - mvm_sta->associated = new_state >= IEEE80211_STA_ASSOC; + mvm_sta->sta_state = new_state; if (old_state == IEEE80211_STA_NOTEXIST && new_state == IEEE80211_STA_NONE) { @@ -2737,8 +2737,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); } - iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band, - true); + iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band); ret = iwl_mvm_update_sta(mvm, vif, sta); } else if (old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTHORIZED) { @@ -2754,8 +2753,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, /* enable beacon filtering */ WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); - iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band, - false); + iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band); ret = 0; } else if (old_state == IEEE80211_STA_AUTHORIZED && diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index af7bc3b7b0c3..642da10b0b7f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -3,6 +3,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -13,10 +14,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * @@ -651,9 +648,10 @@ static void rs_tl_turn_on_agg(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, } tid_data = &mvmsta->tid_data[tid]; - if ((tid_data->state == IWL_AGG_OFF) && + if (mvmsta->sta_state >= IEEE80211_STA_AUTHORIZED && + tid_data->state == IWL_AGG_OFF && (lq_sta->tx_agg_tid_en & BIT(tid)) && - (tid_data->tx_count_last >= IWL_MVM_RS_AGG_START_THRESHOLD)) { + tid_data->tx_count_last >= IWL_MVM_RS_AGG_START_THRESHOLD) { IWL_DEBUG_RATE(mvm, "try to aggregate tid %d\n", tid); if (rs_tl_turn_on_agg_for_tid(mvm, lq_sta, tid, sta) == 0) tid_data->state = IWL_AGG_QUEUED; @@ -1257,7 +1255,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, (unsigned long)(lq_sta->last_tx + (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) { IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); - iwl_mvm_rs_rate_init(mvm, sta, info->band, false); + iwl_mvm_rs_rate_init(mvm, sta, info->band); return; } lq_sta->last_tx = jiffies; @@ -2690,9 +2688,9 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta, enum nl80211_band band, - struct rs_rate *rate, - bool init) + struct rs_rate *rate) { + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); int i, nentries; unsigned long active_rate; s8 best_rssi = S8_MIN; @@ -2754,7 +2752,8 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm, * bandwidth rate, and after authorization, when the phy context * is already up-to-date, re-init rs with the correct bw. */ - u32 bw = init ? RATE_MCS_CHAN_WIDTH_20 : rs_bw_from_sta_bw(sta); + u32 bw = mvmsta->sta_state < IEEE80211_STA_AUTHORIZED ? + RATE_MCS_CHAN_WIDTH_20 : rs_bw_from_sta_bw(sta); switch (bw) { case RATE_MCS_CHAN_WIDTH_40: @@ -2839,9 +2838,9 @@ void rs_update_last_rssi(struct iwl_mvm *mvm, static void rs_initialize_lq(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta, - enum nl80211_band band, - bool init) + enum nl80211_band band) { + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_scale_tbl_info *tbl; struct rs_rate *rate; u8 active_tbl = 0; @@ -2857,7 +2856,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, tbl = &(lq_sta->lq_info[active_tbl]); rate = &tbl->rate; - rs_get_initial_rate(mvm, sta, lq_sta, band, rate, init); + rs_get_initial_rate(mvm, sta, lq_sta, band, rate); rs_init_optimal_rate(mvm, sta, lq_sta); WARN_ONCE(rate->ant != ANT_A && rate->ant != ANT_B, @@ -2870,7 +2869,8 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, rs_set_expected_tpt_table(lq_sta, tbl); rs_fill_lq_cmd(mvm, sta, lq_sta, rate); /* TODO restore station should remember the lq cmd */ - iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, init); + iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, + mvmsta->sta_state < IEEE80211_STA_AUTHORIZED); } static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta, @@ -3123,7 +3123,7 @@ void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg) * Called after adding a new station to initialize rate scaling */ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - enum nl80211_band band, bool init) + enum nl80211_band band) { int i, j; struct ieee80211_hw *hw = mvm->hw; @@ -3203,7 +3203,7 @@ static void rs_drv_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, #ifdef CONFIG_IWLWIFI_DEBUGFS iwl_mvm_reset_frame_stats(mvm); #endif - rs_initialize_lq(mvm, sta, lq_sta, band, init); + rs_initialize_lq(mvm, sta, lq_sta, band); } static void rs_drv_rate_update(void *mvm_r, @@ -3223,7 +3223,7 @@ static void rs_drv_rate_update(void *mvm_r, for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) ieee80211_stop_tx_ba_session(sta, tid); - iwl_mvm_rs_rate_init(mvm, sta, sband->band, false); + iwl_mvm_rs_rate_init(mvm, sta, sband->band); } #ifdef CONFIG_MAC80211_DEBUGFS @@ -4069,12 +4069,12 @@ static const struct rate_control_ops rs_mvm_ops_drv = { }; void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - enum nl80211_band band, bool init) + enum nl80211_band band) { if (iwl_mvm_has_tlc_offload(mvm)) rs_fw_rate_init(mvm, sta, band); else - rs_drv_rate_init(mvm, sta, band, init); + rs_drv_rate_init(mvm, sta, band); } int iwl_mvm_rate_control_register(void) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h index 5e89141656c0..cffb8c852934 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h @@ -3,6 +3,7 @@ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Mobile Communications GmbH * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -13,10 +14,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * @@ -410,7 +407,7 @@ struct iwl_lq_sta { /* Initialize station's rate scaling information after adding station */ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, - enum nl80211_band band, bool init); + enum nl80211_band band); /* Notify RS about Tx status */ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 4ddd2c427b83..9263b9aa8b72 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -216,7 +216,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, cpu_to_le32(agg_size << STA_FLG_MAX_AGG_SIZE_SHIFT); add_sta_cmd.station_flags |= cpu_to_le32(mpdu_dens << STA_FLG_AGG_MPDU_DENS_SHIFT); - if (mvm_sta->associated) + if (mvm_sta->sta_state >= IEEE80211_STA_ASSOC) add_sta_cmd.assoc_id = cpu_to_le16(sta->aid); if (sta->wme) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 60502c81dfce..1c43ea8dd8cc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -18,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * @@ -35,6 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -376,6 +373,7 @@ struct iwl_mvm_rxq_dup_data { * tid. * @max_agg_bufsize: the maximal size of the AGG buffer for this station * @sta_type: station type + * @sta_state: station state according to enum %ieee80211_sta_state * @bt_reduced_txpower: is reduced tx power enabled for this station * @next_status_eosp: the next reclaimed packet is a PS-Poll response and * we need to signal the EOSP @@ -416,6 +414,7 @@ struct iwl_mvm_sta { u16 tid_disable_agg; u8 max_agg_bufsize; enum iwl_sta_type sta_type; + enum ieee80211_sta_state sta_state; bool bt_reduced_txpower; bool next_status_eosp; spinlock_t lock; @@ -441,7 +440,6 @@ struct iwl_mvm_sta { u16 amsdu_enabled; u16 max_amsdu_len; bool sleeping; - bool associated; u8 agg_tids; u8 sleep_tx_count; u8 avg_energy; -- cgit v1.2.3 From 5dd9f6c703e8161bf69fb9d004528bfb639548ce Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 17 May 2018 10:44:20 +0300 Subject: iwlwifi: mvm: honor the max_amsdu_subframes limit A peer can limit the number of subframes it can handle in a single A-MSDU. Honor this limit. Note that the smallest limit is 8, and we are very unlikely to reach that limit. So this isn't really a big deal. Fixes: a6d5e32f247c ("iwlwifi: mvm: send large SKBs to the transport") Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 0b7f98d00298..cf2591f2ac23 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -844,6 +844,10 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, */ num_subframes = (max_amsdu_len + pad) / (subf_len + pad); + if (sta->max_amsdu_subframes && + num_subframes > sta->max_amsdu_subframes) + num_subframes = sta->max_amsdu_subframes; + tcp_payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) - tcp_hdrlen(skb) + skb->data_len; -- cgit v1.2.3 From 42116705a7b17ddc321b6e9999b8df2dc967c357 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 22 May 2018 15:08:32 +0200 Subject: iwlwifi: mvm: fix race in queue notification wait Initially in this code, the race didn't matter since it didn't do anything. Latest with the commit I marked this as fixing it started to matter as something got done here that needed other data that got freed as soon as the queue notification wait was returning. In the scenario we saw, apparently the IWL_MVM_RXQ_NOTIF_DEL_BA event was sent to all queues, but processing the last event we returned from iwl_mvm_sync_rx_queues_internal() and then from iwl_mvm_free_reorder() and continued some processing before wl_mvm_del_ba() was even invoked on the other CPU. Thus, when the latter finally ran, it found that mvm->baid_map[baid] was no longer valid. Correct the race by moving the counter decrement and wake_up() to be done only after all the per-event processing completed. Note that in the commit I marked as being fixed the wake_up() didn't exist yet (and the code was otherwise problematic) but this particular problem already existed in a way. Fixes: b915c10174fb ("iwlwifi: mvm: add reorder buffer per queue") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 2b1f0dc73c25..129c4c09648d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -590,14 +590,10 @@ void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, notif = (void *)pkt->data; internal_notif = (void *)notif->payload; - if (internal_notif->sync) { - if (mvm->queue_sync_cookie != internal_notif->cookie) { - WARN_ONCE(1, - "Received expired RX queue sync message\n"); - return; - } - if (!atomic_dec_return(&mvm->queue_sync_counter)) - wake_up(&mvm->rx_sync_waitq); + if (internal_notif->sync && + mvm->queue_sync_cookie != internal_notif->cookie) { + WARN_ONCE(1, "Received expired RX queue sync message\n"); + return; } switch (internal_notif->type) { @@ -609,6 +605,10 @@ void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, default: WARN_ONCE(1, "Invalid identifier %d", internal_notif->type); } + + if (internal_notif->sync && + !atomic_dec_return(&mvm->queue_sync_counter)) + wake_up(&mvm->rx_sync_waitq); } /* -- cgit v1.2.3 From 506247825c5e877741f33a2c657d351e5c7943ba Mon Sep 17 00:00:00 2001 From: Erel Geron Date: Mon, 28 May 2018 17:09:30 +0300 Subject: iwlwifi: fix non_shared_ant for 9000 devices The non-shared antenna was wrong for 9000 device series. Fix it to ANT_B for correct antenna preference by coex in MVM driver. Fixes: 89374fe60bfb ("iwlwifi: Add new PCI IDs for 9260 and 5165 series") Signed-off-by: Erel Geron Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/cfg/9000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index 9706624911f8..e20c30b29c03 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -137,7 +137,7 @@ static const struct iwl_tt_params iwl9000_tt_params = { .base_params = &iwl9000_base_params, \ .led_mode = IWL_LED_RF_STATE, \ .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_9000, \ - .non_shared_ant = ANT_A, \ + .non_shared_ant = ANT_B, \ .dccm_offset = IWL9000_DCCM_OFFSET, \ .dccm_len = IWL9000_DCCM_LEN, \ .dccm2_offset = IWL9000_DCCM2_OFFSET, \ -- cgit v1.2.3 From d602de8e7e7fc25fb3a2112ce4285962f15aa549 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 28 May 2018 19:51:57 -0700 Subject: drivers/net: Fix various unnecessary characters after logging newlines Remove and coalesce formats when there is an unnecessary character after a logging newline. These extra characters cause logging defects. Miscellanea: o Coalesce formats Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 2 +- drivers/net/wireless/intel/ipw2x00/ipw2200.c | 3 +-- drivers/net/wireless/intersil/prism54/islpci_eth.c | 6 +++--- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c | 4 ++-- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c | 4 ++-- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 4 ++-- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c | 2 +- 7 files changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index f5b405c98047..b6122aad639e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -1264,7 +1264,7 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason) brcmf_dbg(TRACE, "Enter\n"); if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) { - brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n "); + brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n"); err = brcmf_fil_cmd_data_set(vif->ifp, BRCMF_C_DISASSOC, NULL, 0); if (err) { diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index ba3fb1d2ddb4..f26beeb6c5ff 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -7557,8 +7557,7 @@ static int ipw_associate(void *data) } if (priv->status & STATUS_DISASSOCIATING) { - IPW_DEBUG_ASSOC("Not attempting association (in " - "disassociating)\n "); + IPW_DEBUG_ASSOC("Not attempting association (in disassociating)\n"); schedule_work(&priv->associate); return 0; } diff --git a/drivers/net/wireless/intersil/prism54/islpci_eth.c b/drivers/net/wireless/intersil/prism54/islpci_eth.c index 9b0ded733294..b277113b33d3 100644 --- a/drivers/net/wireless/intersil/prism54/islpci_eth.c +++ b/drivers/net/wireless/intersil/prism54/islpci_eth.c @@ -57,7 +57,7 @@ islpci_eth_cleanup_transmit(islpci_private *priv, #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, - "cleanup skb %p skb->data %p skb->len %u truesize %u\n ", + "cleanup skb %p skb->data %p skb->len %u truesize %u\n", skb, skb->data, skb->len, skb->truesize); #endif @@ -328,7 +328,7 @@ islpci_eth_receive(islpci_private *priv) #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, - "frq->addr %x skb->data %p skb->len %u offset %u truesize %u\n ", + "frq->addr %x skb->data %p skb->len %u offset %u truesize %u\n", control_block->rx_data_low[priv->free_data_rx].address, skb->data, skb->len, offset, skb->truesize); #endif @@ -436,7 +436,7 @@ islpci_eth_receive(islpci_private *priv) #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_TRACING, - "new alloc skb %p skb->data %p skb->len %u index %u truesize %u\n ", + "new alloc skb %p skb->data %p skb->len %u index %u truesize %u\n", skb, skb->data, skb->len, index, skb->truesize); #endif diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c index 38b2ba1ac6f8..380e86f9e00b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c @@ -1267,8 +1267,8 @@ static void rtl8192eu_phy_iq_calibrate(struct rtl8xxxu_priv *priv) reg_ecc = result[candidate][7]; dev_dbg(dev, "%s: candidate is %x\n", __func__, candidate); dev_dbg(dev, - "%s: e94 =%x e9c=%x ea4=%x eac=%x eb4=%x ebc=%x ec4=%x " - "ecc=%x\n ", __func__, reg_e94, reg_e9c, + "%s: e94 =%x e9c=%x ea4=%x eac=%x eb4=%x ebc=%x ec4=%x ecc=%x\n", + __func__, reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc); path_a_ok = true; path_b_ok = true; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c index c4b86a84a721..26b674aca125 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c @@ -1175,8 +1175,8 @@ static void rtl8723bu_phy_iq_calibrate(struct rtl8xxxu_priv *priv) reg_ecc = result[candidate][7]; dev_dbg(dev, "%s: candidate is %x\n", __func__, candidate); dev_dbg(dev, - "%s: e94 =%x e9c=%x ea4=%x eac=%x eb4=%x ebc=%x ec4=%x " - "ecc=%x\n ", __func__, reg_e94, reg_e9c, + "%s: e94 =%x e9c=%x ea4=%x eac=%x eb4=%x ebc=%x ec4=%x ecc=%x\n", + __func__, reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc); path_a_ok = true; path_b_ok = true; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 718a73c623a7..505ab1b055ff 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -3406,8 +3406,8 @@ void rtl8xxxu_gen1_phy_iq_calibrate(struct rtl8xxxu_priv *priv) reg_ecc = result[candidate][7]; dev_dbg(dev, "%s: candidate is %x\n", __func__, candidate); dev_dbg(dev, - "%s: e94 =%x e9c=%x ea4=%x eac=%x eb4=%x ebc=%x ec4=%x " - "ecc=%x\n ", __func__, reg_e94, reg_e9c, + "%s: e94 =%x e9c=%x ea4=%x eac=%x eb4=%x ebc=%x ec4=%x ecc=%x\n", + __func__, reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc); path_a_ok = true; path_b_ok = true; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c index 9111ba7ff0a1..3be8c88971e2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c @@ -2642,7 +2642,7 @@ static void rtl8821ae_dm_edca_choose_traffic_idx( if (cur_tx_bytes > (cur_rx_bytes*4)) { *pb_is_cur_rdl_state = false; RT_TRACE(rtlpriv, COMP_TURBO, DBG_LOUD, - "Uplink Traffic\n "); + "Uplink Traffic\n"); } else { *pb_is_cur_rdl_state = true; RT_TRACE(rtlpriv, COMP_TURBO, DBG_LOUD, -- cgit v1.2.3 From 6d89265d78417174f344c4ec4c13347f178ea0da Mon Sep 17 00:00:00 2001 From: Andrey Shevchenko Date: Tue, 29 May 2018 14:59:57 +0300 Subject: qtnfmac: remove unused function declarations Functions qtnf_cmd_resp_parse and qtnf_cmd_resp_check have been removed. Remove their declarations as well. Signed-off-by: Andrey Shevchenko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/commands.h | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.h b/drivers/net/wireless/quantenna/qtnfmac/commands.h index 69a7d56f7e58..cf9274add26d 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.h +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.h @@ -58,11 +58,6 @@ int qtnf_cmd_send_change_sta(struct qtnf_vif *vif, const u8 *mac, struct station_parameters *params); int qtnf_cmd_send_del_sta(struct qtnf_vif *vif, struct station_del_parameters *params); - -int qtnf_cmd_resp_parse(struct qtnf_bus *bus, struct sk_buff *resp_skb); -int qtnf_cmd_resp_check(const struct qtnf_vif *vif, - const struct sk_buff *resp_skb, u16 cmd_id, - u16 *result, const u8 **payload, size_t *payload_size); int qtnf_cmd_send_scan(struct qtnf_wmac *mac); int qtnf_cmd_send_connect(struct qtnf_vif *vif, struct cfg80211_connect_params *sme); -- cgit v1.2.3 From d62b622ca4099517878db5b7bfb06bc449513365 Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Tue, 29 May 2018 14:59:58 +0300 Subject: qtnfmac: simplify notation Shorten line lengths using a more compact notation to access mac info. Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 25 ++++++++++++----------- 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index 5122dc798064..bf624d975953 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -955,6 +955,7 @@ qtnf_wiphy_setup_if_comb(struct wiphy *wiphy, struct qtnf_mac_info *mac_info) int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) { struct wiphy *wiphy = priv_to_wiphy(mac); + struct qtnf_mac_info *macinfo = &mac->macinfo; int ret; if (!wiphy) { @@ -962,20 +963,20 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) return -EFAULT; } - wiphy->frag_threshold = mac->macinfo.frag_thr; - wiphy->rts_threshold = mac->macinfo.rts_thr; - wiphy->retry_short = mac->macinfo.sretry_limit; - wiphy->retry_long = mac->macinfo.lretry_limit; - wiphy->coverage_class = mac->macinfo.coverage_class; + wiphy->frag_threshold = macinfo->frag_thr; + wiphy->rts_threshold = macinfo->rts_thr; + wiphy->retry_short = macinfo->sretry_limit; + wiphy->retry_long = macinfo->lretry_limit; + wiphy->coverage_class = macinfo->coverage_class; wiphy->max_scan_ssids = QTNF_MAX_SSID_LIST_LENGTH; wiphy->max_scan_ie_len = QTNF_MAX_VSIE_LEN; wiphy->mgmt_stypes = qtnf_mgmt_stypes; wiphy->max_remain_on_channel_duration = 5000; - wiphy->max_acl_mac_addrs = mac->macinfo.max_acl_mac_addrs; + wiphy->max_acl_mac_addrs = macinfo->max_acl_mac_addrs; wiphy->max_num_csa_counters = 2; - ret = qtnf_wiphy_setup_if_comb(wiphy, &mac->macinfo); + ret = qtnf_wiphy_setup_if_comb(wiphy, macinfo); if (ret) goto out; @@ -994,12 +995,12 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2; - wiphy->available_antennas_tx = mac->macinfo.num_tx_chain; - wiphy->available_antennas_rx = mac->macinfo.num_rx_chain; + wiphy->available_antennas_tx = macinfo->num_tx_chain; + wiphy->available_antennas_rx = macinfo->num_rx_chain; - wiphy->max_ap_assoc_sta = mac->macinfo.max_ap_assoc_sta; - wiphy->ht_capa_mod_mask = &mac->macinfo.ht_cap_mod_mask; - wiphy->vht_capa_mod_mask = &mac->macinfo.vht_cap_mod_mask; + wiphy->max_ap_assoc_sta = macinfo->max_ap_assoc_sta; + wiphy->ht_capa_mod_mask = &macinfo->ht_cap_mod_mask; + wiphy->vht_capa_mod_mask = &macinfo->vht_cap_mod_mask; ether_addr_copy(wiphy->perm_addr, mac->macaddr); -- cgit v1.2.3 From 36e8c538b374d07b69961cb1980f8bb39061b822 Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Tue, 29 May 2018 14:59:59 +0300 Subject: qtnfmac: decode error codes from firmware replies Introduce a function that will map an error code reported in reply to a firmware command, into one of standard errno codes. Use additional error codes to improve error reporting for MAC address changes. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/commands.c | 26 +++++++++++++++++++++-- drivers/net/wireless/quantenna/qtnfmac/qlink.h | 2 ++ 2 files changed, 26 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index deca0060eb27..9dc4560be5d8 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -55,6 +55,28 @@ static int qtnf_cmd_check_reply_header(const struct qlink_resp *resp, return 0; } +static int qtnf_cmd_resp_result_decode(enum qlink_cmd_result qcode) +{ + switch (qcode) { + case QLINK_CMD_RESULT_OK: + return 0; + case QLINK_CMD_RESULT_INVALID: + return -EINVAL; + case QLINK_CMD_RESULT_ENOTSUPP: + return -ENOTSUPP; + case QLINK_CMD_RESULT_ENOTFOUND: + return -ENOENT; + case QLINK_CMD_RESULT_EALREADY: + return -EALREADY; + case QLINK_CMD_RESULT_EADDRINUSE: + return -EADDRINUSE; + case QLINK_CMD_RESULT_EADDRNOTAVAIL: + return -EADDRNOTAVAIL; + default: + return -EFAULT; + } +} + static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus, struct sk_buff *cmd_skb, struct sk_buff **response_skb, @@ -810,10 +832,10 @@ static int qtnf_cmd_send_add_change_intf(struct qtnf_vif *vif, if (unlikely(ret)) goto out; - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + ret = qtnf_cmd_resp_result_decode(res_code); + if (ret) { pr_err("VIF%u.%u: CMD %d failed: %u\n", vif->mac->macid, vif->vifid, cmd_type, res_code); - ret = -EFAULT; goto out; } diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h index 9ab27e158023..f85deda703fb 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h @@ -674,6 +674,8 @@ enum qlink_cmd_result { QLINK_CMD_RESULT_ENOTSUPP, QLINK_CMD_RESULT_ENOTFOUND, QLINK_CMD_RESULT_EALREADY, + QLINK_CMD_RESULT_EADDRINUSE, + QLINK_CMD_RESULT_EADDRNOTAVAIL, }; /** -- cgit v1.2.3 From 9a3beeb5b73a55d8d4ada9cf17bec24ad1f31394 Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Tue, 29 May 2018 15:00:00 +0300 Subject: qtnfmac: cleanup wdev structure between its uses Driver uses statically allocated wdev structures for each virtual interface. However wdev structure is not properly cleaned up between its uses. As a result, various bugs appear when userspace tools like hostapd were not gracefully stopped. In particular, this commit fixes the following issue: - start hostapd with more than 2 mBSS - kill hostapd using SIGKILL - start again hostapd with more than 2 mBSS However only two mBSS entities will be started: primary and the last BSS listed in hostapd config. Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 8 +++----- drivers/net/wireless/quantenna/qtnfmac/core.c | 1 - 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index bf624d975953..2089cb095283 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -177,8 +177,6 @@ int qtnf_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) vif->netdev->ieee80211_ptr = NULL; vif->netdev = NULL; vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; - eth_zero_addr(vif->mac_addr); - eth_zero_addr(vif->bssid); return 0; } @@ -216,10 +214,12 @@ static struct wireless_dev *qtnf_add_virtual_intf(struct wiphy *wiphy, } eth_zero_addr(vif->mac_addr); + eth_zero_addr(vif->bssid); vif->bss_priority = QTNF_DEF_BSS_PRIORITY; + vif->sta_state = QTNF_STA_DISCONNECTED; + memset(&vif->wdev, 0, sizeof(vif->wdev)); vif->wdev.wiphy = wiphy; vif->wdev.iftype = type; - vif->sta_state = QTNF_STA_DISCONNECTED; break; default: pr_err("MAC%u: unsupported IF type %d\n", mac->macid, type); @@ -255,8 +255,6 @@ err_mac: qtnf_cmd_send_del_intf(vif); err_cmd: vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; - eth_zero_addr(vif->mac_addr); - eth_zero_addr(vif->bssid); return ERR_PTR(-EFAULT); } diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c index b3bfb4faa918..3ccbc427cf56 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.c +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -394,7 +394,6 @@ int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *vif, dev = alloc_netdev_mqs(sizeof(struct qtnf_vif *), name, name_assign_type, ether_setup, 1, 1); if (!dev) { - memset(&vif->wdev, 0, sizeof(vif->wdev)); vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; return -ENOMEM; } -- cgit v1.2.3 From 9e33e7fb47728cb53dbba09415d95d3ce0ea1ce4 Mon Sep 17 00:00:00 2001 From: Dmitry Lebed Date: Tue, 29 May 2018 15:00:01 +0300 Subject: qtnfmac: improve control path timeout handling Control path will not be operational after firmware failure. Change bus state to QTNF_FW_STATE_EP_DEAD after the control path timeout. Don't wait for timeout if control path is already dead. Signed-off-by: Dmitry Lebed Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/bus.h | 3 ++- drivers/net/wireless/quantenna/qtnfmac/core.c | 2 +- drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c | 15 ++++++++++++--- 3 files changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/quantenna/qtnfmac/bus.h b/drivers/net/wireless/quantenna/qtnfmac/bus.h index 0a1604683bab..323e47cea1e2 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/bus.h +++ b/drivers/net/wireless/quantenna/qtnfmac/bus.h @@ -27,7 +27,8 @@ enum qtnf_fw_state { QTNF_FW_STATE_FW_DNLD_DONE, QTNF_FW_STATE_BOOT_DONE, QTNF_FW_STATE_ACTIVE, - QTNF_FW_STATE_DEAD, + QTNF_FW_STATE_DETACHED, + QTNF_FW_STATE_EP_DEAD, }; struct qtnf_bus; diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c index 3ccbc427cf56..a6a450984f9a 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.c +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -628,7 +628,7 @@ void qtnf_core_detach(struct qtnf_bus *bus) if (bus->fw_state == QTNF_FW_STATE_ACTIVE) qtnf_cmd_send_deinit_fw(bus); - bus->fw_state = QTNF_FW_STATE_DEAD; + bus->fw_state = QTNF_FW_STATE_DETACHED; if (bus->workqueue) { flush_workqueue(bus->workqueue); diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c index 6c1e139bb8f7..3120d49df565 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c @@ -751,8 +751,16 @@ tx_done: static int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb) { struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + int ret; + + ret = qtnf_shm_ipc_send(&priv->shm_ipc_ep_in, skb->data, skb->len); - return qtnf_shm_ipc_send(&priv->shm_ipc_ep_in, skb->data, skb->len); + if (ret == -ETIMEDOUT) { + pr_err("EP firmware is dead\n"); + bus->fw_state = QTNF_FW_STATE_EP_DEAD; + } + + return ret; } static irqreturn_t qtnf_interrupt(int irq, void *data) @@ -1238,7 +1246,7 @@ static void qtnf_fw_work_handler(struct work_struct *work) goto fw_load_exit; fw_load_fail: - bus->fw_state = QTNF_FW_STATE_DEAD; + bus->fw_state = QTNF_FW_STATE_DETACHED; fw_load_exit: complete(&bus->firmware_init_complete); @@ -1408,7 +1416,8 @@ static void qtnf_pcie_remove(struct pci_dev *pdev) wait_for_completion(&bus->firmware_init_complete); - if (bus->fw_state == QTNF_FW_STATE_ACTIVE) + if (bus->fw_state == QTNF_FW_STATE_ACTIVE || + bus->fw_state == QTNF_FW_STATE_EP_DEAD) qtnf_core_detach(bus); priv = get_bus_priv(bus); -- cgit v1.2.3 From b60769e2dff0b168dfe3f03fe0d1950963c3c3da Mon Sep 17 00:00:00 2001 From: Dmitry Lebed Date: Tue, 29 May 2018 15:00:02 +0300 Subject: qtnfmac: fix firmware command error path Free command skb if bus state is not QTNF_FW_STATE_ACTIVE. Signed-off-by: Dmitry Lebed Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/commands.c | 1 + drivers/net/wireless/quantenna/qtnfmac/trans.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index 9dc4560be5d8..e2fc57be1cdd 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -102,6 +102,7 @@ static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus, pr_warn("VIF%u.%u: drop cmd 0x%.4X in fw state %d\n", mac_id, vif_id, le16_to_cpu(cmd->cmd_id), bus->fw_state); + dev_kfree_skb(cmd_skb); return -ENODEV; } diff --git a/drivers/net/wireless/quantenna/qtnfmac/trans.c b/drivers/net/wireless/quantenna/qtnfmac/trans.c index ccddfebc508a..345f34ec9750 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/trans.c +++ b/drivers/net/wireless/quantenna/qtnfmac/trans.c @@ -35,8 +35,10 @@ int qtnf_trans_send_cmd_with_resp(struct qtnf_bus *bus, struct sk_buff *cmd_skb, bool resp_not_handled = true; struct sk_buff *resp_skb = NULL; - if (unlikely(!response_skb)) + if (unlikely(!response_skb)) { + dev_kfree_skb(cmd_skb); return -EFAULT; + } spin_lock(&ctl_node->resp_lock); ctl_node->seq_num++; -- cgit v1.2.3 From f5d2ff43b9ed9f56e7ff67640aa593fcb8fa56c1 Mon Sep 17 00:00:00 2001 From: Andrey Shevchenko Date: Tue, 29 May 2018 15:00:03 +0300 Subject: qtnfmac: fix bg_scan_period parameter processing Do not process bg_scan_period parameter in qtnfmac driver. Pass correct values as is. In the case of invalid values pass default value. Leave further processing to firmware. Signed-off-by: Andrey Shevchenko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/commands.c | 8 +++----- drivers/net/wireless/quantenna/qtnfmac/core.h | 2 -- 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index e2fc57be1cdd..5eb143667539 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -2339,13 +2339,11 @@ int qtnf_cmd_send_connect(struct qtnf_vif *vif, else eth_zero_addr(cmd->prev_bssid); - if ((sme->bg_scan_period > 0) && - (sme->bg_scan_period <= QTNF_MAX_BG_SCAN_PERIOD)) + if ((sme->bg_scan_period >= 0) && + (sme->bg_scan_period <= SHRT_MAX)) cmd->bg_scan_period = cpu_to_le16(sme->bg_scan_period); - else if (sme->bg_scan_period == -1) - cmd->bg_scan_period = cpu_to_le16(QTNF_DEFAULT_BG_SCAN_PERIOD); else - cmd->bg_scan_period = 0; /* disabled */ + cmd->bg_scan_period = cpu_to_le16(-1); /* use default value */ if (sme->flags & ASSOC_REQ_DISABLE_HT) connect_flags |= QLINK_STA_CONNECT_DISABLE_HT; diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.h b/drivers/net/wireless/quantenna/qtnfmac/core.h index 3b884c80b6ab..214435448335 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.h +++ b/drivers/net/wireless/quantenna/qtnfmac/core.h @@ -44,8 +44,6 @@ #define QTNF_MAX_VSIE_LEN 255 #define QTNF_MAX_INTF 8 #define QTNF_MAX_EVENT_QUEUE_LEN 255 -#define QTNF_DEFAULT_BG_SCAN_PERIOD 300 -#define QTNF_MAX_BG_SCAN_PERIOD 0xffff #define QTNF_SCAN_TIMEOUT_SEC 15 #define QTNF_DEF_BSS_PRIORITY 0 -- cgit v1.2.3 From 40d68dbb986d2116c15e70f63c419a5481d7b91c Mon Sep 17 00:00:00 2001 From: Andrey Shevchenko Date: Tue, 29 May 2018 15:00:04 +0300 Subject: qtnfmac: cancel scan on disconnect Cancel scan operation on STA disconnect. Signed-off-by: Andrey Shevchenko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index 2089cb095283..1fcd94bf7c59 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -660,6 +660,8 @@ qtnf_disconnect(struct wiphy *wiphy, struct net_device *dev, if (vif->wdev.iftype != NL80211_IFTYPE_STATION) return -EOPNOTSUPP; + qtnf_scan_done(mac, true); + if (vif->sta_state == QTNF_STA_DISCONNECTED) return 0; -- cgit v1.2.3 From 480daa9cb62c14bbd1b87a01cd9bc10cc56dbf32 Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Tue, 29 May 2018 15:00:05 +0300 Subject: qtnfmac: fix invalid STA state on EAPOL failure Driver switches vif sta_state into QTNF_STA_CONNECTING when cfg80211 core initiates connect procedure. Further this state is changed either to QTNF_STA_CONNECTED or to QTNF_STA_DISCONNECTED by BSS_JOIN and BSS_LEAVE events from firmware. However it is possible that no such events will be sent by firmware, e.g. if EAPOL timed out. In this case vif sta_mode will remain in QTNF_STA_CONNECTING state and all subsequent connection attempts will fail with -EBUSY error code. Fix this by perfroming STA state transition from QTNF_STA_CONNECTING to QTNF_STA_DISCONNECTED in cfg80211 disconnect callback. No need to rely upon firmware events in this case. Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 21 ++++++++++++++------- drivers/net/wireless/quantenna/qtnfmac/event.c | 8 +++----- 2 files changed, 17 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index 1fcd94bf7c59..220e2b710208 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -649,30 +649,37 @@ qtnf_disconnect(struct wiphy *wiphy, struct net_device *dev, { struct qtnf_wmac *mac = wiphy_priv(wiphy); struct qtnf_vif *vif; - int ret; + int ret = 0; vif = qtnf_mac_get_base_vif(mac); if (!vif) { pr_err("MAC%u: primary VIF is not configured\n", mac->macid); - return -EFAULT; + ret = -EFAULT; + goto out; } - if (vif->wdev.iftype != NL80211_IFTYPE_STATION) - return -EOPNOTSUPP; + if (vif->wdev.iftype != NL80211_IFTYPE_STATION) { + ret = -EOPNOTSUPP; + goto out; + } qtnf_scan_done(mac, true); if (vif->sta_state == QTNF_STA_DISCONNECTED) - return 0; + goto out; ret = qtnf_cmd_send_disconnect(vif, reason_code); if (ret) { pr_err("VIF%u.%u: failed to disconnect\n", mac->macid, vif->vifid); - return ret; + goto out; } - return 0; +out: + if (vif->sta_state == QTNF_STA_CONNECTING) + vif->sta_state = QTNF_STA_DISCONNECTED; + + return ret; } static int diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.c b/drivers/net/wireless/quantenna/qtnfmac/event.c index 16617c44f81b..68da81bec4e9 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/event.c +++ b/drivers/net/wireless/quantenna/qtnfmac/event.c @@ -211,11 +211,9 @@ qtnf_event_handle_bss_leave(struct qtnf_vif *vif, return -EPROTO; } - if (vif->sta_state != QTNF_STA_CONNECTED) { - pr_err("VIF%u.%u: BSS_LEAVE event when STA is not connected\n", - vif->mac->macid, vif->vifid); - return -EPROTO; - } + if (vif->sta_state != QTNF_STA_CONNECTED) + pr_warn("VIF%u.%u: BSS_LEAVE event when STA is not connected\n", + vif->mac->macid, vif->vifid); pr_debug("VIF%u.%u: disconnected\n", vif->mac->macid, vif->vifid); -- cgit v1.2.3