From 90a44bb4251c4bd6363431d6819ed1725e892bdd Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Thu, 22 Mar 2018 03:52:59 +0000 Subject: Wifi fixes for QCom DragonBoard 410c, drop reference to upstreamed bcm283x patch --- kernel.spec | 18 ++- ...are-crash-due-to-corrupted-buffer-address.patch | 164 +++++++++++++++++++++ wcn36xx-reduce-verbosity-of-drivers-messages.patch | 95 ++++++++++++ 3 files changed, 271 insertions(+), 6 deletions(-) create mode 100644 wcn36xx-Fix-firmware-crash-due-to-corrupted-buffer-address.patch create mode 100644 wcn36xx-reduce-verbosity-of-drivers-messages.patch diff --git a/kernel.spec b/kernel.spec index 81e15c6b2..7f4221ee6 100644 --- a/kernel.spec +++ b/kernel.spec @@ -580,19 +580,22 @@ Patch302: arm-revert-mmc-omap_hsmmc-Use-dma_request_chan-for-reque.patch # http://patchwork.ozlabs.org/patch/587554/ Patch303: ARM-tegra-usb-no-reset.patch -Patch305: arm64-Revert-allwinner-a64-pine64-Use-dcdc1-regulato.patch +Patch304: arm64-Revert-allwinner-a64-pine64-Use-dcdc1-regulato.patch # https://patchwork.kernel.org/patch/9820417/ -Patch306: qcom-msm89xx-fixes.patch +Patch305: qcom-msm89xx-fixes.patch # https://patchwork.kernel.org/patch/10173115/ -Patch307: arm-dts-imx6qdl-udoo-Disable-usbh1-to-avoid-kernel-hang.patch +Patch306: arm-dts-imx6qdl-udoo-Disable-usbh1-to-avoid-kernel-hang.patch # Fix USB on the RPi https://patchwork.kernel.org/patch/9879371/ -Patch308: bcm283x-dma-mapping-skip-USB-devices-when-configuring-DMA-during-probe.patch +Patch307: bcm283x-dma-mapping-skip-USB-devices-when-configuring-DMA-during-probe.patch -# https://www.spinics.net/lists/stable/msg214527.html -Patch311: arm-clk-bcm2835-hdmi-fixes.patch +# http://patches.linaro.org/patch/131764/ +Patch308: wcn36xx-Fix-firmware-crash-due-to-corrupted-buffer-address.patch + +# https://patchwork.kernel.org/patch/10245303/ +Patch309: wcn36xx-reduce-verbosity-of-drivers-messages.patch # https://www.spinics.net/lists/arm-kernel/msg632925.html Patch313: arm-crypto-sunxi-ss-Add-MODULE_ALIAS-to-sun4i-ss.patch @@ -1924,6 +1927,9 @@ fi # # %changelog +* Thu Mar 22 2018 Peter Robinson +- Wifi fixes for QCom DragonBoard 410c + * Wed Mar 21 2018 Jeremy Cline - 4.16.0-0.rc6.git2.1 - Linux v4.16-rc6-75-g3215b9d57a2c diff --git a/wcn36xx-Fix-firmware-crash-due-to-corrupted-buffer-address.patch b/wcn36xx-Fix-firmware-crash-due-to-corrupted-buffer-address.patch new file mode 100644 index 000000000..dd8db063c --- /dev/null +++ b/wcn36xx-Fix-firmware-crash-due-to-corrupted-buffer-address.patch @@ -0,0 +1,164 @@ +From patchwork Thu Mar 15 11:31:33 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: wcn36xx: Fix firmware crash due to corrupted buffer address +X-Patchwork-Submitter: Ramon Fried +X-Patchwork-Id: 131764 +Message-Id: <20180315113133.28791-1-rfried@codeaurora.org> +To: k.eugene.e@gmail.com, kvalo@codeaurora.org, + wcn36xx@lists.infradead.org, linux-wireless@vger.kernel.org +Cc: Loic Poulain , Ramon Fried +Date: Thu, 15 Mar 2018 13:31:33 +0200 +From: Ramon Fried +List-Id: + +From: Loic Poulain + +wcn36xx_start_tx function retrieves the buffer descriptor from the +channel control queue to start filling tx buffer information. However, +nothing prevents this same buffer to be concurrently accessed in a +concurent tx call, leading to potential buffer coruption and firmware +crash (observed during iperf test). The channel control queue should +only be accessed and updated with the channel lock. + +Fix this issue by using a local buffer descriptor which will be copied +in the thread-safe wcn36xx_dxe_tx_frame. + +Note that buffer descriptor size is few bytes so the introduced copy +overhead is insignificant. Moreover, this allows to keep the locked +section minimal. + +Signed-off-by: Loic Poulain +Signed-off-by: Ramon Fried +--- + drivers/net/wireless/ath/wcn36xx/dxe.c | 13 ++++--------- + drivers/net/wireless/ath/wcn36xx/dxe.h | 3 ++- + drivers/net/wireless/ath/wcn36xx/txrx.c | 32 ++++++++++---------------------- + 3 files changed, 16 insertions(+), 32 deletions(-) + +-- +The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, +a Linux Foundation Collaborative Project + +diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c +index 7d5ecaf02288..2c3b899a88fa 100644 +--- a/drivers/net/wireless/ath/wcn36xx/dxe.c ++++ b/drivers/net/wireless/ath/wcn36xx/dxe.c +@@ -27,15 +27,6 @@ + #include "wcn36xx.h" + #include "txrx.h" + +-void *wcn36xx_dxe_get_next_bd(struct wcn36xx *wcn, bool is_low) +-{ +- struct wcn36xx_dxe_ch *ch = is_low ? +- &wcn->dxe_tx_l_ch : +- &wcn->dxe_tx_h_ch; +- +- return ch->head_blk_ctl->bd_cpu_addr; +-} +- + static void wcn36xx_ccu_write_register(struct wcn36xx *wcn, int addr, int data) + { + wcn36xx_dbg(WCN36XX_DBG_DXE, +@@ -648,6 +639,7 @@ void wcn36xx_dxe_free_mem_pools(struct wcn36xx *wcn) + + int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, + struct wcn36xx_vif *vif_priv, ++ struct wcn36xx_tx_bd *bd, + struct sk_buff *skb, + bool is_low) + { +@@ -681,6 +673,9 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, + ctl->skb = NULL; + desc = ctl->desc; + ++ /* write buffer descriptor */ ++ memcpy(ctl->bd_cpu_addr, bd, sizeof(*bd)); ++ + /* Set source address of the BD we send */ + desc->src_addr_l = ctl->bd_phy_addr; + +diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.h b/drivers/net/wireless/ath/wcn36xx/dxe.h +index 2bc376c5391b..ce580960d109 100644 +--- a/drivers/net/wireless/ath/wcn36xx/dxe.h ++++ b/drivers/net/wireless/ath/wcn36xx/dxe.h +@@ -452,6 +452,7 @@ struct wcn36xx_dxe_mem_pool { + dma_addr_t phy_addr; + }; + ++struct wcn36xx_tx_bd; + struct wcn36xx_vif; + int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn); + void wcn36xx_dxe_free_mem_pools(struct wcn36xx *wcn); +@@ -463,8 +464,8 @@ void wcn36xx_dxe_deinit(struct wcn36xx *wcn); + int wcn36xx_dxe_init_channels(struct wcn36xx *wcn); + int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, + struct wcn36xx_vif *vif_priv, ++ struct wcn36xx_tx_bd *bd, + struct sk_buff *skb, + bool is_low); + void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status); +-void *wcn36xx_dxe_get_next_bd(struct wcn36xx *wcn, bool is_low); + #endif /* _DXE_H_ */ +diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c +index 22304edc5948..b1768ed6b0be 100644 +--- a/drivers/net/wireless/ath/wcn36xx/txrx.c ++++ b/drivers/net/wireless/ath/wcn36xx/txrx.c +@@ -272,21 +272,9 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, + bool is_low = ieee80211_is_data(hdr->frame_control); + bool bcast = is_broadcast_ether_addr(hdr->addr1) || + is_multicast_ether_addr(hdr->addr1); +- struct wcn36xx_tx_bd *bd = wcn36xx_dxe_get_next_bd(wcn, is_low); +- +- if (!bd) { +- /* +- * TX DXE are used in pairs. One for the BD and one for the +- * actual frame. The BD DXE's has a preallocated buffer while +- * the skb ones does not. If this isn't true something is really +- * wierd. TODO: Recover from this situation +- */ +- +- wcn36xx_err("bd address may not be NULL for BD DXE\n"); +- return -EINVAL; +- } ++ struct wcn36xx_tx_bd bd; + +- memset(bd, 0, sizeof(*bd)); ++ memset(&bd, 0, sizeof(bd)); + + wcn36xx_dbg(WCN36XX_DBG_TX, + "tx skb %p len %d fc %04x sn %d %s %s\n", +@@ -296,10 +284,10 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, + + wcn36xx_dbg_dump(WCN36XX_DBG_TX_DUMP, "", skb->data, skb->len); + +- bd->dpu_rf = WCN36XX_BMU_WQ_TX; ++ bd.dpu_rf = WCN36XX_BMU_WQ_TX; + +- bd->tx_comp = !!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS); +- if (bd->tx_comp) { ++ bd.tx_comp = !!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS); ++ if (bd.tx_comp) { + wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested\n"); + spin_lock_irqsave(&wcn->dxe_lock, flags); + if (wcn->tx_ack_skb) { +@@ -321,13 +309,13 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, + + /* Data frames served first*/ + if (is_low) +- wcn36xx_set_tx_data(bd, wcn, &vif_priv, sta_priv, skb, bcast); ++ wcn36xx_set_tx_data(&bd, wcn, &vif_priv, sta_priv, skb, bcast); + else + /* MGMT and CTRL frames are handeld here*/ +- wcn36xx_set_tx_mgmt(bd, wcn, &vif_priv, skb, bcast); ++ wcn36xx_set_tx_mgmt(&bd, wcn, &vif_priv, skb, bcast); + +- buff_to_be((u32 *)bd, sizeof(*bd)/sizeof(u32)); +- bd->tx_bd_sign = 0xbdbdbdbd; ++ buff_to_be((u32 *)&bd, sizeof(bd)/sizeof(u32)); ++ bd.tx_bd_sign = 0xbdbdbdbd; + +- return wcn36xx_dxe_tx_frame(wcn, vif_priv, skb, is_low); ++ return wcn36xx_dxe_tx_frame(wcn, vif_priv, &bd, skb, is_low); + } diff --git a/wcn36xx-reduce-verbosity-of-drivers-messages.patch b/wcn36xx-reduce-verbosity-of-drivers-messages.patch new file mode 100644 index 000000000..7f9e39b40 --- /dev/null +++ b/wcn36xx-reduce-verbosity-of-drivers-messages.patch @@ -0,0 +1,95 @@ +From patchwork Tue Feb 27 14:05:35 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v3] wcn36xx: reduce verbosity of drivers messages +From: Ramon Fried +X-Patchwork-Id: 10245303 +Message-Id: <20180227140535.4794-1-rfried@codeaurora.org> +To: k.eugene.e@gmail.com, kvalo@codeaurora.org, + wcn36xx@lists.infradead.org, linux-wireless@vger.kernel.org +Cc: Ramon Fried +Date: Tue, 27 Feb 2018 16:05:35 +0200 + +Whenever the WLAN interface is started the FW +version and caps are printed. +The caps now will be displayed only in debug mode. +Firmware version will be displayed only once on first +startup of the interface. + +Change-Id: I4db6ea7f384fe15eebe4c3ddb1d1ccab00094332 +Signed-off-by: Ramon Fried +--- +v2: print the firwmare version as info but only + onetime. +v3: change the static variable to a struct variable. + + drivers/net/wireless/ath/wcn36xx/main.c | 3 ++- + drivers/net/wireless/ath/wcn36xx/smd.c | 18 ++++++++++-------- + drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 2 ++ + 3 files changed, 14 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c +index ab5be6d2c691..bfe9062bfa52 100644 +--- a/drivers/net/wireless/ath/wcn36xx/main.c ++++ b/drivers/net/wireless/ath/wcn36xx/main.c +@@ -261,7 +261,7 @@ static void wcn36xx_feat_caps_info(struct wcn36xx *wcn) + + for (i = 0; i < MAX_FEATURE_SUPPORTED; i++) { + if (get_feat_caps(wcn->fw_feat_caps, i)) +- wcn36xx_info("FW Cap %s\n", wcn36xx_get_cap_name(i)); ++ wcn36xx_dbg(WCN36XX_DBG_MAC, "FW Cap %s\n", wcn36xx_get_cap_name(i)); + } + } + +@@ -1283,6 +1283,7 @@ static int wcn36xx_probe(struct platform_device *pdev) + wcn = hw->priv; + wcn->hw = hw; + wcn->dev = &pdev->dev; ++ wcn->first_boot = true; + mutex_init(&wcn->conf_mutex); + mutex_init(&wcn->hal_mutex); + mutex_init(&wcn->scan_lock); +diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c +index 2a4871ca9c72..1a5b4d57c0ac 100644 +--- a/drivers/net/wireless/ath/wcn36xx/smd.c ++++ b/drivers/net/wireless/ath/wcn36xx/smd.c +@@ -409,15 +409,17 @@ static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len) + wcn->fw_minor = rsp->start_rsp_params.version.minor; + wcn->fw_major = rsp->start_rsp_params.version.major; + +- wcn36xx_info("firmware WLAN version '%s' and CRM version '%s'\n", +- wcn->wlan_version, wcn->crm_version); +- +- wcn36xx_info("firmware API %u.%u.%u.%u, %u stations, %u bssids\n", +- wcn->fw_major, wcn->fw_minor, +- wcn->fw_version, wcn->fw_revision, +- rsp->start_rsp_params.stations, +- rsp->start_rsp_params.bssids); ++ if (wcn->first_boot) { ++ wcn->first_boot = false; ++ wcn36xx_info("firmware WLAN version '%s' and CRM version '%s'\n", ++ wcn->wlan_version, wcn->crm_version); + ++ wcn36xx_info("firmware API %u.%u.%u.%u, %u stations, %u bssids\n", ++ wcn->fw_major, wcn->fw_minor, ++ wcn->fw_version, wcn->fw_revision, ++ rsp->start_rsp_params.stations, ++ rsp->start_rsp_params.bssids); ++ } + return 0; + } + +diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +index 81017e6703b4..5854adf43f3a 100644 +--- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h ++++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +@@ -192,6 +192,8 @@ struct wcn36xx { + u8 crm_version[WCN36XX_HAL_VERSION_LENGTH + 1]; + u8 wlan_version[WCN36XX_HAL_VERSION_LENGTH + 1]; + ++ bool first_boot; ++ + /* IRQs */ + int tx_irq; + int rx_irq; -- cgit