Beispiel #1
0
/*
 * This is the master bt coex work which runs for every
 * 45ms, bt traffic will be given priority during 55% of this
 * period while wlan gets remaining 45%
 */
static void ath_btcoex_period_work(struct work_struct *work)
{
	struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
						   coex_period_work.work);
	struct ath_btcoex *btcoex = &priv->btcoex;
	struct ath_common *common = ath9k_hw_common(priv->ah);
	u32 timer_period;
	bool is_btscan;
	int ret;

	ath_detect_bt_priority(priv);

	is_btscan = !!(priv->op_flags & OP_BT_SCAN);

	ret = ath9k_htc_update_cap_target(priv,
				  !!(priv->op_flags & OP_BT_PRIORITY_DETECTED));
	if (ret) {
		ath_err(common, "Unable to set BTCOEX parameters\n");
		return;
	}

	ath9k_hw_btcoex_bt_stomp(priv->ah, is_btscan ? ATH_BTCOEX_STOMP_ALL :
			btcoex->bt_stomp_type);

	timer_period = is_btscan ? btcoex->btscan_no_stomp :
		btcoex->btcoex_no_stomp;
	ieee80211_queue_delayed_work(priv->hw, &priv->duty_cycle_work,
				     msecs_to_jiffies(timer_period));
	ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work,
				     msecs_to_jiffies(btcoex->btcoex_period));
}
Beispiel #2
0
/*
 * This is the master bt coex timer which runs for every
 * 45ms, bt traffic will be given priority during 55% of this
 * period while wlan gets remaining 45%
 */
static void ath_btcoex_period_timer(unsigned long data)
{
	struct ath_softc *sc = (struct ath_softc *) data;
	struct ath_hw *ah = sc->sc_ah;
	struct ath_btcoex *btcoex = &sc->btcoex;
	u32 timer_period;
	bool is_btscan;

	ath9k_ps_wakeup(sc);
	ath_detect_bt_priority(sc);

	is_btscan = sc->sc_flags & SC_OP_BT_SCAN;

	spin_lock_bh(&btcoex->btcoex_lock);

	ath9k_hw_btcoex_bt_stomp(ah, is_btscan ? ATH_BTCOEX_STOMP_ALL :
			      btcoex->bt_stomp_type);

	spin_unlock_bh(&btcoex->btcoex_lock);

	if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) {
		if (btcoex->hw_timer_enabled)
			ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);

		timer_period = is_btscan ? btcoex->btscan_no_stomp :
					   btcoex->btcoex_no_stomp;
		ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, timer_period,
				      timer_period * 10);
		btcoex->hw_timer_enabled = true;
	}

	ath9k_ps_restore(sc);
	mod_timer(&btcoex->period_timer, jiffies +
				  msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
}
Beispiel #3
0
/*
 * Work to time slice between wlan and bt traffic and
 * configure weight registers
 */
static void ath_btcoex_duty_cycle_work(struct work_struct *work)
{
	struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
						   duty_cycle_work.work);
	struct ath_hw *ah = priv->ah;
	struct ath_btcoex *btcoex = &priv->btcoex;
	struct ath_common *common = ath9k_hw_common(ah);
	bool is_btscan = priv->op_flags & OP_BT_SCAN;

	ath_dbg(common, ATH_DBG_BTCOEX,
		"time slice work for bt and wlan\n");

	if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
		ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
	else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
		ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);
}
Beispiel #4
0
/*
 * This is the master bt coex timer which runs for every
 * 45ms, bt traffic will be given priority during 55% of this
 * period while wlan gets remaining 45%
 */
