Loading drivers/net/wireless/ath/ath9k/Makefile +2 −1 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ ath9k_htc-y += htc_hst.o \ htc_drv_txrx.o \ htc_drv_main.o \ htc_drv_beacon.o \ htc_drv_init.o htc_drv_init.o \ htc_drv_gpio.o obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o drivers/net/wireless/ath/ath9k/btcoex.c +7 −0 Original line number Diff line number Diff line Loading @@ -168,6 +168,7 @@ EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight); static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) { struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; u32 val; /* * Program coex mode and weight registers to Loading @@ -177,6 +178,12 @@ static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights); REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_hw->bt_coex_mode2); if (AR_SREV_9271(ah)) { val = REG_READ(ah, 0x50040); val &= 0xFFFFFEFF; REG_WRITE(ah, 0x50040, val); } REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); Loading drivers/net/wireless/ath/ath9k/hif_usb.c +2 −1 Original line number Diff line number Diff line Loading @@ -920,7 +920,8 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, } ret = ath9k_htc_hw_init(hif_dev->htc_handle, &hif_dev->udev->dev, hif_dev->device_id); &hif_dev->udev->dev, hif_dev->device_id, hif_dev->udev->product); if (ret) { ret = -EINVAL; goto err_htc_hw_init; Loading drivers/net/wireless/ath/ath9k/htc.h +30 −12 Original line number Diff line number Diff line Loading @@ -316,6 +316,19 @@ struct htc_beacon_config { u8 dtim_count; }; struct ath_btcoex { u32 bt_priority_cnt; unsigned long bt_priority_time; int bt_stomp_type; /* Types of BT stomping */ u32 btcoex_no_stomp; u32 btcoex_period; u32 btscan_no_stomp; }; void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv); void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv); void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv); #define OP_INVALID BIT(0) #define OP_SCANNING BIT(1) #define OP_FULL_RESET BIT(2) Loading @@ -327,6 +340,8 @@ struct htc_beacon_config { #define OP_ENABLE_BEACON BIT(8) #define OP_LED_DEINIT BIT(9) #define OP_UNPLUGGED BIT(10) #define OP_BT_PRIORITY_DETECTED BIT(11) #define OP_BT_SCAN BIT(12) struct ath9k_htc_priv { struct device *dev; Loading Loading @@ -391,6 +406,9 @@ struct ath9k_htc_priv { int cabq; int hwq_map[WME_NUM_AC]; struct ath_btcoex btcoex; struct delayed_work coex_period_work; struct delayed_work duty_cycle_work; #ifdef CONFIG_ATH9K_HTC_DEBUGFS struct ath9k_debug debug; #endif Loading Loading @@ -443,7 +461,7 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv); void ath9k_deinit_leds(struct ath9k_htc_priv *priv); int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, u16 devid); u16 devid, char *product); void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug); #ifdef CONFIG_PM int ath9k_htc_resume(struct htc_target *htc_handle); Loading drivers/net/wireless/ath/ath9k/htc_drv_gpio.c 0 → 100644 +134 −0 Original line number Diff line number Diff line #include "htc.h" /******************/ /* BTCOEX */ /******************/ /* * Detects if there is any priority bt traffic */ static void ath_detect_bt_priority(struct ath9k_htc_priv *priv) { struct ath_btcoex *btcoex = &priv->btcoex; struct ath_hw *ah = priv->ah; if (ath9k_hw_gpio_get(ah, ah->btcoex_hw.btpriority_gpio)) btcoex->bt_priority_cnt++; if (time_after(jiffies, btcoex->bt_priority_time + msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN); /* Detect if colocated bt started scanning */ if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) { ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, "BT scan detected"); priv->op_flags |= (OP_BT_SCAN | OP_BT_PRIORITY_DETECTED); } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, "BT priority traffic detected"); priv->op_flags |= OP_BT_PRIORITY_DETECTED; } btcoex->bt_priority_cnt = 0; btcoex->bt_priority_time = jiffies; } } /* * 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; u8 cmd_rsp, aggr; ath_detect_bt_priority(priv); is_btscan = !!(priv->op_flags & OP_BT_SCAN); aggr = priv->op_flags & OP_BT_PRIORITY_DETECTED; WMI_CMD_BUF(WMI_AGGR_LIMIT_CMD, &aggr); ath9k_cmn_btcoex_bt_stomp(common, 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)); } /* * 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_print(common, ATH_DBG_BTCOEX, "time slice work for bt and wlan\n"); if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan) ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE); else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW); } void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv) { struct ath_btcoex *btcoex = &priv->btcoex; btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD; btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * btcoex->btcoex_period / 100; btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) * btcoex->btcoex_period / 100; INIT_DELAYED_WORK(&priv->coex_period_work, ath_btcoex_period_work); INIT_DELAYED_WORK(&priv->duty_cycle_work, ath_btcoex_duty_cycle_work); } /* * (Re)start btcoex work */ void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv) { struct ath_btcoex *btcoex = &priv->btcoex; struct ath_hw *ah = priv->ah; ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, "Starting btcoex work"); btcoex->bt_priority_cnt = 0; btcoex->bt_priority_time = jiffies; priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN); ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work, 0); } /* * Cancel btcoex and bt duty cycle work. */ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv) { cancel_delayed_work_sync(&priv->coex_period_work); cancel_delayed_work_sync(&priv->duty_cycle_work); } Loading
drivers/net/wireless/ath/ath9k/Makefile +2 −1 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ ath9k_htc-y += htc_hst.o \ htc_drv_txrx.o \ htc_drv_main.o \ htc_drv_beacon.o \ htc_drv_init.o htc_drv_init.o \ htc_drv_gpio.o obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o
drivers/net/wireless/ath/ath9k/btcoex.c +7 −0 Original line number Diff line number Diff line Loading @@ -168,6 +168,7 @@ EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight); static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) { struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; u32 val; /* * Program coex mode and weight registers to Loading @@ -177,6 +178,12 @@ static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights); REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_hw->bt_coex_mode2); if (AR_SREV_9271(ah)) { val = REG_READ(ah, 0x50040); val &= 0xFFFFFEFF; REG_WRITE(ah, 0x50040, val); } REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); Loading
drivers/net/wireless/ath/ath9k/hif_usb.c +2 −1 Original line number Diff line number Diff line Loading @@ -920,7 +920,8 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, } ret = ath9k_htc_hw_init(hif_dev->htc_handle, &hif_dev->udev->dev, hif_dev->device_id); &hif_dev->udev->dev, hif_dev->device_id, hif_dev->udev->product); if (ret) { ret = -EINVAL; goto err_htc_hw_init; Loading
drivers/net/wireless/ath/ath9k/htc.h +30 −12 Original line number Diff line number Diff line Loading @@ -316,6 +316,19 @@ struct htc_beacon_config { u8 dtim_count; }; struct ath_btcoex { u32 bt_priority_cnt; unsigned long bt_priority_time; int bt_stomp_type; /* Types of BT stomping */ u32 btcoex_no_stomp; u32 btcoex_period; u32 btscan_no_stomp; }; void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv); void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv); void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv); #define OP_INVALID BIT(0) #define OP_SCANNING BIT(1) #define OP_FULL_RESET BIT(2) Loading @@ -327,6 +340,8 @@ struct htc_beacon_config { #define OP_ENABLE_BEACON BIT(8) #define OP_LED_DEINIT BIT(9) #define OP_UNPLUGGED BIT(10) #define OP_BT_PRIORITY_DETECTED BIT(11) #define OP_BT_SCAN BIT(12) struct ath9k_htc_priv { struct device *dev; Loading Loading @@ -391,6 +406,9 @@ struct ath9k_htc_priv { int cabq; int hwq_map[WME_NUM_AC]; struct ath_btcoex btcoex; struct delayed_work coex_period_work; struct delayed_work duty_cycle_work; #ifdef CONFIG_ATH9K_HTC_DEBUGFS struct ath9k_debug debug; #endif Loading Loading @@ -443,7 +461,7 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv); void ath9k_deinit_leds(struct ath9k_htc_priv *priv); int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, u16 devid); u16 devid, char *product); void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug); #ifdef CONFIG_PM int ath9k_htc_resume(struct htc_target *htc_handle); Loading
drivers/net/wireless/ath/ath9k/htc_drv_gpio.c 0 → 100644 +134 −0 Original line number Diff line number Diff line #include "htc.h" /******************/ /* BTCOEX */ /******************/ /* * Detects if there is any priority bt traffic */ static void ath_detect_bt_priority(struct ath9k_htc_priv *priv) { struct ath_btcoex *btcoex = &priv->btcoex; struct ath_hw *ah = priv->ah; if (ath9k_hw_gpio_get(ah, ah->btcoex_hw.btpriority_gpio)) btcoex->bt_priority_cnt++; if (time_after(jiffies, btcoex->bt_priority_time + msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN); /* Detect if colocated bt started scanning */ if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) { ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, "BT scan detected"); priv->op_flags |= (OP_BT_SCAN | OP_BT_PRIORITY_DETECTED); } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, "BT priority traffic detected"); priv->op_flags |= OP_BT_PRIORITY_DETECTED; } btcoex->bt_priority_cnt = 0; btcoex->bt_priority_time = jiffies; } } /* * 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; u8 cmd_rsp, aggr; ath_detect_bt_priority(priv); is_btscan = !!(priv->op_flags & OP_BT_SCAN); aggr = priv->op_flags & OP_BT_PRIORITY_DETECTED; WMI_CMD_BUF(WMI_AGGR_LIMIT_CMD, &aggr); ath9k_cmn_btcoex_bt_stomp(common, 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)); } /* * 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_print(common, ATH_DBG_BTCOEX, "time slice work for bt and wlan\n"); if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan) ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE); else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW); } void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv) { struct ath_btcoex *btcoex = &priv->btcoex; btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD; btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * btcoex->btcoex_period / 100; btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) * btcoex->btcoex_period / 100; INIT_DELAYED_WORK(&priv->coex_period_work, ath_btcoex_period_work); INIT_DELAYED_WORK(&priv->duty_cycle_work, ath_btcoex_duty_cycle_work); } /* * (Re)start btcoex work */ void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv) { struct ath_btcoex *btcoex = &priv->btcoex; struct ath_hw *ah = priv->ah; ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, "Starting btcoex work"); btcoex->bt_priority_cnt = 0; btcoex->bt_priority_time = jiffies; priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN); ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work, 0); } /* * Cancel btcoex and bt duty cycle work. */ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv) { cancel_delayed_work_sync(&priv->coex_period_work); cancel_delayed_work_sync(&priv->duty_cycle_work); }