From aa538aca9fb4a197464f5926c7b5d7050e9144b1 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 16 Dec 2015 16:52:19 +0200 Subject: [PATCH 01/11] ath10k: wake up device before accessing registers commit 1aaf8efba0ae ("ath10k: disable PCI PS for QCA988X and QCA99X0") partially reverts pci soc powersave support added by commit 77258d409ce4 ("ath10k: enable pci soc powersaving"). While reverting the change, pci wake up function is called after accessing pci registers instead of prior to access. The assumption is that chip is woken up before accessing its registers.Though this change does not fix any known issues, this might help to avoid unknown or low power platform specific issues. Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 14fd73ec1c96..d77ba4c09e78 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -3071,9 +3071,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_sleep; } - ath10k_pci_ce_deinit(ar); - ath10k_pci_irq_disable(ar); - if (ar_pci->pci_ps == 0) { ret = ath10k_pci_force_wake(ar); if (ret) { @@ -3082,6 +3079,9 @@ static int ath10k_pci_probe(struct pci_dev *pdev, } } + ath10k_pci_ce_deinit(ar); + ath10k_pci_irq_disable(ar); + ret = ath10k_pci_init_irq(ar); if (ret) { ath10k_err(ar, "failed to init irqs: %d\n", ret); From d9d6a5ae2171576aa8f4a9669d1d02e99d830b77 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 16 Dec 2015 16:52:19 +0200 Subject: [PATCH 02/11] ath10k: reduce indentation by moving powersave check within function For devices that does not support PCI power save, force wake up API is used. So move powersave check inside force wakeup to reduce one level indentation. Signed-off-by: Rajkumar Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 34 ++++++++++++--------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index d77ba4c09e78..ee925c618535 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -487,6 +487,9 @@ static int ath10k_pci_force_wake(struct ath10k *ar) unsigned long flags; int ret = 0; + if (ar_pci->pci_ps) + return ret; + spin_lock_irqsave(&ar_pci->ps_lock, flags); if (!ar_pci->ps_awake) { @@ -2480,12 +2483,10 @@ static int ath10k_pci_hif_resume(struct ath10k *ar) u32 val; int ret = 0; - if (ar_pci->pci_ps == 0) { - ret = ath10k_pci_force_wake(ar); - if (ret) { - ath10k_err(ar, "failed to wake up target: %d\n", ret); - return ret; - } + ret = ath10k_pci_force_wake(ar); + if (ret) { + ath10k_err(ar, "failed to wake up target: %d\n", ret); + return ret; } /* Suspend/Resume resets the PCI configuration space, so we have to @@ -2592,13 +2593,10 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; - if (ar_pci->pci_ps == 0) { - ret = ath10k_pci_force_wake(ar); - if (ret) { - ath10k_warn(ar, "failed to wake device up on irq: %d\n", - ret); - return IRQ_NONE; - } + ret = ath10k_pci_force_wake(ar); + if (ret) { + ath10k_warn(ar, "failed to wake device up on irq: %d\n", ret); + return IRQ_NONE; } if (ar_pci->num_msi_intrs == 0) { @@ -3071,12 +3069,10 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_sleep; } - if (ar_pci->pci_ps == 0) { - ret = ath10k_pci_force_wake(ar); - if (ret) { - ath10k_warn(ar, "failed to wake up device : %d\n", ret); - goto err_free_pipes; - } + ret = ath10k_pci_force_wake(ar); + if (ret) { + ath10k_warn(ar, "failed to wake up device : %d\n", ret); + goto err_free_pipes; } ath10k_pci_ce_deinit(ar); From 5c352bf0880655e3a782f55a86fb172542c19a00 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 14 Dec 2015 11:06:01 +0100 Subject: [PATCH 03/11] ath9k_htc: fix handling return value of ath9k_hw_calibrate The function can return negative values in case of error. Its result should be then tested for such case. The problem has been detected using proposed semantic patch scripts/coccinelle/tests/assign_signed_to_unsigned.cocci [1]. [1]: http://permalink.gmane.org/gmane.linux.kernel/2046107 Signed-off-by: Andrzej Hajda Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index a680a970b7f7..fe1fd1a5ae15 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -834,7 +834,7 @@ void ath9k_htc_ani_work(struct work_struct *work) if (longcal || shortcal) common->ani.caldone = ath9k_hw_calibrate(ah, ah->curchan, - ah->rxchainmask, longcal); + ah->rxchainmask, longcal) > 0; ath9k_htc_ps_restore(priv); } From f94c48d6c315a580b60b062c0360561b61faa311 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 16 Dec 2015 14:10:00 +0300 Subject: [PATCH 04/11] wil6210: fix a warning message condition "iter" is -1 at the end of the loop and not zero. It means we don't print a warning message. Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 09b4daebab9d..b39f0bfc591e 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -987,7 +987,7 @@ int __wil_down(struct wil6210_priv *wil) } mutex_lock(&wil->mutex); - if (!iter) + if (iter < 0) wil_err(wil, "timeout waiting for idle FW/HW\n"); wil_reset(wil, false); From e33a99e227e430a788467e5a85dc29f6df16b983 Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Thu, 31 Dec 2015 15:26:20 +0200 Subject: [PATCH 05/11] ath10k: set SM power save disabled to default value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use SMPS disabled as default because FW does not indicate any support of SMPS. This change will help STAs out that don’t support SMPS from sticking on 1SS, since they don’t have method to change it back to multiple chains. This change also should not affect power consumption of STAs supporting SMPS, because they are capable to switch the mode to dynamic or static either at the end of frame sequence or by using SMPS action frame. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b4bdeb07a012..6146a293601a 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3860,7 +3860,8 @@ static struct ieee80211_sta_ht_cap ath10k_get_ht_cap(struct ath10k *ar) ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40; - ht_cap.cap |= WLAN_HT_CAP_SM_PS_STATIC << IEEE80211_HT_CAP_SM_PS_SHIFT; + ht_cap.cap |= + WLAN_HT_CAP_SM_PS_DISABLED << IEEE80211_HT_CAP_SM_PS_SHIFT; if (ar->ht_cap_info & WMI_HT_CAP_HT20_SGI) ht_cap.cap |= IEEE80211_HT_CAP_SGI_20; From dea16eddb4753129dbcd8dc8d1a58ff0cc4ea38c Mon Sep 17 00:00:00 2001 From: Hamad Kadmany Date: Wed, 16 Dec 2015 17:51:45 +0200 Subject: [PATCH 06/11] wil6210: fix kernel OOPS when stopping interface during Rx traffic When network interface is stopping, some resources may be already released by the network stack, and Rx frames cause kernel OOPS (observed one is in netfilter code) Proper solution is to drop packets pending in reorder buffer. Signed-off-by: Hamad Kadmany Signed-off-by: Vladimir Kondratiev Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/rx_reorder.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index e3d1be82f314..32031e7a11d5 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -261,9 +261,19 @@ struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, struct wil_tid_ampdu_rx *r) { + int i; + if (!r) return; - wil_release_reorder_frames(wil, r, r->head_seq_num + r->buf_size); + + /* Do not pass remaining frames to the network stack - it may be + * not expecting to get any more Rx. Rx from here may lead to + * kernel OOPS since some per-socket accounting info was already + * released. + */ + for (i = 0; i < r->buf_size; i++) + kfree_skb(r->reorder_buf[i]); + kfree(r->reorder_buf); kfree(r->reorder_time); kfree(r); From ea3ade75db690dc47c78a77d71dfd7c2df3bb15d Mon Sep 17 00:00:00 2001 From: Lior David Date: Wed, 16 Dec 2015 17:51:46 +0200 Subject: [PATCH 07/11] wil6210: support for platform specific crash recovery Added a simple interface for platform to perform crash recovery. When firmware crashes, wil driver can notify the platform which can trigger a crash recovery process. During the process the platform can request a ram dump from the wil driver as well as control when firmware recovery will start. This interface allows the platform to implement a more advanced crash recovery, for example to reset dependent subsystems in proper order, or to provide its own notifications during the recovery process. Signed-off-by: Lior David Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/interrupt.c | 8 +++- drivers/net/wireless/ath/wil6210/pcie_bus.c | 30 ++++++++++++++- drivers/net/wireless/ath/wil6210/wil6210.h | 1 + .../net/wireless/ath/wil6210/wil_crash_dump.c | 3 +- .../net/wireless/ath/wil6210/wil_platform.c | 3 +- .../net/wireless/ath/wil6210/wil_platform.h | 38 +++++++++++++++++-- 6 files changed, 73 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 50c136e843c4..4f2ffa5c6e17 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -394,9 +394,13 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) wil_fw_core_dump(wil); wil_notify_fw_error(wil); isr &= ~ISR_MISC_FW_ERROR; - wil_fw_error_recovery(wil); + if (wil->platform_ops.notify_crash) { + wil_err(wil, "notify platform driver about FW crash"); + wil->platform_ops.notify_crash(wil->platform_handle); + } else { + wil_fw_error_recovery(wil); + } } - if (isr & ISR_MISC_MBOX_EVT) { wil_dbg_irq(wil, "MBOX event\n"); wmi_recv_cmd(wil); diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 1a3142c332e1..e36f2a0c8cb6 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -125,11 +125,37 @@ static int wil_if_pcie_disable(struct wil6210_priv *wil) return 0; } +static int wil_platform_rop_ramdump(void *wil_handle, void *buf, uint32_t size) +{ + struct wil6210_priv *wil = wil_handle; + + if (!wil) + return -EINVAL; + + return wil_fw_copy_crash_dump(wil, buf, size); +} + +static int wil_platform_rop_fw_recovery(void *wil_handle) +{ + struct wil6210_priv *wil = wil_handle; + + if (!wil) + return -EINVAL; + + wil_fw_error_recovery(wil); + + return 0; +} + static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct wil6210_priv *wil; struct device *dev = &pdev->dev; int rc; + const struct wil_platform_rops rops = { + .ramdump = wil_platform_rop_ramdump, + .fw_recovery = wil_platform_rop_fw_recovery, + }; /* check HW */ dev_info(&pdev->dev, WIL_NAME @@ -154,7 +180,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* rollback to if_free */ wil->platform_handle = - wil_platform_init(&pdev->dev, &wil->platform_ops); + wil_platform_init(&pdev->dev, &wil->platform_ops, &rops, wil); if (!wil->platform_handle) { rc = -ENODEV; wil_err(wil, "wil_platform_init failed\n"); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index ade5f3b8274b..235e205ce2bc 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -828,6 +828,7 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime); int wil_suspend(struct wil6210_priv *wil, bool is_runtime); int wil_resume(struct wil6210_priv *wil, bool is_runtime); +int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size); void wil_fw_core_dump(struct wil6210_priv *wil); #endif /* __WIL6210_H__ */ diff --git a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c index 7e70934990ae..b57d280946e0 100644 --- a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c +++ b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c @@ -51,8 +51,7 @@ static int wil_fw_get_crash_dump_bounds(struct wil6210_priv *wil, return 0; } -static int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, - u32 size) +int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size) { int i; const struct fw_map *map; diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.c b/drivers/net/wireless/ath/wil6210/wil_platform.c index 2e831bf20117..4eed05bddb60 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.c +++ b/drivers/net/wireless/ath/wil6210/wil_platform.c @@ -33,7 +33,8 @@ void wil_platform_modexit(void) * It returns a handle which is used with the rest of the API * */ -void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops) +void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops, + const struct wil_platform_rops *rops, void *wil_handle) { void *handle = ops; /* to return some non-NULL for 'void' impl. */ diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h index d7fa19b7886d..9a949d910343 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.h +++ b/drivers/net/wireless/ath/wil6210/wil_platform.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,16 +20,48 @@ struct device; /** - * struct wil_platform_ops - wil platform module callbacks + * struct wil_platform_ops - wil platform module calls from this + * driver to platform driver */ struct wil_platform_ops { int (*bus_request)(void *handle, uint32_t kbps /* KBytes/Sec */); int (*suspend)(void *handle); int (*resume)(void *handle); void (*uninit)(void *handle); + int (*notify_crash)(void *handle); }; -void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops); +/** + * struct wil_platform_rops - wil platform module callbacks from + * platform driver to this driver + * @ramdump: store a ramdump from the wil firmware. The platform + * driver may add additional data to the ramdump to + * generate the final crash dump. + * @fw_recovery: start a firmware recovery process. Called as + * part of a crash recovery process which may include other + * related platform subsystems. + */ +struct wil_platform_rops { + int (*ramdump)(void *wil_handle, void *buf, uint32_t size); + int (*fw_recovery)(void *wil_handle); +}; + +/** + * wil_platform_init - initialize the platform driver + * + * @dev - pointer to the wil6210 device + * @ops - structure with platform driver operations. Platform + * driver will fill this structure with function pointers. + * @rops - structure with callbacks from platform driver to + * this driver. The platform driver copies the structure to + * its own storage. Can be NULL if this driver does not + * support crash recovery. + * @wil_handle - context for this driver that will be passed + * when platform driver invokes one of the callbacks in + * rops. May be NULL if rops is NULL. + */ +void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops, + const struct wil_platform_rops *rops, void *wil_handle); int __init wil_platform_modinit(void); void wil_platform_modexit(void); From 50e81e2f0b0a9fdb9e5bd515270680c7c281ce1f Mon Sep 17 00:00:00 2001 From: Pawel Kulakowski Date: Fri, 18 Dec 2015 10:48:57 +0100 Subject: [PATCH 08/11] ath9k: Enable support for cloned SKBS Ath9k driver does not modify tx skbs, so SUPPORTS_CLONED_SKBS flag can be set. Enabling this flag significant reduce number of copy operation during TCP Tx. This is especially noticeable on platforms with slower CPU (lower CPU usage brings profits in better TCP Tx troughput results). Tested on MIPS with 560 MHz clock Without CLONED_SKBS flag: TCP Tx 145 Mb/s (iperf result) __copy_user_common consumes 12.9% of CPU (result from perf tool) 0% CPU Idle With CLONED_SKBS flag: TCP Tx 170 Mb/s (iperf result) __copy_user_common consumes 1.8% of CPU (result from perf tool) 12% CPU Idle Signed-off-by: Pawel Kulakowski Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 2e2b92ba96b8..ab7a1ac37849 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -828,6 +828,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) ieee80211_hw_set(hw, RX_INCLUDES_FCS); ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); + ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); if (ath9k_ps_enable) ieee80211_hw_set(hw, SUPPORTS_PS); From 19f2ce3f1114c5d59e5e4457ccdd15464070dc5f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 19 Dec 2015 13:59:19 +0300 Subject: [PATCH 09/11] ath9k: fix ath9k_hw_nvram_check_version() There is a type bug so it always returns success. Fixes: 6fa658fd5ab2 ('ath9k: Simplify and fix eeprom endianness swapping') Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index f8c5065e5f5f..a7afdeee698c 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -206,7 +206,7 @@ bool ath9k_hw_nvram_check_version(struct ath_hw *ah, int version, int minrev) ath_err(common, "Bad EEPROM VER 0x%04x or REV 0x%04x\n", ah->eep_ops->get_eeprom_ver(ah), ah->eep_ops->get_eeprom_rev(ah)); - return -EINVAL; + return false; } return true; From 2ec7752fd9b9fe5924973390b784584e7481f52c Mon Sep 17 00:00:00 2001 From: Fengwei Yin Date: Sun, 20 Dec 2015 21:20:40 +0800 Subject: [PATCH 10/11] wcn36xx: handle rx skb allocation failure to avoid system crash Lawrence reported that git clone could make system crash on a Qualcomm ARM soc based device (DragonBoard, 1G memory without swap) running 64bit Debian. It's turned out the crash is related with rx skb allocation failure. git could consume more than 600MB anonymous memory. And system is in extremely memory shortage case. But driver didn't handle the rx allocation failure case. This patch doesn't submit skb to upper layer if rx skb allocation fails. Instead, it reuse the old skb for rx DMA again. It's more like drop the packets if system is in memory shortage case. With this change, git clone is OOMed instead of system crash. Reported-by: King, Lawrence Signed-off-by: Fengwei Yin Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/dxe.c | 41 +++++++++++++------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index f8dfa05b290a..473381f483bf 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -474,36 +474,37 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn, struct wcn36xx_dxe_desc *dxe = ctl->desc; dma_addr_t dma_addr; struct sk_buff *skb; + int ret = 0, int_mask; + u32 value; + + 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; + } while (!(dxe->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)) { skb = ctl->skb; dma_addr = dxe->dst_addr_l; - wcn36xx_dxe_fill_skb(wcn->dev, ctl); + ret = wcn36xx_dxe_fill_skb(wcn->dev, ctl); + if (0 == ret) { + /* new skb allocation ok. Use the new one and queue + * the old one to network system. + */ + dma_unmap_single(wcn->dev, dma_addr, WCN36XX_PKT_SIZE, + DMA_FROM_DEVICE); + wcn36xx_rx_skb(wcn, skb); + } /* else keep old skb not submitted and use it for rx DMA */ - switch (ch->ch_type) { - case WCN36XX_DXE_CH_RX_L: - dxe->ctrl = WCN36XX_DXE_CTRL_RX_L; - wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_ENCH_ADDR, - WCN36XX_DXE_INT_CH1_MASK); - break; - case WCN36XX_DXE_CH_RX_H: - dxe->ctrl = WCN36XX_DXE_CTRL_RX_H; - wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_ENCH_ADDR, - WCN36XX_DXE_INT_CH3_MASK); - break; - default: - wcn36xx_warn("Unknown channel\n"); - } - - dma_unmap_single(wcn->dev, dma_addr, WCN36XX_PKT_SIZE, - DMA_FROM_DEVICE); - wcn36xx_rx_skb(wcn, skb); + wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_ENCH_ADDR, int_mask); + dxe->ctrl = value; ctl = ctl->next; dxe = ctl->desc; } ch->head_blk_ctl = ctl; - return 0; } From 9d5db23eecdb001ac26610d7a87ccdea566feee9 Mon Sep 17 00:00:00 2001 From: Fengwei Yin Date: Sun, 20 Dec 2015 21:20:41 +0800 Subject: [PATCH 11/11] wcn36xx: split DMA mask register writing. Per comments from Bjorn Andersson , split DMA mask register writing as seperate patch in case we need bi-sect in the furture. Signed-off-by: Fengwei Yin Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/dxe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index 473381f483bf..8643801f31b6 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -498,11 +498,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 */ - wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_ENCH_ADDR, int_mask); dxe->ctrl = value; ctl = ctl->next; dxe = ctl->desc; } + wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_ENCH_ADDR, int_mask); ch->head_blk_ctl = ctl; return 0;