static void ath_btcoex_period_timer(unsigned long data)
{
	struct ath_softc *sc = (struct ath_softc *) data;
	struct ath_hw *ah = sc->sc_ah;
	struct ath_btcoex *btcoex = &sc->btcoex;
	struct ath_mci_profile *mci = &btcoex->mci;
	u32 timer_period;
	bool is_btscan;
	unsigned long flags;

	spin_lock_irqsave(&sc->sc_pm_lock, flags);
	if (sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP) {
		spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
		goto skip_hw_wakeup;
	}
	spin_unlock_irqrestore(&sc->sc_pm_lock, flags);

	ath9k_ps_wakeup(sc);
	if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
		ath_detect_bt_priority(sc);
	is_btscan = test_bit(BT_OP_SCAN, &btcoex->op_flags);

	btcoex->bt_wait_time += btcoex->btcoex_period;
	if (btcoex->bt_wait_time > ATH_BTCOEX_RX_WAIT_TIME) {
		if (ar9003_mci_state(ah, MCI_STATE_NEED_FTP_STOMP) &&
		    (mci->num_pan || mci->num_other_acl))
			ah->btcoex_hw.mci.stomp_ftp =
				(sc->rx.num_pkts < ATH_BTCOEX_STOMP_FTP_THRESH);
		else
			ah->btcoex_hw.mci.stomp_ftp = false;
		btcoex->bt_wait_time = 0;
		sc->rx.num_pkts = 0;
	}

	spin_lock_bh(&btcoex->btcoex_lock);

	ath9k_hw_btcoex_bt_stomp(ah, is_btscan ? ATH_BTCOEX_STOMP_ALL :
			      btcoex->bt_stomp_type);

	ath9k_hw_btcoex_enable(ah);
	spin_unlock_bh(&btcoex->btcoex_lock);

	if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) {
		if (btcoex->hw_timer_enabled)
			ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);

		timer_period = is_btscan ? btcoex->btscan_no_stomp :
					   btcoex->btcoex_no_stomp;
		ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, timer_period,
				      timer_period * 10);
		btcoex->hw_timer_enabled = true;
	}

	ath9k_ps_restore(sc);
skip_hw_wakeup:
	timer_period = btcoex->btcoex_period;
	mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(timer_period));
}
Beispiel #5
0
/*
 * This is the master bt coex timer which runs for every
 * 45ms, bt traffic will be given priority during 55% of this
 * period while wlan gets remaining 45%
 */
static void ath_btcoex_period_timer(unsigned long data)
{
    struct ath_softc *sc = (struct ath_softc *) data;
    struct ath_hw *ah = sc->sc_ah;
    struct ath_btcoex *btcoex = &sc->btcoex;
    enum ath_stomp_type stomp_type;
    u32 timer_period;
    unsigned long flags;

    spin_lock_irqsave(&sc->sc_pm_lock, flags);
    if (sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP) {
        btcoex->bt_wait_time += btcoex->btcoex_period;
        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
        goto skip_hw_wakeup;
    }
    spin_unlock_irqrestore(&sc->sc_pm_lock, flags);

    ath9k_mci_update_rssi(sc);

    ath9k_ps_wakeup(sc);

    if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
        ath_detect_bt_priority(sc);

    if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
        ath_mci_ftp_adjust(sc);

    spin_lock_bh(&btcoex->btcoex_lock);

    stomp_type = btcoex->bt_stomp_type;
    timer_period = btcoex->btcoex_no_stomp;

    if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) {
        if (test_bit(BT_OP_SCAN, &btcoex->op_flags)) {
            stomp_type = ATH_BTCOEX_STOMP_ALL;
            timer_period = btcoex->btscan_no_stomp;
        }
    } else if (btcoex->stomp_audio >= 5) {
        stomp_type = ATH_BTCOEX_STOMP_AUDIO;
        btcoex->stomp_audio = 0;
    }

    ath9k_hw_btcoex_bt_stomp(ah, stomp_type);
    ath9k_hw_btcoex_enable(ah);

    spin_unlock_bh(&btcoex->btcoex_lock);

    if (btcoex->btcoex_period != btcoex->btcoex_no_stomp)
        mod_timer(&btcoex->no_stomp_timer,
                  jiffies + msecs_to_jiffies(timer_period));

    ath9k_ps_restore(sc);

skip_hw_wakeup:
    mod_timer(&btcoex->period_timer,
              jiffies + msecs_to_jiffies(btcoex->btcoex_period));
}
Beispiel #6
0
/*
 * Generic tsf based hw timer which configures weight
 * registers to time slice between wlan and bt traffic
 */
