From 4895efc9a11ba6a3089b42c5dd4aabf68e467d64 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:21 +0530 Subject: ath9k: Remove ATH9K_HW_WOW_DEVICE_CAPABLE Enabling WOW based on the chip is incorrect since it needs to be done for specific sub-devices which have proper platform support. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/wow.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/wow.c') diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 5f30e580d942..4ffaadd167a8 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -352,9 +352,7 @@ void ath9k_init_wow(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) && - (sc->driver_data & ATH9K_PCI_WOW) && - device_can_wakeup(sc->dev)) + if ((sc->driver_data & ATH9K_PCI_WOW) && device_can_wakeup(sc->dev)) hw->wiphy->wowlan = &ath9k_wowlan_support; atomic_set(&sc->wow_sleep_proc_intr, -1); -- cgit v1.2.3 From 13084c2d18bfee72594ba3a969dfdd972544e644 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:22 +0530 Subject: ath9k: Return early for error conditions Do not try to cancel work instances and ANI when the device is not present or WOW triggers are not configured. Bail out early and use ath_err() for such error conditions. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/wow.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/wow.c') diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 4ffaadd167a8..1d5cd88783bd 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -197,21 +197,21 @@ int ath9k_suspend(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); - ath_cancel_work(sc); - ath_stop_ani(sc); - if (test_bit(ATH_OP_INVALID, &common->op_flags)) { - ath_dbg(common, ANY, "Device not present\n"); - ret = -EINVAL; + ath_err(common, "Device not present\n"); + ret = -ENODEV; goto fail_wow; } if (WARN_ON(!wowlan)) { - ath_dbg(common, WOW, "None of the WoW triggers enabled\n"); + ath_err(common, "None of the WoW triggers enabled\n"); ret = -EINVAL; goto fail_wow; } + ath_cancel_work(sc); + ath_stop_ani(sc); + if (!device_can_wakeup(sc->dev)) { ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n"); ret = 1; -- cgit v1.2.3 From 410b4e27992b7bc3ed8064dc9383eb66c1fee04d Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:23 +0530 Subject: ath9k: Remove redundant device_can_wakeup() check WOW capability is registered with mac80211 only when the device has the ability to wakeup, so there is no need to check in the suspend() routine. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/wow.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/wow.c') diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 1d5cd88783bd..272c05c5c24e 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -212,12 +212,6 @@ int ath9k_suspend(struct ieee80211_hw *hw, ath_cancel_work(sc); ath_stop_ani(sc); - if (!device_can_wakeup(sc->dev)) { - ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n"); - ret = 1; - goto fail_wow; - } - /* * none of the sta vifs are associated * and we are not currently handling multivif -- cgit v1.2.3 From dc4b277d51599453f9ebf8e117957c26187d5fce Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:24 +0530 Subject: ath9k: Check early for multi-vif/STA conditions If multiple interfaces are active or there is no associated station interface, bail out early and return 1 so that mac80211 can proceed with the normal suspend routine. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/wow.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/wow.c') diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 272c05c5c24e..1799a1d69ebd 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -209,29 +209,21 @@ int ath9k_suspend(struct ieee80211_hw *hw, goto fail_wow; } - ath_cancel_work(sc); - ath_stop_ani(sc); - - /* - * none of the sta vifs are associated - * and we are not currently handling multivif - * cases, for instance we have to seperately - * configure 'keep alive frame' for each - * STA. - */ - - if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { - ath_dbg(common, WOW, "None of the STA vifs are associated\n"); + if (sc->cur_chan->nvifs > 1) { + ath_dbg(common, WOW, "WoW for multivif is not yet supported\n"); ret = 1; goto fail_wow; } - if (sc->cur_chan->nvifs > 1) { - ath_dbg(common, WOW, "WoW for multivif is not yet supported\n"); + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { + ath_dbg(common, WOW, "None of the STA vifs are associated\n"); ret = 1; goto fail_wow; } + ath_cancel_work(sc); + ath_stop_ani(sc); + ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled); ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n", -- cgit v1.2.3 From 1331f5a751eb143bc7732c880bbdde4431e90a77 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:25 +0530 Subject: ath9k: Check multi-channel context for WOW If CONFIG_ATH9K_CHANNEL_CONTEXT is enabled, check whether multiple contexts are active and if so, return 1 without enabling WOW since we don't support it in this case. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/wow.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/net/wireless/ath/ath9k/wow.c') diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 1799a1d69ebd..1b005c697c03 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -215,6 +215,15 @@ int ath9k_suspend(struct ieee80211_hw *hw, goto fail_wow; } + if (ath9k_is_chanctx_enabled()) { + if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) { + ath_dbg(common, WOW, + "Multi-channel WOW is not supported\n"); + ret = 1; + goto fail_wow; + } + } + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { ath_dbg(common, WOW, "None of the STA vifs are associated\n"); ret = 1; -- cgit v1.2.3 From 661d25815ea533d06c7535ddd1c4810fa7ab9e22 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:26 +0530 Subject: ath9k: Fix wow init/deinit Registering the card as a wakeup source needs to be done once, during initialization. When the WOW configuration changes, the card's status as wakeup source needs to be changed too and this is done via the set_wakeup() callback. Also, make sure the device is removed properly using ath9k_deinit_wow(). Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 ++++ drivers/net/wireless/ath/ath9k/init.c | 1 + drivers/net/wireless/ath/ath9k/wow.c | 22 ++++++++++++++++++---- 3 files changed, 23 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/wow.c') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index e84b5769deb0..4209d7baf1d4 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -838,6 +838,7 @@ struct ath9k_wow_pattern { #ifdef CONFIG_ATH9K_WOW void ath9k_init_wow(struct ieee80211_hw *hw); +void ath9k_deinit_wow(struct ieee80211_hw *hw); int ath9k_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); int ath9k_resume(struct ieee80211_hw *hw); @@ -846,6 +847,9 @@ void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled); static inline void ath9k_init_wow(struct ieee80211_hw *hw) { } +static inline void ath9k_deinit_wow(struct ieee80211_hw *hw) +{ +} static inline int ath9k_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 2aef14e47c39..6c6e88495394 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -996,6 +996,7 @@ void ath9k_deinit_device(struct ath_softc *sc) ath9k_ps_restore(sc); ath9k_deinit_debug(sc); + ath9k_deinit_wow(hw); ieee80211_unregister_hw(hw); ath_rx_cleanup(sc); ath9k_deinit_softc(sc); diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 1b005c697c03..8bcbaa91529e 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -336,20 +336,34 @@ int ath9k_resume(struct ieee80211_hw *hw) void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) { struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); mutex_lock(&sc->mutex); - device_init_wakeup(sc->dev, 1); device_set_wakeup_enable(sc->dev, enabled); mutex_unlock(&sc->mutex); + + ath_dbg(common, WOW, "WoW wakeup source is %s\n", + (enabled) ? "enabled" : "disabled"); } void ath9k_init_wow(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - if ((sc->driver_data & ATH9K_PCI_WOW) && device_can_wakeup(sc->dev)) + if (sc->driver_data & ATH9K_PCI_WOW) { hw->wiphy->wowlan = &ath9k_wowlan_support; - atomic_set(&sc->wow_sleep_proc_intr, -1); - atomic_set(&sc->wow_got_bmiss_intr, -1); + atomic_set(&sc->wow_sleep_proc_intr, -1); + atomic_set(&sc->wow_got_bmiss_intr, -1); + + device_init_wakeup(sc->dev, 1); + } +} + +void ath9k_deinit_wow(struct ieee80211_hw *hw) +{ + struct ath_softc *sc = hw->priv; + + if (sc->driver_data & ATH9K_PCI_WOW) + device_init_wakeup(sc->dev, 0); } -- cgit v1.2.3 From 249943a2215c4d03c5dacf549b4ef9bf8439f17b Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:27 +0530 Subject: ath9k: Check WOW triggers properly This patch makes sure that valid WOW triggers are present before trying to suspend the device. Also, introduce and use ATH_OP_WOW_ENABLED to bypass PCI suspend and clear it in resume(). Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath.h | 1 + drivers/net/wireless/ath/ath9k/pci.c | 5 +++- drivers/net/wireless/ath/ath9k/wow.c | 53 ++++++++++++++++-------------------- 3 files changed, 29 insertions(+), 30 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/wow.c') diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index ccba4fea7269..1eebe2ea3dfb 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -64,6 +64,7 @@ enum ath_op_flags { ATH_OP_HW_RESET, ATH_OP_SCANNING, ATH_OP_MULTI_CHANNEL, + ATH_OP_WOW_ENABLED, }; enum ath_bus_type { diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index cc5c6810f32e..e6fef1be9977 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -998,9 +998,12 @@ static int ath_pci_suspend(struct device *device) struct pci_dev *pdev = to_pci_dev(device); struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); - if (sc->wow_enabled) + if (test_bit(ATH_OP_WOW_ENABLED, &common->op_flags)) { + dev_info(&pdev->dev, "WOW is enabled, bypassing PCI suspend\n"); return 0; + } /* The device has to be moved to FULLSLEEP forcibly. * Otherwise the chip never moved to full sleep, diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 8bcbaa91529e..c0c564de982e 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -23,21 +23,21 @@ static const struct wiphy_wowlan_support ath9k_wowlan_support = { .pattern_max_len = MAX_PATTERN_SIZE, }; -static void ath9k_wow_map_triggers(struct ath_softc *sc, - struct cfg80211_wowlan *wowlan, - u32 *wow_triggers) +static u8 ath9k_wow_map_triggers(struct ath_softc *sc, + struct cfg80211_wowlan *wowlan) { + u8 wow_triggers = 0; + if (wowlan->disconnect) - *wow_triggers |= AH_WOW_LINK_CHANGE | - AH_WOW_BEACON_MISS; + wow_triggers |= AH_WOW_LINK_CHANGE | + AH_WOW_BEACON_MISS; if (wowlan->magic_pkt) - *wow_triggers |= AH_WOW_MAGIC_PATTERN_EN; + wow_triggers |= AH_WOW_MAGIC_PATTERN_EN; if (wowlan->n_patterns) - *wow_triggers |= AH_WOW_USER_PATTERN_EN; - - sc->wow_enabled = *wow_triggers; + wow_triggers |= AH_WOW_USER_PATTERN_EN; + return wow_triggers; } static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) @@ -45,7 +45,7 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); int pattern_count = 0; - int i, byte_cnt; + int i, byte_cnt = 0; u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; u8 dis_deauth_mask[MAX_PATTERN_SIZE]; @@ -80,12 +80,7 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) * | x:x:x:x:x:x -- 22 bytes */ - /* Create Disassociate Pattern first */ - - byte_cnt = 0; - /* Fill out the mask with all FF's */ - for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++) dis_deauth_mask[i] = 0xff; @@ -108,17 +103,13 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) byte_cnt += 6; /* copy the bssid, its same as the source mac address */ - memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); /* Create Disassociate pattern mask */ - dis_deauth_mask[0] = 0xfe; dis_deauth_mask[1] = 0x03; dis_deauth_mask[2] = 0xc0; - ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n"); - ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, pattern_count, byte_cnt); @@ -131,7 +122,6 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, pattern_count, byte_cnt); - } static void ath9k_wow_add_pattern(struct ath_softc *sc, @@ -190,7 +180,7 @@ int ath9k_suspend(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - u32 wow_triggers_enabled = 0; + u8 triggers; int ret = 0; ath9k_deinit_channel_context(sc); @@ -230,14 +220,16 @@ int ath9k_suspend(struct ieee80211_hw *hw, goto fail_wow; } + triggers = ath9k_wow_map_triggers(sc, wowlan); + if (!triggers) { + ath_dbg(common, WOW, "No valid WoW triggers\n"); + ret = 1; + goto fail_wow; + } + ath_cancel_work(sc); ath_stop_ani(sc); - ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled); - - ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n", - wow_triggers_enabled); - ath9k_ps_wakeup(sc); ath9k_stop_btcoex(sc); @@ -248,7 +240,7 @@ int ath9k_suspend(struct ieee80211_hw *hw, */ ath9k_wow_add_disassoc_deauth_pattern(sc); - if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN) + if (triggers & AH_WOW_USER_PATTERN_EN) ath9k_wow_add_pattern(sc, wowlan); spin_lock_bh(&sc->sc_pcu_lock); @@ -273,12 +265,13 @@ int ath9k_suspend(struct ieee80211_hw *hw, synchronize_irq(sc->irq); tasklet_kill(&sc->intr_tq); - ath9k_hw_wow_enable(ah, wow_triggers_enabled); + ath9k_hw_wow_enable(ah, triggers); ath9k_ps_restore(sc); - ath_dbg(common, ANY, "WoW enabled in ath9k\n"); + ath_dbg(common, WOW, "Suspend with WoW triggers: 0x%x\n", triggers); atomic_inc(&sc->wow_sleep_proc_intr); + set_bit(ATH_OP_WOW_ENABLED, &common->op_flags); fail_wow: mutex_unlock(&sc->mutex); return ret; @@ -327,6 +320,8 @@ int ath9k_resume(struct ieee80211_hw *hw) ath_restart_work(sc); ath9k_start_btcoex(sc); + clear_bit(ATH_OP_WOW_ENABLED, &common->op_flags); + ath9k_ps_restore(sc); mutex_unlock(&sc->mutex); -- cgit v1.2.3 From c4d0975bba51ac339727703123cfca8034c1aeb3 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:28 +0530 Subject: ath9k: Remove unused BMISS processing The various variables tracking bmiss interrupts are not really used anywhere except in a debug message. Remove them since they have no functional purpose. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 -- drivers/net/wireless/ath/ath9k/main.c | 9 --------- drivers/net/wireless/ath/ath9k/wow.c | 18 ------------------ 3 files changed, 29 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/wow.c') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 4209d7baf1d4..803a7d4ff1b2 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -1043,8 +1043,6 @@ struct ath_softc { s16 tx99_power; #ifdef CONFIG_ATH9K_WOW - atomic_t wow_got_bmiss_intr; - atomic_t wow_sleep_proc_intr; /* in the middle of WoW sleep ? */ u32 wow_intr_before_sleep; #endif }; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9a72640237cb..98b1e4aa1506 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -556,15 +556,6 @@ irqreturn_t ath_isr(int irq, void *dev) (status & ATH9K_INT_BB_WATCHDOG)) goto chip_reset; -#ifdef CONFIG_ATH9K_WOW - if (status & ATH9K_INT_BMISS) { - if (atomic_read(&sc->wow_sleep_proc_intr) == 0) { - atomic_inc(&sc->wow_got_bmiss_intr); - atomic_dec(&sc->wow_sleep_proc_intr); - } - } -#endif - if (status & ATH9K_INT_SWBA) tasklet_schedule(&sc->bcon_tasklet); diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index c0c564de982e..fa60dbb0bf14 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -269,7 +269,6 @@ int ath9k_suspend(struct ieee80211_hw *hw, ath9k_ps_restore(sc); ath_dbg(common, WOW, "Suspend with WoW triggers: 0x%x\n", triggers); - atomic_inc(&sc->wow_sleep_proc_intr); set_bit(ATH_OP_WOW_ENABLED, &common->op_flags); fail_wow: @@ -299,19 +298,6 @@ int ath9k_resume(struct ieee80211_hw *hw) wow_status = ath9k_hw_wow_wakeup(ah); - if (atomic_read(&sc->wow_got_bmiss_intr) == 0) { - /* - * some devices may not pick beacon miss - * as the reason they woke up so we add - * that here for that shortcoming. - */ - wow_status |= AH_WOW_BEACON_MISS; - atomic_dec(&sc->wow_got_bmiss_intr); - ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep\n"); - } - - atomic_dec(&sc->wow_sleep_proc_intr); - if (wow_status) { ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n", ath9k_hw_wow_event_to_string(wow_status), wow_status); @@ -347,10 +333,6 @@ void ath9k_init_wow(struct ieee80211_hw *hw) if (sc->driver_data & ATH9K_PCI_WOW) { hw->wiphy->wowlan = &ath9k_wowlan_support; - - atomic_set(&sc->wow_sleep_proc_intr, -1); - atomic_set(&sc->wow_got_bmiss_intr, -1); - device_init_wakeup(sc->dev, 1); } } -- cgit v1.2.3 From e094c3375c5179ea30505676fd35e08568a77ee2 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:29 +0530 Subject: ath9k: Remove ath9k_hw_wow_event_to_string Printing the value of the wakeup status is sufficient. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_wow.c | 15 --------------- drivers/net/wireless/ath/ath9k/hw.h | 5 ----- drivers/net/wireless/ath/ath9k/wow.c | 10 +++------- 3 files changed, 3 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/wow.c') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c index 81c88dd606dc..3abc9073f4ac 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_wow.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_wow.c @@ -19,21 +19,6 @@ #include "reg.h" #include "hw-ops.h" -const char *ath9k_hw_wow_event_to_string(u32 wow_event) -{ - if (wow_event & AH_WOW_MAGIC_PATTERN_EN) - return "Magic pattern"; - if (wow_event & AH_WOW_USER_PATTERN_EN) - return "User pattern"; - if (wow_event & AH_WOW_LINK_CHANGE) - return "Link change"; - if (wow_event & AH_WOW_BEACON_MISS) - return "Beacon miss"; - - return "unknown reason"; -} -EXPORT_SYMBOL(ath9k_hw_wow_event_to_string); - static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index dabc94e11805..22b04222a1bd 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -1146,17 +1146,12 @@ ath9k_hw_get_btcoex_scheme(struct ath_hw *ah) #ifdef CONFIG_ATH9K_WOW -const char *ath9k_hw_wow_event_to_string(u32 wow_event); void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, u8 *user_mask, int pattern_count, int pattern_len); u32 ath9k_hw_wow_wakeup(struct ath_hw *ah); void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable); #else -static inline const char *ath9k_hw_wow_event_to_string(u32 wow_event) -{ - return NULL; -} static inline void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, u8 *user_mask, diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index fa60dbb0bf14..d4cfbc363eb5 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -281,7 +281,7 @@ int ath9k_resume(struct ieee80211_hw *hw) struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - u32 wow_status; + u8 status; mutex_lock(&sc->mutex); @@ -296,12 +296,8 @@ int ath9k_resume(struct ieee80211_hw *hw) spin_unlock_bh(&sc->sc_pcu_lock); - wow_status = ath9k_hw_wow_wakeup(ah); - - if (wow_status) { - ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n", - ath9k_hw_wow_event_to_string(wow_status), wow_status); - } + status = ath9k_hw_wow_wakeup(ah); + ath_dbg(common, WOW, "Resume with WoW status: 0x%x\n", status); ath_restart_work(sc); ath9k_start_btcoex(sc); -- cgit v1.2.3 From 8b861715087fe17796fe411eff1c7f7e493d0d10 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:30 +0530 Subject: ath9k: Add a debugfs file for WOW This can be used to force WOW for cards that are not present in the supported PCI ID list. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/debug.c | 68 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/wow.c | 4 +- 3 files changed, 71 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/wow.c') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 803a7d4ff1b2..20216c56e158 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -1044,6 +1044,7 @@ struct ath_softc { #ifdef CONFIG_ATH9K_WOW u32 wow_intr_before_sleep; + bool force_wow; #endif }; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index dd5d3914799b..50a2e0ac3b8b 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1043,6 +1043,69 @@ static const struct file_operations fops_ackto = { }; #endif +#ifdef CONFIG_ATH9K_WOW + +static ssize_t read_file_wow(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + unsigned int len = 0, size = 32; + ssize_t retval; + char *buf; + + buf = kzalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + len += scnprintf(buf + len, size - len, "WOW: %s\n", + sc->force_wow ? "ENABLED" : "DISABLED"); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static ssize_t write_file_wow(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + unsigned long val; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val != 1) + return -EINVAL; + + if (!sc->force_wow) { + sc->force_wow = true; + ath9k_init_wow(sc->hw); + } + + return count; +} + +static const struct file_operations fops_wow = { + .read = read_file_wow, + .write = write_file_wow, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +#endif + static ssize_t read_file_tpc(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1313,6 +1376,11 @@ int ath9k_init_debug(struct ath_hw *ah) &fops_btcoex); #endif +#ifdef CONFIG_ATH9K_WOW + debugfs_create_file("wow", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_wow); +#endif + #ifdef CONFIG_ATH9K_DYNACK debugfs_create_file("ack_to", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_ackto); diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index d4cfbc363eb5..4b3b56563714 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -327,7 +327,7 @@ void ath9k_init_wow(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - if (sc->driver_data & ATH9K_PCI_WOW) { + if ((sc->driver_data & ATH9K_PCI_WOW) || sc->force_wow) { hw->wiphy->wowlan = &ath9k_wowlan_support; device_init_wakeup(sc->dev, 1); } @@ -337,6 +337,6 @@ void ath9k_deinit_wow(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - if (sc->driver_data & ATH9K_PCI_WOW) + if ((sc->driver_data & ATH9K_PCI_WOW) || sc->force_wow) device_init_wakeup(sc->dev, 0); } -- cgit v1.2.3 From 34d102c921100a70d8262adc1afc09f492782778 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:31 +0530 Subject: ath9k: Simplify user pattern configuration There is no need to allocate a new structure and free it for every user pattern, instead use local variables. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ath9k.h | 6 ----- drivers/net/wireless/ath/ath9k/wow.c | 49 +++++++++------------------------- 2 files changed, 12 insertions(+), 43 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/wow.c') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 20216c56e158..0f8e9464e4ab 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -830,12 +830,6 @@ static inline void ath_fill_led_pin(struct ath_softc *sc) /* Wake on Wireless LAN */ /************************/ -struct ath9k_wow_pattern { - u8 pattern_bytes[MAX_PATTERN_SIZE]; - u8 mask_bytes[MAX_PATTERN_SIZE]; - u32 pattern_len; -}; - #ifdef CONFIG_ATH9K_WOW void ath9k_init_wow(struct ieee80211_hw *hw); void ath9k_deinit_wow(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 4b3b56563714..da52b1ffff24 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -128,50 +128,25 @@ static void ath9k_wow_add_pattern(struct ath_softc *sc, struct cfg80211_wowlan *wowlan) { struct ath_hw *ah = sc->sc_ah; - struct ath9k_wow_pattern *wow_pattern = NULL; struct cfg80211_pkt_pattern *patterns = wowlan->patterns; + u8 wow_pattern[MAX_PATTERN_SIZE]; + u8 wow_mask[MAX_PATTERN_SIZE]; int mask_len; s8 i = 0; - if (!wowlan->n_patterns) - return; - - /* - * Add the new user configured patterns - */ for (i = 0; i < wowlan->n_patterns; i++) { - - wow_pattern = kzalloc(sizeof(*wow_pattern), GFP_KERNEL); - - if (!wow_pattern) - return; - - /* - * TODO: convert the generic user space pattern to - * appropriate chip specific/802.11 pattern. - */ - - mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8); - memset(wow_pattern->pattern_bytes, 0, MAX_PATTERN_SIZE); - memset(wow_pattern->mask_bytes, 0, MAX_PATTERN_SIZE); - memcpy(wow_pattern->pattern_bytes, patterns[i].pattern, - patterns[i].pattern_len); - memcpy(wow_pattern->mask_bytes, patterns[i].mask, mask_len); - wow_pattern->pattern_len = patterns[i].pattern_len; - - /* - * just need to take care of deauth and disssoc pattern, - * make sure we don't overwrite them. - */ - - ath9k_hw_wow_apply_pattern(ah, wow_pattern->pattern_bytes, - wow_pattern->mask_bytes, + mask_len = DIV_ROUND_UP(patterns[i].pattern_len, 8); + memset(wow_pattern, 0, MAX_PATTERN_SIZE); + memset(wow_mask, 0, MAX_PATTERN_SIZE); + memcpy(wow_pattern, patterns[i].pattern, patterns[i].pattern_len); + memcpy(wow_mask, patterns[i].mask, mask_len); + + ath9k_hw_wow_apply_pattern(ah, + wow_pattern, + wow_mask, i + 2, - wow_pattern->pattern_len); - kfree(wow_pattern); - + patterns[i].pattern_len); } - } int ath9k_suspend(struct ieee80211_hw *hw, -- cgit v1.2.3 From 6af75e4da330bf7ead84566275a9b49fe471bb4d Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 30 Jan 2015 19:05:37 +0530 Subject: ath9k: Fix max pattern check Since the maximum number of configurable patterns is chip-specific, use the HW capability instead of a fixed value for checking if a free pattern slot is available. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_wow.c | 12 +++---- drivers/net/wireless/ath/ath9k/hw.h | 17 ++++----- drivers/net/wireless/ath/ath9k/wow.c | 53 ++++++++++++++++++++--------- 3 files changed, 51 insertions(+), 31 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/wow.c') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c index 6681a7b03cd0..d2a4f6f49045 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_wow.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_wow.c @@ -89,17 +89,16 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah) } -void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, - u8 *user_mask, int pattern_count, - int pattern_len) +int ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, + u8 *user_mask, int pattern_count, + int pattern_len) { int i; u32 pattern_val, mask_val; u32 set, clr; - /* FIXME: should check count by querying the hardware capability */ - if (pattern_count >= MAX_NUM_PATTERN) - return; + if (pattern_count >= ah->wow.max_patterns) + return -ENOSPC; REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count)); @@ -154,6 +153,7 @@ void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, REG_RMW(ah, AR_WOW_LENGTH2, set, clr); } + return 0; } EXPORT_SYMBOL(ath9k_hw_wow_apply_pattern); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index e1801c91d538..f51a28f0740e 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -1152,18 +1152,19 @@ ath9k_hw_get_btcoex_scheme(struct ath_hw *ah) #ifdef CONFIG_ATH9K_WOW -void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, - u8 *user_mask, int pattern_count, - int pattern_len); +int ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, + u8 *user_mask, int pattern_count, + int pattern_len); u32 ath9k_hw_wow_wakeup(struct ath_hw *ah); void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable); #else -static inline void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, - u8 *user_pattern, - u8 *user_mask, - int pattern_count, - int pattern_len) +static inline int ath9k_hw_wow_apply_pattern(struct ath_hw *ah, + u8 *user_pattern, + u8 *user_mask, + int pattern_count, + int pattern_len) { + return 0; } static inline u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) { diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index da52b1ffff24..5092939876f6 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -40,12 +40,12 @@ static u8 ath9k_wow_map_triggers(struct ath_softc *sc, return wow_triggers; } -static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) +static int ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); int pattern_count = 0; - int i, byte_cnt = 0; + int ret, i, byte_cnt = 0; u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; u8 dis_deauth_mask[MAX_PATTERN_SIZE]; @@ -110,8 +110,10 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) dis_deauth_mask[1] = 0x03; dis_deauth_mask[2] = 0xc0; - ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, - pattern_count, byte_cnt); + ret = ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, + pattern_count, byte_cnt); + if (ret) + goto exit; pattern_count++; /* @@ -120,18 +122,20 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) */ dis_deauth_pattern[0] = 0xC0; - ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, - pattern_count, byte_cnt); + ret = ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, + pattern_count, byte_cnt); +exit: + return ret; } -static void ath9k_wow_add_pattern(struct ath_softc *sc, - struct cfg80211_wowlan *wowlan) +static int ath9k_wow_add_pattern(struct ath_softc *sc, + struct cfg80211_wowlan *wowlan) { struct ath_hw *ah = sc->sc_ah; struct cfg80211_pkt_pattern *patterns = wowlan->patterns; u8 wow_pattern[MAX_PATTERN_SIZE]; u8 wow_mask[MAX_PATTERN_SIZE]; - int mask_len; + int mask_len, ret = 0; s8 i = 0; for (i = 0; i < wowlan->n_patterns; i++) { @@ -141,12 +145,16 @@ static void ath9k_wow_add_pattern(struct ath_softc *sc, memcpy(wow_pattern, patterns[i].pattern, patterns[i].pattern_len); memcpy(wow_mask, patterns[i].mask, mask_len); - ath9k_hw_wow_apply_pattern(ah, - wow_pattern, - wow_mask, - i + 2, - patterns[i].pattern_len); + ret = ath9k_hw_wow_apply_pattern(ah, + wow_pattern, + wow_mask, + i + 2, + patterns[i].pattern_len); + if (ret) + break; } + + return ret; } int ath9k_suspend(struct ieee80211_hw *hw, @@ -213,10 +221,21 @@ int ath9k_suspend(struct ieee80211_hw *hw, * Enable wake up on recieving disassoc/deauth * frame by default. */ - ath9k_wow_add_disassoc_deauth_pattern(sc); + ret = ath9k_wow_add_disassoc_deauth_pattern(sc); + if (ret) { + ath_err(common, + "Unable to add disassoc/deauth pattern: %d\n", ret); + goto fail_wow; + } - if (triggers & AH_WOW_USER_PATTERN_EN) - ath9k_wow_add_pattern(sc, wowlan); + if (triggers & AH_WOW_USER_PATTERN_EN) { + ret = ath9k_wow_add_pattern(sc, wowlan); + if (ret) { + ath_err(common, + "Unable to add user pattern: %d\n", ret); + goto fail_wow; + } + } spin_lock_bh(&sc->sc_pcu_lock); /* -- cgit v1.2.3 From e68e9c10fbe0d4e49732783aae534ba0a328887f Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 2 Feb 2015 18:21:09 +0530 Subject: ath9k: Register correct WOW details with mac80211 Since the number of user patterns is higher for newer chips, make sure that this is registered during initialization. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/wow.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath/ath9k/wow.c') diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 5092939876f6..8d0b1730a9d5 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -16,13 +16,20 @@ #include "ath9k.h" -static const struct wiphy_wowlan_support ath9k_wowlan_support = { +static const struct wiphy_wowlan_support ath9k_wowlan_support_legacy = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, .n_patterns = MAX_NUM_USER_PATTERN, .pattern_min_len = 1, .pattern_max_len = MAX_PATTERN_SIZE, }; +static const struct wiphy_wowlan_support ath9k_wowlan_support = { + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, + .n_patterns = MAX_NUM_PATTERN - 2, + .pattern_min_len = 1, + .pattern_max_len = MAX_PATTERN_SIZE, +}; + static u8 ath9k_wow_map_triggers(struct ath_softc *sc, struct cfg80211_wowlan *wowlan) { @@ -320,9 +327,14 @@ void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) void ath9k_init_wow(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; if ((sc->driver_data & ATH9K_PCI_WOW) || sc->force_wow) { - hw->wiphy->wowlan = &ath9k_wowlan_support; + if (AR_SREV_9462_20_OR_LATER(ah) || AR_SREV_9565_11_OR_LATER(ah)) + hw->wiphy->wowlan = &ath9k_wowlan_support; + else + hw->wiphy->wowlan = &ath9k_wowlan_support_legacy; + device_init_wakeup(sc->dev, 1); } } -- cgit v1.2.3