From: Mohammed Shafi Shajakhan <mohammed@qca.qualcomm.com>
To: "John W. Linville" <linville@tuxdriver.com>
Cc: Mohammed Shafi Shajakhan <mohammed@qca.qualcomm.com>,
<linux-wireless@vger.kernel.org>,
Rodriguez Luis <rodrigue@qca.qualcomm.com>,
<ath9k-devel@lists.ath9k.org>,
Rajkumar Manoharan <rmanohar@qca.qualcomm.com>,
Sujith Manoharan <c_manoha@qca.qualcomm.com>,
Bala Shanmugam <bkamatch@qca.qualcomm.com>,
<vadivel@qca.qualcomm.com>, <rhu@qca.qualcomm.com>,
Senthil Balasubramanian <senthilb@qca.qualcomm.com>
Subject: Re: [PATCH v2 09/10] ath9k: Add WoW related mac80211 callbacks
Date: Mon, 25 Jun 2012 16:28:00 +0530 [thread overview]
Message-ID: <4FE84438.1040007@qca.qualcomm.com> (raw)
In-Reply-To: <1340467194-16930-10-git-send-email-mohammed@qca.qualcomm.com>
Hi John,
please wait, i will send a v3 for this. i missed something while
rebasing with the latest wireless-testing.
On Saturday 23 June 2012 09:29 PM, Mohammed Shafi Shajakhan wrote:
> From: Mohammed Shafi Shajakhan<mohammed@qca.qualcomm.com>
>
> add suspend/resume/set_wakeup callbacks to the driver
>
> *suspend
>
> - bail out only if all the conditions for configuring WoW.
> is fine, currently multivif case is not handled
> - check for associated state.
> - map wow triggers from user space data.
> - add deauth/disassoc pattern and user defined pattern,
> for the later a list is maintained.
> - store the interrupt mask before suspend, enabled beacon
> miss interrupt for WoW.
> - configure WoW in the hardware by calling ath9k_hw_wow_enable.
>
> *resume
>
> - restore the interrupts based on the interrupt mask
> stored before suspend.
> - call ath9k_hw_wow_wakeup to configure/restore the hardware.
> - after wow wakeup clear away WoW events and query the
> WoW wakeup reason from the status register
>
> *set_wakeup
>
> - to call 'device_set_wakeup_enable' from cfg80211/mac80211
> when wow is configured and as per Rafael/Johannnes the
> right way to do so rather in the driver suspend/resume
> call back
>
> Cc: Senthil Balasubramanian<senthilb@qca.qualcomm.com>
> Cc: Rajkumar Manoharan<rmanohar@qca.qualcomm.com>
> Cc: vadivel@qca.qualcomm.com
> Signed-off-by: Mohammed Shafi Shajakhan<mohammed@qca.qualcomm.com>
> ---
> drivers/net/wireless/ath/ath9k/ath9k.h | 9 +
> drivers/net/wireless/ath/ath9k/init.c | 1 +
> drivers/net/wireless/ath/ath9k/main.c | 389 ++++++++++++++++++++++++++++++++
> 3 files changed, 399 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
> index 4c530e5..43de1e1 100644
> --- a/drivers/net/wireless/ath/ath9k/ath9k.h
> +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
> @@ -518,6 +518,14 @@ struct ath9k_wow_info {
> struct list_head wow_patterns;
> };
>
> +#ifdef CONFIG_PM_SLEEP
> +void ath_wow_cleanup(struct ath_softc *sc);
> +#else
> +static inline void ath_wow_cleanup(struct ath_softc *sc)
> +{
> +}
> +#endif
> +
> /********************/
> /* LED Control */
> /********************/
> @@ -719,6 +727,7 @@ struct ath_softc {
> struct ath_ant_comb ant_comb;
> u8 ant_tx, ant_rx;
> struct dfs_pattern_detector *dfs_detector;
> + u32 wow_enabled;
>
> #ifdef CONFIG_PM_SLEEP
> bool wow_got_bmiss_intr;
> diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
> index 576f808..a5a4794 100644
> --- a/drivers/net/wireless/ath/ath9k/init.c
> +++ b/drivers/net/wireless/ath/ath9k/init.c
> @@ -885,6 +885,7 @@ void ath9k_deinit_device(struct ath_softc *sc)
> ath9k_ps_restore(sc);
>
> ieee80211_unregister_hw(hw);
> + ath_wow_cleanup(sc);
> ath_rx_cleanup(sc);
> ath_tx_cleanup(sc);
> ath9k_deinit_softc(sc);
> diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
> index 85f9ab4..3029b1c 100644
> --- a/drivers/net/wireless/ath/ath9k/main.c
> +++ b/drivers/net/wireless/ath/ath9k/main.c
> @@ -486,6 +486,17 @@ irqreturn_t ath_isr(int irq, void *dev)
> if (status& SCHED_INTR)
> sched = true;
>
> +#ifdef CONFIG_PM_SLEEP
> + if (status& ATH9K_INT_BMISS) {
> + if (sc->wow_sleep_proc_intr) {
> + ath_dbg(common, ANY, "during WoW we got a BMISS\n");
> + sc->wow_got_bmiss_intr = true;
> + sc->wow_sleep_proc_intr = false;
> + }
> + ath_dbg(common, INTERRUPT, "beacon miss interrupt\n");
> + }
> +#endif
> +
> /*
> * If a FATAL or RXORN interrupt is received, we have to reset the
> * chip immediately.
> @@ -2069,6 +2080,378 @@ static void ath9k_get_et_stats(struct ieee80211_hw *hw,
> #endif
>
>
> +#ifdef CONFIG_PM_SLEEP
> +
> +void ath_wow_cleanup(struct ath_softc *sc)
> +{
> + struct ath9k_wow_info *wow_info =&sc->wow_info;
> + struct ath9k_wow_pattern *wow_pattern = NULL, *tmp;
> +
> + if (!(sc->wow_enabled& AH_WOW_USER_PATTERN_EN))
> + return;
> +
> + list_for_each_entry_safe(wow_pattern, tmp,
> + &wow_info->wow_patterns, list) {
> +
> + list_del(&wow_pattern->list);
> + kfree(wow_pattern);
> + }
> +
> +}
> +
> +static void ath9k_wow_map_triggers(struct ath_softc *sc,
> + struct cfg80211_wowlan *wowlan,
> + u32 *wow_triggers)
> +{
> + if (wowlan->disconnect)
> + *wow_triggers |= AH_WOW_LINK_CHANGE |
> + AH_WOW_BEACON_MISS;
> + if (wowlan->magic_pkt)
> + *wow_triggers |= AH_WOW_MAGIC_PATTERN_EN;
> +
> + if (wowlan->n_patterns)
> + *wow_triggers |= AH_WOW_USER_PATTERN_EN;
> +
> + sc->wow_enabled = *wow_triggers;
> +
> +}
> +
> +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);
> + struct ath9k_hw_capabilities *pcaps =&ah->caps;
> + int pattern_count = 0;
> + int i, byte_cnt;
> + u8 dis_deauth_pattern[MAX_PATTERN_SIZE];
> + u8 dis_deauth_mask[MAX_PATTERN_SIZE];
> +
> + memset(dis_deauth_pattern, 0, MAX_PATTERN_SIZE);
> + memset(dis_deauth_mask, 0, MAX_PATTERN_SIZE);
> +
> + /*
> + * Create Dissassociate / Deauthenticate packet filter
> + *
> + * 2 bytes 2 byte 6 bytes 6 bytes 6 bytes
> + * +--------------+----------+---------+--------+--------+----
> + * + Frame Control+ Duration + DA + SA + BSSID +
> + * +--------------+----------+---------+--------+--------+----
> + *
> + * The above is the management frame format for disassociate/
> + * deauthenticate pattern, from this we need to match the first byte
> + * of 'Frame Control' and DA, SA, and BSSID fields
> + * (skipping 2nd byte of FC and Duration feild.
> + *
> + * Disassociate pattern
> + * --------------------
> + * Frame control = 00 00 1010
> + * DA, SA, BSSID = x:x:x:x:x:x
> + * Pattern will be A0000000 | x:x:x:x:x:x | x:x:x:x:x:x
> + * | x:x:x:x:x:x -- 22 bytes
> + *
> + * Deauthenticate pattern
> + * ----------------------
> + * Frame control = 00 00 1100
> + * DA, SA, BSSID = x:x:x:x:x:x
> + * Pattern will be C0000000 | x:x:x:x:x:x | x:x:x:x:x:x
> + * | 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;
> +
> + /* copy the first byte of frame control field */
> + dis_deauth_pattern[byte_cnt] = 0xa0;
> + byte_cnt++;
> +
> + /* skip 2nd byte of frame control and Duration field */
> + byte_cnt += 3;
> +
> + /*
> + * need not match the destination mac address, it can be a broadcast
> + * mac address or an unicast to this station
> + */
> + byte_cnt += 6;
> +
> + /* copy the source mac address */
> + memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
> +
> + 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 */
> +
> + if (pcaps->hw_caps& ATH9K_HW_WOW_PATTERN_MATCH_EXACT) {
> +
> + if (pcaps->hw_caps& ATH9K_HW_WOW_PATTERN_MATCH_DWORD) {
> + /*
> + * for AR9280, because of hardware limitation, the
> + * first 4 bytes have to be matched for all patterns.
> + * the mask for disassociation and de-auth pattern
> + * matching need to enable the first 4 bytes.
> + * also the duration field needs to be filled.
> + */
> + dis_deauth_mask[0] = 0xf0;
> +
> + /*
> + * fill in duration field
> + FIXME: what is the exact value ?
> + */
> + dis_deauth_pattern[2] = 0xff;
> + dis_deauth_pattern[3] = 0xff;
> + } else {
> + dis_deauth_mask[0] = 0xfe;
> + }
> +
> + dis_deauth_mask[1] = 0x03;
> + dis_deauth_mask[2] = 0xc0;
> + } else {
> + dis_deauth_mask[0] = 0xef;
> + dis_deauth_mask[1] = 0x3f;
> + dis_deauth_mask[2] = 0x00;
> + dis_deauth_mask[3] = 0xfc;
> + }
> +
> + 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);
> +
> + pattern_count++;
> + /*
> + * for de-authenticate pattern, only the first byte of the frame
> + * control field gets changed from 0xA0 to 0xC0
> + */
> + dis_deauth_pattern[0] = 0xC0;
> +
> + 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,
> + struct cfg80211_wowlan *wowlan)
> +{
> + struct ath_hw *ah = sc->sc_ah;
> + struct ath9k_wow_info *wow_info =&sc->wow_info;
> + struct ath9k_wow_pattern *wow_pattern = NULL;
> + struct cfg80211_wowlan_trig_pkt_pattern *patterns = wowlan->patterns;
> + int mask_len;
> + s8 i = 0;
> +
> + if (!wowlan->n_patterns)
> + return;
> +
> + /*
> + * Clear existing WoW patterns.
> + */
> + ath_wow_cleanup(sc);
> +
> + /*
> + * 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;
> +
> + 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;
> +
> + list_add_tail(&wow_pattern->list,&wow_info->wow_patterns);
> + wow_info->num_of_patterns = i + 2;
> + /*
> + * 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,
> + wow_info->num_of_patterns,
> + wow_pattern->pattern_len);
> +
> + }
> +
> +}
> +
> +static int ath9k_suspend(struct ieee80211_hw *hw,
> + struct cfg80211_wowlan *wowlan)
> +{
> + 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;
> + int ret = 0;
> +
> + mutex_lock(&sc->mutex);
> +
> + ath_cancel_work(sc);
> + del_timer_sync(&common->ani.timer);
> + del_timer_sync(&sc->rx_poll_timer);
> +
> + if (test_bit(SC_OP_INVALID,&sc->sc_flags)) {
> + ath_dbg(common, ANY, "Device not present\n");
> + ret = -EINVAL;
> + goto fail_wow;
> + }
> +
> + if (WARN_ON(!wowlan)) {
> + ath_dbg(common, WOW, "None of the WoW triggers enabled\n");
> + ret = -EINVAL;
> + goto fail_wow;
> + }
> +
> + 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
> + * cases, for instance we have to seperately
> + * configure 'keep alive frame' for each
> + * STA.
> + */
> + if (!(sc->sc_flags& SC_OP_PRIM_STA_VIF)) {
the above should be if (!test_bit(SC_OP_PRIM_STA_VIF,
&sc->sc_flags)).sorry i missed it in re-basing with the latest
wireless-testing, quite tricky nothing complained.just found it was
broken due to this :(
> + ath_dbg(common, WOW, "None of the STA vifs are associated\n");
> + ret = 1;
> + goto fail_wow;
> + }
> +
> + if (sc->nvifs> 1) {
> + ath_dbg(common, WOW, "WoW for multivif is not yet supported\n");
> + ret = 1;
> + goto fail_wow;
> + }
> +
> + 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);
> +
> + /*
> + * Enable wake up on recieving disassoc/deauth
> + * frame by default.
> + */
> + ath9k_wow_add_disassoc_deauth_pattern(sc);
> +
> + if (wow_triggers_enabled& AH_WOW_USER_PATTERN_EN)
> + ath9k_wow_add_pattern(sc, wowlan);
> +
> + spin_lock_bh(&sc->sc_pcu_lock);
> + /*
> + * To avoid false wake, we enable beacon miss interrupt only
> + * when we go to sleep. We save the current interrupt mask
> + * so we can restore it after the system wakes up
> + */
> + sc->wow_intr_before_sleep = ah->imask;
> + ah->imask&= ~ATH9K_INT_GLOBAL;
> + ath9k_hw_disable_interrupts(ah);
> + ah->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL;
> + ath9k_hw_set_interrupts(ah);
> + ath9k_hw_enable_interrupts(ah);
> +
> + spin_unlock_bh(&sc->sc_pcu_lock);
> +
> + /*
> + * we can now sync irq and kill any running tasklets, since we already
> + * disabled interrupts and not holding a spin lock
> + */
> + synchronize_irq(sc->irq);
> + tasklet_kill(&sc->intr_tq);
> +
> + ath9k_hw_wow_enable(ah, wow_triggers_enabled);
> +
> + ath9k_ps_restore(sc);
> + ath_dbg(common, ANY, "WoW enabled in ath9k\n");
> + sc->wow_sleep_proc_intr = true;
> +
> +fail_wow:
> + mutex_unlock(&sc->mutex);
> + return ret;
> +}
> +
> +static 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;
> +
> + mutex_lock(&sc->mutex);
> +
> + ath9k_ps_wakeup(sc);
> +
> + spin_lock_bh(&sc->sc_pcu_lock);
> +
> + ath9k_hw_disable_interrupts(ah);
> + ah->imask = sc->wow_intr_before_sleep;
> + ath9k_hw_set_interrupts(ah);
> + ath9k_hw_enable_interrupts(ah);
> +
> + spin_unlock_bh(&sc->sc_pcu_lock);
> +
> + wow_status = ath9k_hw_wow_wakeup(ah);
> +
> + if (sc->wow_got_bmiss_intr) {
> + /*
> + * 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;
> + sc->wow_got_bmiss_intr = false;
> + ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep");
> + }
> +
> + 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);
> + }
> +
> + ath_restart_work(sc);
> + ath9k_start_btcoex(sc);
> +
> + ath9k_ps_restore(sc);
> + mutex_unlock(&sc->mutex);
> +
> + return 0;
> +}
> +
> +static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)
> +{
> + struct ath_softc *sc = hw->priv;
> +
> + mutex_lock(&sc->mutex);
> + device_init_wakeup(sc->dev, 1);
> + device_set_wakeup_enable(sc->dev, enabled);
> + mutex_unlock(&sc->mutex);
> +}
> +
> +#endif
> +
> struct ieee80211_ops ath9k_ops = {
> .tx = ath9k_tx,
> .start = ath9k_start,
> @@ -2098,6 +2481,12 @@ struct ieee80211_ops ath9k_ops = {
> .set_antenna = ath9k_set_antenna,
> .get_antenna = ath9k_get_antenna,
>
> +#ifdef CONFIG_PM_SLEEP
> + .suspend = ath9k_suspend,
> + .resume = ath9k_resume,
> + .set_wakeup = ath9k_set_wakeup,
> +#endif
> +
> #ifdef CONFIG_ATH9K_DEBUGFS
> .get_et_sset_count = ath9k_get_et_sset_count,
> .get_et_stats = ath9k_get_et_stats,
--
thanks,
shafi
next prev parent reply other threads:[~2012-06-25 10:58 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-06-23 15:59 [PATCH v2 00/10] Add support for WOW in ath9k Mohammed Shafi Shajakhan
2012-06-23 15:59 ` [PATCH v2 01/10] ath9k_hw: Add register definitions for WoW support Mohammed Shafi Shajakhan
2012-06-23 15:59 ` [PATCH v2 02/10] ath9k: Add definitions and structures to support WoW Mohammed Shafi Shajakhan
2012-06-23 15:59 ` [PATCH v2 03/10] ath9k_hw: Add WoW hardware capability flags Mohammed Shafi Shajakhan
2012-06-23 15:59 ` [PATCH v2 04/10] ath9k_hw: advertise WoW support for capable chipsets Mohammed Shafi Shajakhan
2012-06-23 15:59 ` [PATCH v2 05/10] ath9k: advertise supported WoW flags to upper layer Mohammed Shafi Shajakhan
2012-06-23 15:59 ` [PATCH v2 06/10] ath9k_hw: INI changes for WoW for AR9002 chipsets Mohammed Shafi Shajakhan
2012-06-23 15:59 ` [PATCH v2 07/10] ath9k_hw: Add hardware code for WoW Mohammed Shafi Shajakhan
2012-06-23 15:59 ` [PATCH v2 08/10] ath: Add Wake-on-Wireless debug mask Mohammed Shafi Shajakhan
2012-06-23 15:59 ` [PATCH v2 09/10] ath9k: Add WoW related mac80211 callbacks Mohammed Shafi Shajakhan
2012-06-25 10:58 ` Mohammed Shafi Shajakhan [this message]
2012-06-23 15:59 ` [PATCH v2 10/10] ath9k: do not disable hardware while wow is enabled Mohammed Shafi Shajakhan
2012-06-25 11:04 ` [PATCH v2 00/10] Add support for WOW in ath9k Mohammed Shafi Shajakhan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4FE84438.1040007@qca.qualcomm.com \
--to=mohammed@qca.qualcomm.com \
--cc=ath9k-devel@lists.ath9k.org \
--cc=bkamatch@qca.qualcomm.com \
--cc=c_manoha@qca.qualcomm.com \
--cc=linux-wireless@vger.kernel.org \
--cc=linville@tuxdriver.com \
--cc=rhu@qca.qualcomm.com \
--cc=rmanohar@qca.qualcomm.com \
--cc=rodrigue@qca.qualcomm.com \
--cc=senthilb@qca.qualcomm.com \
--cc=vadivel@qca.qualcomm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).