static void ath_btcoex_no_stomp_timer(unsigned long arg)
{
	struct ath_softc *sc = (struct ath_softc *)arg;
	struct ath_hw *ah = sc->sc_ah;
	struct ath_btcoex *btcoex = &sc->btcoex;

	ath9k_ps_wakeup(sc);
	spin_lock_bh(&btcoex->btcoex_lock);

	if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW ||
	    (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI) &&
	     test_bit(BT_OP_SCAN, &btcoex->op_flags)))
		ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
	else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
		ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);

	ath9k_hw_btcoex_enable(ah);
	spin_unlock_bh(&btcoex->btcoex_lock);
	ath9k_ps_restore(sc);
}
Beispiel #7
0
/*
 * Generic tsf based hw timer which configures weight
 * registers to time slice between wlan and bt traffic
 */
static void ath_btcoex_no_stomp_timer(void *arg)
{
	struct ath_softc *sc = (struct ath_softc *)arg;
	struct ath_hw *ah = sc->sc_ah;
	struct ath_btcoex *btcoex = &sc->btcoex;
	struct ath_common *common = ath9k_hw_common(ah);
	bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN;

	ath_dbg(common, ATH_DBG_BTCOEX,
		"no stomp timer running\n");

	ath9k_ps_wakeup(sc);
	spin_lock_bh(&btcoex->btcoex_lock);

	if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
		ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
	 else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
		ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);

	spin_unlock_bh(&btcoex->btcoex_lock);
	ath9k_ps_restore(sc);
}
Beispiel #8
0
/*
 * This is the master bt coex timer which runs for every
 * 45ms, bt traffic will be given priority during 55% of this
 * period while wlan gets remaining 45%
 */
static void ath_btcoex_period_timer(unsigned long data)
{
	struct ath_softc *sc = (struct ath_softc *) data;
	struct ath_hw *ah = sc->sc_ah;
	struct ath_btcoex *btcoex = &sc->btcoex;
	enum ath_stomp_type stomp_type;
	u32 timer_period;
	unsigned long flags;

	spin_lock_irqsave(&sc->sc_pm_lock, flags);
	if (sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP) {
		btcoex->bt_wait_time += btcoex->btcoex_period;
		spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
		goto skip_hw_wakeup;
	}
	spin_unlock_irqrestore(&sc->sc_pm_lock, flags);

	ath9k_mci_update_rssi(sc);

	ath9k_ps_wakeup(sc);

	if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
		ath_detect_bt_priority(sc);

	if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
		ath_mci_ftp_adjust(sc);

	spin_lock_bh(&btcoex->btcoex_lock);

	stomp_type = btcoex->bt_stomp_type;
	timer_period = btcoex->btcoex_no_stomp;

	if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) {
		if (test_bit(BT_OP_SCAN, &btcoex->op_flags)) {
			stomp_type = ATH_BTCOEX_STOMP_ALL;
			timer_period = btcoex->btscan_no_stomp;
		}
	} else if (btcoex->stomp_audio >= 5) {
		stomp_type = ATH_BTCOEX_STOMP_AUDIO;
		btcoex->stomp_audio = 0;
	}

	ath9k_hw_btcoex_bt_stomp(ah, stomp_type);
	ath9k_hw_btcoex_enable(ah);

	spin_unlock_bh(&btcoex->btcoex_lock);

	/*
	 * btcoex_period is in msec while (btocex/btscan_)no_stomp are in usec,
	 * ensure that we properly convert btcoex_period to usec
	 * for any comparision with (btcoex/btscan_)no_stomp.
	 */
	if (btcoex->btcoex_period * 1000 != btcoex->btcoex_no_stomp) {
		if (btcoex->hw_timer_enabled)
			ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);

		ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, timer_period,
				      timer_period * 10);
		btcoex->hw_timer_enabled = true;
	}

	ath9k_ps_restore(sc);

skip_hw_wakeup:
	mod_timer(&btcoex->period_timer,
		  jiffies + msecs_to_jiffies(btcoex->btcoex_period));
}