From 987cdcba62da369d41f61bb1026d40d670c4efe6 Mon Sep 17 00:00:00 2001 From: Julien Massot Date: Mon, 6 Jan 2014 19:52:47 +0100 Subject: [PATCH 001/414] ath6kl: increase usb rx buffer size to 4096 With the previous value (1700), some urb are dropped with a babble error (urb status equal -EOVERFLOW). These error seems to only happen when urb length is a multiple of packet size (512). Signed-off-by: Julien Massot Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index f38ff6a6255e..bbaf867c7d14 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -24,7 +24,7 @@ /* constants */ #define TX_URB_COUNT 32 #define RX_URB_COUNT 32 -#define ATH6KL_USB_RX_BUFFER_SIZE 1700 +#define ATH6KL_USB_RX_BUFFER_SIZE 4096 /* tx/rx pipes for usb */ enum ATH6KL_USB_PIPE_ID { From 61118fbf5ba01a88d7f7b2210f44b6278f4a597f Mon Sep 17 00:00:00 2001 From: Julien Massot Date: Mon, 6 Jan 2014 19:52:48 +0100 Subject: [PATCH 002/414] ath6kl: set rx urb count threshold to 1 Reduce the Rx count threshold to make sure we read the available credits for Tx. Signed-off-by: Julien Massot Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index bbaf867c7d14..56c3fd5cef65 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -481,8 +481,8 @@ static void ath6kl_usb_start_recv_pipes(struct ath6kl_usb *ar_usb) * ATH6KL_USB_RX_BUFFER_SIZE); */ - ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh = - ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_alloc / 2; + ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh = 1; + ath6kl_usb_post_recv_transfers(&ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA], ATH6KL_USB_RX_BUFFER_SIZE); } From 542fb17400a752c4be2e221857a42f35acc1a1cc Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Fri, 17 Jan 2014 14:08:08 +0100 Subject: [PATCH 003/414] ath10k: enable wmi ps peer param command for 10.x FW Enable ap_ps_peer_param_cmdid for 10.x FW. This is used mainly for AP UAPSD. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 712a606a080a..f49a84276b9b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -213,7 +213,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = { .p2p_go_set_beacon_ie = WMI_10X_P2P_GO_SET_BEACON_IE, .p2p_go_set_probe_resp_ie = WMI_10X_P2P_GO_SET_PROBE_RESP_IE, .p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED, - .ap_ps_peer_param_cmdid = WMI_CMD_UNSUPPORTED, + .ap_ps_peer_param_cmdid = WMI_10X_AP_PS_PEER_PARAM_CMDID, .ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED, .peer_rate_retry_sched_cmdid = WMI_10X_PEER_RATE_RETRY_SCHED_CMDID, .wlan_profile_trigger_cmdid = WMI_10X_WLAN_PROFILE_TRIGGER_CMDID, From 5a13e76eca17212c0a4ad3c1fb97df8a9e9921d8 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 20 Jan 2014 11:01:46 +0200 Subject: [PATCH 004/414] ath10k: enable firmware STA quick kickout Firmware has a feature to track if the associated STA is not acking the frames. When that happens, the firmware sends WMI_PEER_STA_KICKOUT_EVENTID event to the host. Enable that to faster detect when a STA has left BSS without sending a deauth frame. Also set huge keepalive timeouts to avoid using the keepalive functionality in the firmware. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 12 ++++++ drivers/net/wireless/ath/ath10k/mac.c | 58 ++++++++++++++++++++++---- drivers/net/wireless/ath/ath10k/wmi.c | 22 +++++++++- drivers/net/wireless/ath/ath10k/wmi.h | 4 ++ 4 files changed, 88 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index ade1781c7186..e6308f420a5c 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -46,6 +46,18 @@ #define ATH10K_MAX_NUM_MGMT_PENDING 128 +/* number of failed packets */ +#define ATH10K_KICKOUT_THRESHOLD 50 + +/* + * Use insanely high numbers to make sure that the firmware implementation + * won't start, we have the same functionality already in hostapd. Unit + * is seconds. + */ +#define ATH10K_KEEPALIVE_MIN_IDLE 3747 +#define ATH10K_KEEPALIVE_MAX_IDLE 3895 +#define ATH10K_KEEPALIVE_MAX_UNRESPONSIVE 3900 + struct ath10k; struct ath10k_skb_cb { diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 776e364eadcd..5269cf8f2d78 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -339,6 +339,50 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr) return 0; } +static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + u32 param; + int ret; + + param = ar->wmi.pdev_param->sta_kickout_th; + ret = ath10k_wmi_pdev_set_param(ar, param, + ATH10K_KICKOUT_THRESHOLD); + if (ret) { + ath10k_warn("Failed to set kickout threshold: %d\n", ret); + return ret; + } + + param = ar->wmi.vdev_param->ap_keepalive_min_idle_inactive_time_secs; + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, + ATH10K_KEEPALIVE_MIN_IDLE); + if (ret) { + ath10k_warn("Failed to set keepalive minimum idle time : %d\n", + ret); + return ret; + } + + param = ar->wmi.vdev_param->ap_keepalive_max_idle_inactive_time_secs; + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, + ATH10K_KEEPALIVE_MAX_IDLE); + if (ret) { + ath10k_warn("Failed to set keepalive maximum idle time: %d\n", + ret); + return ret; + } + + param = ar->wmi.vdev_param->ap_keepalive_max_unresponsive_time_secs; + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, + ATH10K_KEEPALIVE_MAX_UNRESPONSIVE); + if (ret) { + ath10k_warn("Failed to set keepalive maximum unresponsive time: %d\n", + ret); + return ret; + } + + return 0; +} + static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value) { struct ath10k *ar = arvif->ar; @@ -2214,7 +2258,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); enum wmi_sta_powersave_param param; int ret = 0; - u32 value, param_id; + u32 value; int bit; u32 vdev_param; @@ -2307,12 +2351,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, goto err_vdev_delete; } - param_id = ar->wmi.pdev_param->sta_kickout_th; - - /* Disable STA KICKOUT functionality in FW */ - ret = ath10k_wmi_pdev_set_param(ar, param_id, 0); - if (ret) - ath10k_warn("Failed to disable STA KICKOUT\n"); + ret = ath10k_mac_set_kickout(arvif); + if (ret) { + ath10k_warn("Failed to set kickout parameters: %d\n", + ret); + goto err_peer_delete; + } } if (arvif->vdev_type == WMI_VDEV_TYPE_STA) { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index f49a84276b9b..f0969cd8350f 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1116,7 +1116,27 @@ static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb) { - ath10k_dbg(ATH10K_DBG_WMI, "WMI_PEER_STA_KICKOUT_EVENTID\n"); + struct wmi_peer_sta_kickout_event *ev; + struct ieee80211_sta *sta; + + ev = (struct wmi_peer_sta_kickout_event *)skb->data; + + ath10k_dbg(ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n", + ev->peer_macaddr.addr); + + rcu_read_lock(); + + sta = ieee80211_find_sta_by_ifaddr(ar->hw, ev->peer_macaddr.addr, NULL); + if (!sta) { + ath10k_warn("Spurious quick kickout for STA %pM\n", + ev->peer_macaddr.addr); + goto exit; + } + + ieee80211_report_low_ack(sta, 10); + +exit: + rcu_read_unlock(); } /* diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 4b5e7d3d32b6..9dc90c5dd0e4 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4039,6 +4039,10 @@ struct wmi_chan_info_event { __le32 cycle_count; } __packed; +struct wmi_peer_sta_kickout_event { + struct wmi_mac_addr peer_macaddr; +} __packed; + #define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0) /* FIXME: empirically extrapolated */ From d3d3ff42d9b3a8b90b381ebb398deb5c87ec1692 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Tue, 21 Jan 2014 07:06:53 +0100 Subject: [PATCH 005/414] ath10k: AP mode, set UAPSD params correctly ath10k handles UAPSD completly in the firmware. When works in AP mode we have to configure UAPSD params for each station. Without this patch we configure UAPSD params before we send peer assoc command to the FW, which was wrong. Next FW didn't know what should be trigger frame, couse UAPSD didn't work correctly in AP mode. To configure UAPSD params correctly we have to send them after peer assoc command. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 80 +++++++++++++++------------ 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 5269cf8f2d78..bff0871fa6bd 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1136,27 +1136,20 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, arg->peer_num_spatial_streams); } -static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar, - struct ath10k_vif *arvif, - struct ieee80211_sta *sta, - struct ieee80211_bss_conf *bss_conf, - struct wmi_peer_assoc_complete_arg *arg) +static int ath10k_peer_assoc_qos_ap(struct ath10k *ar, + struct ath10k_vif *arvif, + struct ieee80211_sta *sta) { u32 uapsd = 0; u32 max_sp = 0; + int ret = 0; lockdep_assert_held(&ar->conf_mutex); - if (sta->wme) - arg->peer_flags |= WMI_PEER_QOS; - if (sta->wme && sta->uapsd_queues) { ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n", sta->uapsd_queues, sta->max_sp); - arg->peer_flags |= WMI_PEER_APSD; - arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG; - if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN | WMI_AP_PS_UAPSD_AC3_TRIGGER_EN; @@ -1174,35 +1167,40 @@ static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar, if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP) max_sp = sta->max_sp; - ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, - sta->addr, - WMI_AP_PS_PEER_PARAM_UAPSD, - uapsd); + ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, + sta->addr, + WMI_AP_PS_PEER_PARAM_UAPSD, + uapsd); + if (ret) { + ath10k_warn("failed to set ap ps peer param uapsd: %d\n", + ret); + return ret; + } - ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, - sta->addr, - WMI_AP_PS_PEER_PARAM_MAX_SP, - max_sp); + ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, + sta->addr, + WMI_AP_PS_PEER_PARAM_MAX_SP, + max_sp); + if (ret) { + ath10k_warn("failed to set ap ps peer param max sp: %d\n", + ret); + return ret; + } /* TODO setup this based on STA listen interval and beacon interval. Currently we don't know sta->listen_interval - mac80211 patch required. Currently use 10 seconds */ - ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, - sta->addr, - WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, - 10); + ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr, + WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 10); + if (ret) { + ath10k_warn("failed to set ap ps peer param ageout time: %d\n", + ret); + return ret; + } } -} -static void ath10k_peer_assoc_h_qos_sta(struct ath10k *ar, - struct ath10k_vif *arvif, - struct ieee80211_sta *sta, - struct ieee80211_bss_conf *bss_conf, - struct wmi_peer_assoc_complete_arg *arg) -{ - if (bss_conf->qos) - arg->peer_flags |= WMI_PEER_QOS; + return 0; } static void ath10k_peer_assoc_h_vht(struct ath10k *ar, @@ -1255,10 +1253,17 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar, { switch (arvif->vdev_type) { case WMI_VDEV_TYPE_AP: - ath10k_peer_assoc_h_qos_ap(ar, arvif, sta, bss_conf, arg); + if (sta->wme) + arg->peer_flags |= WMI_PEER_QOS; + + if (sta->wme && sta->uapsd_queues) { + arg->peer_flags |= WMI_PEER_APSD; + arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG; + } break; case WMI_VDEV_TYPE_STA: - ath10k_peer_assoc_h_qos_sta(ar, arvif, sta, bss_conf, arg); + if (bss_conf->qos) + arg->peer_flags |= WMI_PEER_QOS; break; default: break; @@ -1456,6 +1461,13 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, return ret; } + ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta); + if (ret) { + ath10k_warn("could not set qos params for STA %pM, %d\n", + sta->addr, ret); + return ret; + } + return ret; } From 5ba88b395cb447af756d12411456024d65a07814 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Tue, 21 Jan 2014 17:21:21 +0800 Subject: [PATCH 006/414] ath10k: fix the printing of 10.x FW version when FW crashed 10.x FW has no structure member sw_version_1. Thus, both fw_version_release and fw_version_build are not available. The provided fw_version_major is also wrong. Fix this by using the fw_version from struct wiphy. Signed-off-by: Chun-Yeow Yeoh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 29fd197d1fd8..9179c88007d1 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -833,9 +833,7 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar) ath10k_err("firmware crashed!\n"); ath10k_err("hardware name %s version 0x%x\n", ar->hw_params.name, ar->target_version); - ath10k_err("firmware version: %u.%u.%u.%u\n", ar->fw_version_major, - ar->fw_version_minor, ar->fw_version_release, - ar->fw_version_build); + ath10k_err("firmware version: %s\n", ar->hw->wiphy->fw_version); host_addr = host_interest_item_address(HI_ITEM(hi_failure_state)); ret = ath10k_pci_diag_read_mem(ar, host_addr, From c930f744bdb0774ccf7c00e23637f54b8e71f0b6 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 23 Jan 2014 11:38:25 +0100 Subject: [PATCH 007/414] ath10k: implement channel switching Until now channel change wasn't propagating to FW directly because operational channel is abstracted by VDEVs and it wasn't really necessary since ath10k implements hwscan and hwroc. This effectively fixes STA CSA and allows for future AP-like CSA as well. kvalo: change error handling in ath10k_bss_info_changed() Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 12 +- drivers/net/wireless/ath/ath10k/mac.c | 174 +++++++++++++++++++++---- 2 files changed, 156 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index e6308f420a5c..8b145209d37d 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -238,6 +238,11 @@ struct ath10k_vif { struct ath10k *ar; struct ieee80211_vif *vif; + bool is_started; + bool is_up; + u32 aid; + u8 bssid[ETH_ALEN]; + struct work_struct wep_key_work; struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1]; u8 def_wep_key_idx; @@ -247,7 +252,6 @@ struct ath10k_vif { union { struct { - u8 bssid[ETH_ALEN]; u32 uapsd; } sta; struct { @@ -261,9 +265,6 @@ struct ath10k_vif { u32 noa_len; u8 *noa_data; } ap; - struct { - u8 bssid[ETH_ALEN]; - } ibss; } u; u8 fixed_rate; @@ -424,6 +425,9 @@ struct ath10k { /* valid during scan; needed for mgmt rx during scan */ struct ieee80211_channel *scan_channel; + /* current operating channel definition */ + struct cfg80211_chan_def chandef; + int free_vdev_map; int monitor_vdev_id; bool monitor_enabled; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index bff0871fa6bd..8fe451796fde 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -488,8 +488,7 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar) static int ath10k_vdev_start(struct ath10k_vif *arvif) { struct ath10k *ar = arvif->ar; - struct ieee80211_conf *conf = &ar->hw->conf; - struct ieee80211_channel *channel = conf->chandef.chan; + struct cfg80211_chan_def *chandef = &ar->chandef; struct wmi_vdev_start_request_arg arg = {}; int ret = 0; @@ -501,16 +500,14 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif) arg.dtim_period = arvif->dtim_period; arg.bcn_intval = arvif->beacon_interval; - arg.channel.freq = channel->center_freq; - - arg.channel.band_center_freq1 = conf->chandef.center_freq1; - - arg.channel.mode = chan_to_phymode(&conf->chandef); + arg.channel.freq = chandef->chan->center_freq; + arg.channel.band_center_freq1 = chandef->center_freq1; + arg.channel.mode = chan_to_phymode(chandef); arg.channel.min_power = 0; - arg.channel.max_power = channel->max_power * 2; - arg.channel.max_reg_power = channel->max_reg_power * 2; - arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; + arg.channel.max_power = chandef->chan->max_power * 2; + arg.channel.max_reg_power = chandef->chan->max_reg_power * 2; + arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2; if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { arg.ssid = arvif->u.ap.ssid; @@ -519,7 +516,7 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif) /* For now allow DFS for AP mode */ arg.channel.chan_radar = - !!(channel->flags & IEEE80211_CHAN_RADAR); + !!(chandef->chan->flags & IEEE80211_CHAN_RADAR); } else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { arg.ssid = arvif->vif->bss_conf.ssid; arg.ssid_len = arvif->vif->bss_conf.ssid_len; @@ -571,7 +568,8 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif) static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) { - struct ieee80211_channel *channel = ar->hw->conf.chandef.chan; + struct cfg80211_chan_def *chandef = &ar->chandef; + struct ieee80211_channel *channel = chandef->chan; struct wmi_vdev_start_request_arg arg = {}; int ret = 0; @@ -584,11 +582,11 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id) arg.vdev_id = vdev_id; arg.channel.freq = channel->center_freq; - arg.channel.band_center_freq1 = ar->hw->conf.chandef.center_freq1; + arg.channel.band_center_freq1 = chandef->center_freq1; /* TODO setup this dynamically, what in case we don't have any vifs? */ - arg.channel.mode = chan_to_phymode(&ar->hw->conf.chandef); + arg.channel.mode = chan_to_phymode(chandef); arg.channel.chan_radar = !!(channel->flags & IEEE80211_CHAN_RADAR); @@ -835,6 +833,10 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, if (!info->enable_beacon) { ath10k_vdev_stop(arvif); + + arvif->is_started = false; + arvif->is_up = false; + return; } @@ -844,12 +846,21 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, if (ret) return; - ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, 0, info->bssid); + arvif->aid = 0; + memcpy(arvif->bssid, info->bssid, ETH_ALEN); + + ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, + arvif->bssid); if (ret) { ath10k_warn("Failed to bring up VDEV: %d\n", arvif->vdev_id); + ath10k_vdev_stop(arvif); return; } + + arvif->is_started = true; + arvif->is_up = true; + ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id); } @@ -868,18 +879,18 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, ath10k_warn("Failed to delete IBSS self peer:%pM for VDEV:%d ret:%d\n", self_peer, arvif->vdev_id, ret); - if (is_zero_ether_addr(arvif->u.ibss.bssid)) + if (is_zero_ether_addr(arvif->bssid)) return; ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, - arvif->u.ibss.bssid); + arvif->bssid); if (ret) { ath10k_warn("Failed to delete IBSS BSSID peer:%pM for VDEV:%d ret:%d\n", - arvif->u.ibss.bssid, arvif->vdev_id, ret); + arvif->bssid, arvif->vdev_id, ret); return; } - memset(arvif->u.ibss.bssid, 0, ETH_ALEN); + memset(arvif->bssid, 0, ETH_ALEN); return; } @@ -1387,11 +1398,17 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, "mac vdev %d up (associated) bssid %pM aid %d\n", arvif->vdev_id, bss_conf->bssid, bss_conf->aid); - ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, bss_conf->aid, - bss_conf->bssid); - if (ret) + arvif->aid = bss_conf->aid; + memcpy(arvif->bssid, bss_conf->bssid, ETH_ALEN); + + ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid); + if (ret) { ath10k_warn("VDEV: %d up failed: ret %d\n", arvif->vdev_id, ret); + return; + } + + arvif->is_up = true; } /* @@ -1431,6 +1448,9 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); arvif->def_wep_key_idx = 0; + + arvif->is_started = false; + arvif->is_up = false; } static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, @@ -2201,6 +2221,98 @@ static int ath10k_config_ps(struct ath10k *ar) return ret; } +static const char *chandef_get_width(enum nl80211_chan_width width) +{ + switch (width) { + case NL80211_CHAN_WIDTH_20_NOHT: + return "20 (noht)"; + case NL80211_CHAN_WIDTH_20: + return "20"; + case NL80211_CHAN_WIDTH_40: + return "40"; + case NL80211_CHAN_WIDTH_80: + return "80"; + case NL80211_CHAN_WIDTH_80P80: + return "80+80"; + case NL80211_CHAN_WIDTH_160: + return "160"; + case NL80211_CHAN_WIDTH_5: + return "5"; + case NL80211_CHAN_WIDTH_10: + return "10"; + } + return "?"; +} + +static void ath10k_config_chan(struct ath10k *ar) +{ + struct ath10k_vif *arvif; + bool monitor_was_enabled; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + ath10k_dbg(ATH10K_DBG_MAC, + "mac config channel to %dMHz (cf1 %dMHz cf2 %dMHz width %s)\n", + ar->chandef.chan->center_freq, + ar->chandef.center_freq1, + ar->chandef.center_freq2, + chandef_get_width(ar->chandef.width)); + + /* First stop monitor interface. Some FW versions crash if there's a + * lone monitor interface. */ + monitor_was_enabled = ar->monitor_enabled; + + if (ar->monitor_enabled) + ath10k_monitor_stop(ar); + + list_for_each_entry(arvif, &ar->arvifs, list) { + if (!arvif->is_started) + continue; + + if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) + continue; + + ret = ath10k_vdev_stop(arvif); + if (ret) { + ath10k_warn("could not stop vdev %d (%d)\n", + arvif->vdev_id, ret); + continue; + } + } + + /* all vdevs are now stopped - now attempt to restart them */ + + list_for_each_entry(arvif, &ar->arvifs, list) { + if (!arvif->is_started) + continue; + + if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) + continue; + + ret = ath10k_vdev_start(arvif); + if (ret) { + ath10k_warn("could not start vdev %d (%d)\n", + arvif->vdev_id, ret); + continue; + } + + if (!arvif->is_up) + continue; + + ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, + arvif->bssid); + if (ret) { + ath10k_warn("could not bring vdev up %d (%d)\n", + arvif->vdev_id, ret); + continue; + } + } + + if (monitor_was_enabled) + ath10k_monitor_start(ar, ar->monitor_vdev_id); +} + static int ath10k_config(struct ieee80211_hw *hw, u32 changed) { struct ath10k *ar = hw->priv; @@ -2221,6 +2333,11 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) spin_unlock_bh(&ar->data_lock); ath10k_config_radar_detection(ar); + + if (!cfg80211_chandef_identical(&ar->chandef, &conf->chandef)) { + ar->chandef = conf->chandef; + ath10k_config_chan(ar); + } } if (changed & IEEE80211_CONF_CHANGE_POWER) { @@ -2615,15 +2732,20 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, * this is never erased as we it for crypto key * clearing; this is FW requirement */ - memcpy(arvif->u.sta.bssid, info->bssid, - ETH_ALEN); + memcpy(arvif->bssid, info->bssid, ETH_ALEN); ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d start %pM\n", arvif->vdev_id, info->bssid); - /* FIXME: check return value */ ret = ath10k_vdev_start(arvif); + if (ret) { + ath10k_warn("failed to start vdev: %d\n", + ret); + return; + } + + arvif->is_started = true; } /* @@ -2632,7 +2754,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, * IBSS in order to remove BSSID peer. */ if (vif->type == NL80211_IFTYPE_ADHOC) - memcpy(arvif->u.ibss.bssid, info->bssid, + memcpy(arvif->bssid, info->bssid, ETH_ALEN); } } From c2df44b39b31a730a89b13f7be90860d93d1f9d8 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 23 Jan 2014 11:38:26 +0100 Subject: [PATCH 008/414] ath10k: implement AP CSA Most channel switching logic has been implemented already so this patch is pretty small. The patch makes use of mac80211's vif->csa_active for AP CSA handling. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 10 ++++++++++ drivers/net/wireless/ath/ath10k/wmi.c | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 8fe451796fde..4bf5f19602e4 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3818,6 +3818,14 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw, return ath10k_set_fixed_rate_param(arvif, fixed_rate, fixed_nss); } +static void ath10k_channel_switch_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_chan_def *chandef) +{ + /* there's no need to do anything here. vif->csa_active is enough */ + return; +} + static const struct ieee80211_ops ath10k_ops = { .tx = ath10k_tx, .start = ath10k_start, @@ -3841,6 +3849,7 @@ static const struct ieee80211_ops ath10k_ops = { .restart_complete = ath10k_restart_complete, .get_survey = ath10k_get_survey, .set_bitrate_mask = ath10k_set_bitrate_mask, + .channel_switch_beacon = ath10k_channel_switch_beacon, #ifdef CONFIG_PM .suspend = ath10k_suspend, .resume = ath10k_resume, @@ -4220,6 +4229,7 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL; ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; ar->hw->wiphy->max_remain_on_channel_duration = 5000; ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index f0969cd8350f..a1ec5d0fb0ef 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1405,6 +1405,17 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) continue; } + /* There are no completions for beacons so wait for next SWBA + * before telling mac80211 to decrement CSA counter + * + * Once CSA counter is completed stop sending beacons until + * actual channel switch is done */ + if (arvif->vif->csa_active && + ieee80211_csa_is_complete(arvif->vif)) { + ieee80211_csa_finish(arvif->vif); + continue; + } + bcn = ieee80211_beacon_get(ar->hw, arvif->vif); if (!bcn) { ath10k_warn("could not get mac80211 beacon\n"); From 748afc4735361e21ad655c0dc021ea3aaeeb3efd Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 23 Jan 2014 12:48:21 +0100 Subject: [PATCH 009/414] ath10k: implement and use new beacon method Until now ath10k used a copy-by-value beacon submission. The new method passes a DMA address via WMI command only. This command contains additional metadata that fixes AP behaviour with regard to powersave buffering. This also fixes strange bug when multicast traffic would freeze TX indefinitely. Signed-off-by: Michal Kazior Signed-off-by: Marek Puzyniak Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 7 +++ drivers/net/wireless/ath/ath10k/mac.c | 10 ++++ drivers/net/wireless/ath/ath10k/wmi.c | 71 ++++++++++++++++++-------- drivers/net/wireless/ath/ath10k/wmi.h | 21 +++++++- 4 files changed, 85 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 8b145209d37d..c0b00e1f7562 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -73,6 +73,11 @@ struct ath10k_skb_cb { u8 frag_len; u8 pad_len; } __packed htt; + + struct { + bool dtim_zero; + bool deliver_cab; + } bcn; } __packed; static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb) @@ -234,6 +239,8 @@ struct ath10k_vif { u32 beacon_interval; u32 dtim_period; struct sk_buff *beacon; + /* protected by data_lock */ + bool beacon_sent; struct ath10k *ar; struct ieee80211_vif *vif; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 4bf5f19602e4..bb1c8397c0d3 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -837,6 +837,16 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, arvif->is_started = false; arvif->is_up = false; + spin_lock_bh(&arvif->ar->data_lock); + if (arvif->beacon) { + ath10k_skb_unmap(arvif->ar->dev, arvif->beacon); + dev_kfree_skb_any(arvif->beacon); + + arvif->beacon = NULL; + arvif->beacon_sent = false; + } + spin_unlock_bh(&arvif->ar->data_lock); + return; } diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index a1ec5d0fb0ef..bd01f0a7dafb 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -561,7 +561,6 @@ err_pull: static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) { - struct wmi_bcn_tx_arg arg = {0}; int ret; lockdep_assert_held(&arvif->ar->data_lock); @@ -569,18 +568,16 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) if (arvif->beacon == NULL) return; - arg.vdev_id = arvif->vdev_id; - arg.tx_rate = 0; - arg.tx_power = 0; - arg.bcn = arvif->beacon->data; - arg.bcn_len = arvif->beacon->len; + if (arvif->beacon_sent) + return; - ret = ath10k_wmi_beacon_send_nowait(arvif->ar, &arg); + ret = ath10k_wmi_beacon_send_ref_nowait(arvif); if (ret) return; - dev_kfree_skb_any(arvif->beacon); - arvif->beacon = NULL; + /* We need to retain the arvif->beacon reference for DMA unmapping and + * freeing the skbuff later. */ + arvif->beacon_sent = true; } static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac, @@ -1237,6 +1234,13 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->tim_info.tim_mcast); memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len); + if (tim->dtim_count == 0) { + ATH10K_SKB_CB(bcn)->bcn.dtim_zero = true; + + if (__le32_to_cpu(bcn_info->tim_info.tim_mcast) == 1) + ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true; + } + ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n", tim->dtim_count, tim->dtim_period, tim->bitmap_ctrl, pvm_len); @@ -1427,13 +1431,20 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info); spin_lock_bh(&ar->data_lock); + if (arvif->beacon) { - ath10k_warn("SWBA overrun on vdev %d\n", - arvif->vdev_id); + if (!arvif->beacon_sent) + ath10k_warn("SWBA overrun on vdev %d\n", + arvif->vdev_id); + + ath10k_skb_unmap(ar->dev, arvif->beacon); dev_kfree_skb_any(arvif->beacon); } + ath10k_skb_map(ar->dev, bcn); + arvif->beacon = bcn; + arvif->beacon_sent = false; ath10k_wmi_tx_beacon_nowait(arvif); spin_unlock_bh(&ar->data_lock); @@ -3442,25 +3453,41 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar, return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid); } -int ath10k_wmi_beacon_send_nowait(struct ath10k *ar, - const struct wmi_bcn_tx_arg *arg) +/* This function assumes the beacon is already DMA mapped */ +int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif) { - struct wmi_bcn_tx_cmd *cmd; + struct wmi_bcn_tx_ref_cmd *cmd; struct sk_buff *skb; + struct sk_buff *beacon = arvif->beacon; + struct ath10k *ar = arvif->ar; + struct ieee80211_hdr *hdr; int ret; + u16 fc; - skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->bcn_len); + skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); if (!skb) return -ENOMEM; - cmd = (struct wmi_bcn_tx_cmd *)skb->data; - cmd->hdr.vdev_id = __cpu_to_le32(arg->vdev_id); - cmd->hdr.tx_rate = __cpu_to_le32(arg->tx_rate); - cmd->hdr.tx_power = __cpu_to_le32(arg->tx_power); - cmd->hdr.bcn_len = __cpu_to_le32(arg->bcn_len); - memcpy(cmd->bcn, arg->bcn, arg->bcn_len); + hdr = (struct ieee80211_hdr *)beacon->data; + fc = le16_to_cpu(hdr->frame_control); + + cmd = (struct wmi_bcn_tx_ref_cmd *)skb->data; + cmd->vdev_id = __cpu_to_le32(arvif->vdev_id); + cmd->data_len = __cpu_to_le32(beacon->len); + cmd->data_ptr = __cpu_to_le32(ATH10K_SKB_CB(beacon)->paddr); + cmd->msdu_id = 0; + cmd->frame_control = __cpu_to_le32(fc); + cmd->flags = 0; + + if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero) + cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO); + + if (ATH10K_SKB_CB(beacon)->bcn.deliver_cab) + cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB); + + ret = ath10k_wmi_cmd_send_nowait(ar, skb, + ar->wmi.cmd->pdev_send_bcn_cmdid); - ret = ath10k_wmi_cmd_send_nowait(ar, skb, ar->wmi.cmd->bcn_tx_cmdid); if (ret) dev_kfree_skb(skb); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 9dc90c5dd0e4..9d9a81bfbb36 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3403,6 +3403,24 @@ struct wmi_bcn_tx_arg { const void *bcn; }; +enum wmi_bcn_tx_ref_flags { + WMI_BCN_TX_REF_FLAG_DTIM_ZERO = 0x1, + WMI_BCN_TX_REF_FLAG_DELIVER_CAB = 0x2, +}; + +struct wmi_bcn_tx_ref_cmd { + __le32 vdev_id; + __le32 data_len; + /* physical address of the frame - dma pointer */ + __le32 data_ptr; + /* id for host to track */ + __le32 msdu_id; + /* frame ctrl to setup PPDU desc */ + __le32 frame_control; + /* to control CABQ traffic: WMI_BCN_TX_REF_FLAG_ */ + __le32 flags; +} __packed; + /* Beacon filter */ #define WMI_BCN_FILTER_ALL 0 /* Filter all beacons */ #define WMI_BCN_FILTER_NONE 1 /* Pass all beacons */ @@ -4223,8 +4241,7 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, enum wmi_ap_ps_peer_param param_id, u32 value); int ath10k_wmi_scan_chan_list(struct ath10k *ar, const struct wmi_scan_chan_list_arg *arg); -int ath10k_wmi_beacon_send_nowait(struct ath10k *ar, - const struct wmi_bcn_tx_arg *arg); +int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif); int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, const struct wmi_pdev_set_wmm_params_arg *arg); int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id); From c60bdd8334804720e9d236c543612c998baaee0d Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 29 Jan 2014 07:26:31 +0100 Subject: [PATCH 010/414] ath10k: properly return err from start() If recovery failed ath10k returned 0 (success) and mac80211 continued to call other driver callbacks. This caused null dereference. This is how the failure looked like: ath10k: ctl_resp never came in (-110) ath10k: failed to connect to HTC: -110 ath10k: could not init core (-110) BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] ath10k_ce_send+0x1d/0x15d [ath10k_pci] PGD 0 Oops: 0000 [#1] PREEMPT SMP Modules linked in: ath10k_pci ath10k_core ath5k ath9k ath9k_common ath9k_hw ath mac80211 cfg80211 nf_nat_ipv4 ] CPU: 1 PID: 36 Comm: kworker/1:1 Tainted: G WC 3.13.0-rc8-wl-ath+ #8 Hardware name: To be filled by O.E.M. To be filled by O.E.M./HURONRIVER, BIOS 4.6.5 05/02/2012 Workqueue: events ieee80211_restart_work [mac80211] task: ffff880215b521c0 ti: ffff880215e18000 task.ti: ffff880215e18000 RIP: 0010:[] [] ath10k_ce_send+0x1d/0x15d [ath10k_pci] RSP: 0018:ffff880215e19af8 EFLAGS: 00010292 RAX: ffff880215e19b10 RBX: 0000000000000000 RCX: 0000000000000018 RDX: 00000000d9ccf800 RSI: ffff8800c965ad00 RDI: 0000000000000000 RBP: ffff880215e19b58 R08: 0000000000000002 R09: 0000000000000000 R10: ffffffff812e1a23 R11: 0000000000000292 R12: 0000000000000018 R13: 0000000000000000 R14: 0000000000000002 R15: ffff88021562d700 FS: 0000000000000000(0000) GS:ffff88021fa80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 0000000001a0d000 CR4: 00000000000407e0 Stack: d9ccf8000d47df40 ffffffffa0b367a0 ffff880215e19b10 0000000000000010 ffff880215e19b68 ffff880215e19b28 0000000000000018 ffff8800c965ad00 0000000000000018 0000000000000000 0000000000000002 ffff88021562d700 Call Trace: [] ath10k_pci_hif_send_head+0xa7/0xcb [ath10k_pci] [] ath10k_htc_send+0x23d/0x2d0 [ath10k_core] [] ath10k_wmi_cmd_send_nowait+0x5d/0x85 [ath10k_core] [] ath10k_wmi_cmd_send+0x62/0x115 [ath10k_core] [] ? __netdev_alloc_skb+0x4b/0x9b [] ath10k_wmi_vdev_set_param+0x91/0xa3 [ath10k_core] [] ath10k_mac_set_rts+0x3e/0x40 [ath10k_core] [] ath10k_set_frag_threshold+0x5e/0x9c [ath10k_core] [] ieee80211_reconfig+0x12a/0x7b3 [mac80211] [] ? mutex_unlock+0x9/0xb [] ieee80211_restart_work+0x5e/0x68 [mac80211] [] process_one_work+0x1d7/0x2fc [] ? process_one_work+0x16d/0x2fc [] worker_thread+0x12e/0x1fb [] ? rescuer_thread+0x27b/0x27b [] kthread+0xb5/0xbd [] ? _raw_spin_unlock_irq+0x28/0x42 [] ? __kthread_parkme+0x5c/0x5c [] ret_from_fork+0x7c/0xb0 [] ? __kthread_parkme+0x5c/0x5c Code: df ff d0 48 83 c4 18 5b 41 5c 41 5d 5d c3 55 48 89 e5 41 57 41 56 45 89 c6 41 55 41 54 41 89 cc 53 48 89 RIP [] ath10k_ce_send+0x1d/0x15d [ath10k_pci] RSP CR2: 0000000000000000 Reported-By: Ben Greear Signed-off-by: Michal Kazior 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 bb1c8397c0d3..ce91d5c9d60a 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2187,10 +2187,11 @@ static int ath10k_start(struct ieee80211_hw *hw) ret); ath10k_regd_update(ar); + ret = 0; exit: mutex_unlock(&ar->conf_mutex); - return 0; + return ret; } static void ath10k_stop(struct ieee80211_hw *hw) From ab6258edb4e15af016bb9c64fb521211a3f22b36 Mon Sep 17 00:00:00 2001 From: Marek Puzyniak Date: Wed, 29 Jan 2014 15:03:31 +0200 Subject: [PATCH 011/414] ath10k: configure access category for arp ARP frames exchange does not work properly for UAPSD enabled AP. ARP requests which arrives with access category 0 are processed by network stack and send back with access category 0. FW changes access category to 6. This is causing problems when UAPSD associated STA is sleeping after has sent ARP request. Configure ARP access category in FW to best effort (0) solves this problem. ARP frames will be send with access category 0. Simplify arp ac override functionality by removing redundant entry in pdev param maping table. There should be only one entry in pdev param map but enum has different name for different FW. kvalo: change the warning message Signed-off-by: Marek Puzyniak Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 17 +++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.c | 4 +--- drivers/net/wireless/ath/ath10k/wmi.h | 1 - 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index ce91d5c9d60a..144b4d605267 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2186,6 +2186,23 @@ static int ath10k_start(struct ieee80211_hw *hw) ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n", ret); + /* + * By default FW set ARP frames ac to voice (6). In that case ARP + * exchange is not working properly for UAPSD enabled AP. ARP requests + * which arrives with access category 0 are processed by network stack + * and send back with access category 0, but FW changes access category + * to 6. Set ARP frames access category to best effort (0) solves + * this problem. + */ + + ret = ath10k_wmi_pdev_set_param(ar, + ar->wmi.pdev_param->arp_ac_override, 0); + if (ret) { + ath10k_warn("could not set arp ac override parameter: %d\n", + ret); + goto exit; + } + ath10k_regd_update(ar); ret = 0; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index bd01f0a7dafb..7298c0677b0b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -420,7 +420,6 @@ static struct wmi_pdev_param_map wmi_pdev_param_map = { .bcnflt_stats_update_period = WMI_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, .pmf_qos = WMI_PDEV_PARAM_PMF_QOS, .arp_ac_override = WMI_PDEV_PARAM_ARP_AC_OVERRIDE, - .arpdhcp_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, .dcs = WMI_PDEV_PARAM_DCS, .ani_enable = WMI_PDEV_PARAM_ANI_ENABLE, .ani_poll_period = WMI_PDEV_PARAM_ANI_POLL_PERIOD, @@ -472,8 +471,7 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { .bcnflt_stats_update_period = WMI_10X_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, .pmf_qos = WMI_10X_PDEV_PARAM_PMF_QOS, - .arp_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, - .arpdhcp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE, + .arp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE, .dcs = WMI_10X_PDEV_PARAM_DCS, .ani_enable = WMI_10X_PDEV_PARAM_ANI_ENABLE, .ani_poll_period = WMI_10X_PDEV_PARAM_ANI_POLL_PERIOD, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 9d9a81bfbb36..083079f3fdd4 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2277,7 +2277,6 @@ struct wmi_pdev_param_map { u32 bcnflt_stats_update_period; u32 pmf_qos; u32 arp_ac_override; - u32 arpdhcp_ac_override; u32 dcs; u32 ani_enable; u32 ani_poll_period; From f591a1a5dc34341dce9af2efaa9e2e824ceb67be Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 4 Feb 2014 19:51:38 +0200 Subject: [PATCH 012/414] ath10k: Print out firmware feature bits from IE. Aids in understanding excactly what a firmware is offering. Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 3b59af3bddf4..56048b1bbca5 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -470,8 +470,12 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) if (index == ie_len) break; - if (data[index] & (1 << bit)) + if (data[index] & (1 << bit)) { + ath10k_dbg(ATH10K_DBG_BOOT, + "Enabling feature bit: %i\n", + i); __set_bit(i, ar->fw_features); + } } ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "", From 4bf332c785bc14e6decb6ea4949a831e7e199b8b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 6 Feb 2014 16:50:34 +0100 Subject: [PATCH 013/414] mac80211: remove superfluous band variable We already have a band variable, so the new one is just shadowing it, but the existing one already holds the same value so just remove the inner one. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 6973ccdd230b..7f01f2aec7b5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1345,9 +1345,6 @@ static int sta_apply_parameters(struct ieee80211_local *local, params->vht_capa, sta); if (params->opmode_notif_used) { - enum ieee80211_band band = - ieee80211_get_sdata_band(sdata); - /* returned value is only needed for rc update, but the * rc isn't initialized here yet, so ignore it */ From b59ec8dd4394cf11e3253e849a04734be6d3d694 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 7 Feb 2014 10:44:50 +0100 Subject: [PATCH 014/414] mac80211_hwsim: fix number of channels in interface combinations There's little point in setting the number of channels if the entire combination struct is overwritten again later - that was clearly intended the other way around, fix it. Reported-by: Luciano Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index f7e3562542fe..771b8c573bff 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2004,11 +2004,11 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, /* For channels > 1 DFS is not allowed */ hw->wiphy->n_iface_combinations = 1; hw->wiphy->iface_combinations = &data->if_combination; - data->if_combination.num_different_channels = data->channels; if (p2p_device) data->if_combination = hwsim_if_comb_p2p_dev[0]; else data->if_combination = hwsim_if_comb[0]; + data->if_combination.num_different_channels = data->channels; } else if (p2p_device) { hw->wiphy->iface_combinations = hwsim_if_comb_p2p_dev; hw->wiphy->n_iface_combinations = From 448cd2e248732326632957e52ea9c44729affcb2 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 11 Feb 2014 12:30:18 +0200 Subject: [PATCH 015/414] mac80211: reset probe_send_count also in HW_CONNECTION_MONITOR case In case of beacon_loss with IEEE80211_HW_CONNECTION_MONITOR device, mac80211 probes the ap (and disconnects on timeout) but ignores the ack. If we already got an ack, there's no reason to continue disconnecting. this can help devices that supports IEEE80211_HW_CONNECTION_MONITOR only partially (e.g. take care of keep alives, but does not probe the ap. In case the device wants to disconnect without probing, it can just call ieee80211_connection_loss. Signed-off-by: Eliad Peller Signed-off-by: Johannes Berg --- include/net/mac80211.h | 2 -- net/mac80211/mlme.c | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4f0f29dce0aa..4005c5b4e3b4 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1507,8 +1507,6 @@ struct ieee80211_tx_control { * @IEEE80211_HW_CONNECTION_MONITOR: * The hardware performs its own connection monitoring, including * periodic keep-alives to the AP and probing the AP on beacon loss. - * When this flag is set, signaling beacon-loss will cause an immediate - * change to disassociated state. * * @IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC: * This device needs to get data from beacon before association (i.e. diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 61604834b914..b9432b575444 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -131,13 +131,13 @@ void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata) if (unlikely(!sdata->u.mgd.associated)) return; + ifmgd->probe_send_count = 0; + if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) return; mod_timer(&sdata->u.mgd.conn_mon_timer, round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); - - ifmgd->probe_send_count = 0; } static int ecw2cw(int ecw) From 802ee9ecfc886c5d6ad831586e65088893c774fb Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 11 Feb 2014 12:36:18 +0200 Subject: [PATCH 016/414] mac80211: add beacon_loss debugfs file Add beacon_loss debugfs file that emulates ieee80211_beacon_loss call from the driver. This can be used for various testing scenarios. Signed-off-by: Eliad Peller Signed-off-by: Johannes Berg --- net/mac80211/debugfs_netdev.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index ebf80f3abd83..40a648938985 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -358,6 +358,18 @@ static ssize_t ieee80211_if_parse_tkip_mic_test( } IEEE80211_IF_FILE_W(tkip_mic_test); +static ssize_t ieee80211_if_parse_beacon_loss( + struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) +{ + if (!ieee80211_sdata_running(sdata) || !sdata->vif.bss_conf.assoc) + return -ENOTCONN; + + ieee80211_beacon_loss(&sdata->vif); + + return buflen; +} +IEEE80211_IF_FILE_W(beacon_loss); + static ssize_t ieee80211_if_fmt_uapsd_queues( const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) { @@ -569,6 +581,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(beacon_timeout); DEBUGFS_ADD_MODE(smps, 0600); DEBUGFS_ADD_MODE(tkip_mic_test, 0200); + DEBUGFS_ADD_MODE(beacon_loss, 0200); DEBUGFS_ADD_MODE(uapsd_queues, 0600); DEBUGFS_ADD_MODE(uapsd_max_sp_len, 0600); } From e4dcbb375cd829e1649b12e0ab7d7e5b7efcb5a5 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Tue, 11 Feb 2014 13:45:41 +0200 Subject: [PATCH 017/414] mac80211: fix IE buffer len Remove size of SSID IE from the IE buffer in scan and sched scan, since this IE isn't added to this buffer. Reviewed-by: Eliad Peller Reviewed-by: Emmanuel Grumbach Reviewed-by: Alexander Bondar Signed-off-by: David Spinadel Signed-off-by: Johannes Berg --- net/mac80211/scan.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 88c81616f8f7..b211e412511f 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -472,9 +472,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, if (local->ops->hw_scan) { u8 *ies; - local->hw_scan_ies_bufsize = 2 + IEEE80211_MAX_SSID_LEN + - local->scan_ies_len + - req->ie_len; + local->hw_scan_ies_bufsize = local->scan_ies_len + req->ie_len; local->hw_scan_req = kmalloc( sizeof(*local->hw_scan_req) + req->n_channels * sizeof(req->channels[0]) + @@ -979,8 +977,7 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, struct cfg80211_chan_def chandef; int ret, i, iebufsz; - iebufsz = 2 + IEEE80211_MAX_SSID_LEN + - local->scan_ies_len + req->ie_len; + iebufsz = local->scan_ies_len + req->ie_len; lockdep_assert_held(&local->mtx); From 361c3e0485c737b9c8a2d456b8c3c7b08d8ca8ee Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 10 Feb 2014 15:23:03 +0200 Subject: [PATCH 018/414] mac80211_hwsim: allow creation of single-channel radios with chanctx Add a new HWSIM_ATTR_USE_CHANCTX attribute to the HWSIM_CMD_CREATE_RADIO command to allow the creation of radios with one channel that use channel contexts. If this attribute is not present, the behaviour is the same as before (ie. single channel radios don't use channel contexts and multi channel radios do). Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 29 +++++++++++++++++++-------- drivers/net/wireless/mac80211_hwsim.h | 4 ++++ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 771b8c573bff..9d7a52f5a410 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -411,6 +411,7 @@ struct mac80211_hwsim_data { struct mac_address addresses[2]; int channels, idx; + bool use_chanctx; struct ieee80211_channel *tmp_chan; struct delayed_work roc_done; @@ -1088,7 +1089,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, return; } - if (data->channels == 1) { + if (!data->use_chanctx) { channel = data->channel; } else if (txi->hw_queue == 4) { channel = data->tmp_chan; @@ -1354,7 +1355,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) data->channel = conf->chandef.chan; - WARN_ON(data->channel && data->channels > 1); + WARN_ON(data->channel && data->use_chanctx); data->power_level = conf->power_level; if (!data->started || !data->beacon_int) @@ -1940,7 +1941,8 @@ static struct ieee80211_ops mac80211_hwsim_mchan_ops; static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, const struct ieee80211_regdomain *regd, - bool reg_strict, bool p2p_device) + bool reg_strict, bool p2p_device, + bool use_chanctx) { int err; u8 addr[ETH_ALEN]; @@ -1950,11 +1952,14 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, const struct ieee80211_ops *ops = &mac80211_hwsim_ops; int idx; + if (WARN_ON(channels > 1 && !use_chanctx)) + return -EINVAL; + spin_lock_bh(&hwsim_radio_lock); idx = hwsim_radio_idx++; spin_unlock_bh(&hwsim_radio_lock); - if (channels > 1) + if (use_chanctx) ops = &mac80211_hwsim_mchan_ops; hw = ieee80211_alloc_hw(sizeof(*data), ops); if (!hw) { @@ -1995,9 +2000,10 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, hw->wiphy->addresses = data->addresses; data->channels = channels; + data->use_chanctx = use_chanctx; data->idx = idx; - if (data->channels > 1) { + if (data->use_chanctx) { hw->wiphy->max_scan_ssids = 255; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; hw->wiphy->max_remain_on_channel_duration = 1000; @@ -2156,7 +2162,7 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps); debugfs_create_file("group", 0666, data->debugfs, data, &hwsim_fops_group); - if (data->channels == 1) + if (!data->use_chanctx) debugfs_create_file("dfs_simulate_radar", 0222, data->debugfs, data, &hwsim_simulate_radar); @@ -2423,10 +2429,16 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info) const struct ieee80211_regdomain *regd = NULL; bool reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG]; bool p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE]; + bool use_chanctx; if (info->attrs[HWSIM_ATTR_CHANNELS]) chans = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]); + if (info->attrs[HWSIM_ATTR_USE_CHANCTX]) + use_chanctx = true; + else + use_chanctx = (chans > 1); + if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]) alpha2 = nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]); @@ -2439,7 +2451,7 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info) } return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict, - p2p_device); + p2p_device, use_chanctx); } static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info) @@ -2658,7 +2670,8 @@ static int __init init_mac80211_hwsim(void) err = mac80211_hwsim_create_radio(channels, reg_alpha2, regd, reg_strict, - support_p2p_device); + support_p2p_device, + channels > 1); if (err < 0) goto out_free_radios; } diff --git a/drivers/net/wireless/mac80211_hwsim.h b/drivers/net/wireless/mac80211_hwsim.h index 6e72996ec8c1..c9d0315575ba 100644 --- a/drivers/net/wireless/mac80211_hwsim.h +++ b/drivers/net/wireless/mac80211_hwsim.h @@ -108,6 +108,9 @@ enum { * @HWSIM_ATTR_REG_CUSTOM_REG: custom regulatory domain index (u32 attribute) * @HWSIM_ATTR_REG_STRICT_REG: request REGULATORY_STRICT_REG (flag attribute) * @HWSIM_ATTR_SUPPORT_P2P_DEVICE: support P2P Device virtual interface (flag) + * @HWSIM_ATTR_USE_CHANCTX: used with the %HWSIM_CMD_CREATE_RADIO + * command to force use of channel contexts even when only a + * single channel is supported * @__HWSIM_ATTR_MAX: enum limit */ @@ -128,6 +131,7 @@ enum { HWSIM_ATTR_REG_CUSTOM_REG, HWSIM_ATTR_REG_STRICT_REG, HWSIM_ATTR_SUPPORT_P2P_DEVICE, + HWSIM_ATTR_USE_CHANCTX, __HWSIM_ATTR_MAX, }; #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1) From 1d5e1266cf4d96660e9b01577fdf8046b076cb58 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 12 Feb 2014 11:29:32 +0100 Subject: [PATCH 019/414] mac80211: simplify roc check in idle calculation There's no need to start iterating the list only to break on the first item, just use !list_empty() and also simplify the whole conditional into a single expression. Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 8880bc8fce0d..9db71cf7a665 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -101,9 +101,8 @@ static u32 __ieee80211_idle_on(struct ieee80211_local *local) static u32 __ieee80211_recalc_idle(struct ieee80211_local *local, bool force_active) { - bool working = false, scanning, active; + bool working, scanning, active; unsigned int led_trig_start = 0, led_trig_stop = 0; - struct ieee80211_roc_work *roc; lockdep_assert_held(&local->mtx); @@ -111,12 +110,8 @@ static u32 __ieee80211_recalc_idle(struct ieee80211_local *local, !list_empty(&local->chanctx_list) || local->monitors; - if (!local->ops->remain_on_channel) { - list_for_each_entry(roc, &local->roc_list, list) { - working = true; - break; - } - } + working = !local->ops->remain_on_channel && + !list_empty(&local->roc_list); scanning = test_bit(SCAN_SW_SCANNING, &local->scanning) || test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning); From dfa1ad299184abeb8fea170e65727e263ac236a5 Mon Sep 17 00:00:00 2001 From: Calvin Owens Date: Tue, 11 Feb 2014 12:36:24 -0600 Subject: [PATCH 020/414] ieee80211: Print human-readable disassoc/deauth reason codes Create a function to return a descriptive string for each reason code, and print that in addition to the numeric value in the kernel log. These codes are easily found on popular search engines, but one is generally not able to access the internet when dealing with wireless connectivity issues. Signed-off-by: Calvin Owens [use 'unknown' rather than 'invalid' since more valid codes exist] Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 68 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b9432b575444..46b62bb3677c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2249,6 +2249,62 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, /* ignore frame -- wait for timeout */ } +#define case_WLAN(type) \ + case WLAN_REASON_##type: return #type + +static const char *ieee80211_get_reason_code_string(u16 reason_code) +{ + switch (reason_code) { + case_WLAN(UNSPECIFIED); + case_WLAN(PREV_AUTH_NOT_VALID); + case_WLAN(DEAUTH_LEAVING); + case_WLAN(DISASSOC_DUE_TO_INACTIVITY); + case_WLAN(DISASSOC_AP_BUSY); + case_WLAN(CLASS2_FRAME_FROM_NONAUTH_STA); + case_WLAN(CLASS3_FRAME_FROM_NONASSOC_STA); + case_WLAN(DISASSOC_STA_HAS_LEFT); + case_WLAN(STA_REQ_ASSOC_WITHOUT_AUTH); + case_WLAN(DISASSOC_BAD_POWER); + case_WLAN(DISASSOC_BAD_SUPP_CHAN); + case_WLAN(INVALID_IE); + case_WLAN(MIC_FAILURE); + case_WLAN(4WAY_HANDSHAKE_TIMEOUT); + case_WLAN(GROUP_KEY_HANDSHAKE_TIMEOUT); + case_WLAN(IE_DIFFERENT); + case_WLAN(INVALID_GROUP_CIPHER); + case_WLAN(INVALID_PAIRWISE_CIPHER); + case_WLAN(INVALID_AKMP); + case_WLAN(UNSUPP_RSN_VERSION); + case_WLAN(INVALID_RSN_IE_CAP); + case_WLAN(IEEE8021X_FAILED); + case_WLAN(CIPHER_SUITE_REJECTED); + case_WLAN(DISASSOC_UNSPECIFIED_QOS); + case_WLAN(DISASSOC_QAP_NO_BANDWIDTH); + case_WLAN(DISASSOC_LOW_ACK); + case_WLAN(DISASSOC_QAP_EXCEED_TXOP); + case_WLAN(QSTA_LEAVE_QBSS); + case_WLAN(QSTA_NOT_USE); + case_WLAN(QSTA_REQUIRE_SETUP); + case_WLAN(QSTA_TIMEOUT); + case_WLAN(QSTA_CIPHER_NOT_SUPP); + case_WLAN(MESH_PEER_CANCELED); + case_WLAN(MESH_MAX_PEERS); + case_WLAN(MESH_CONFIG); + case_WLAN(MESH_CLOSE); + case_WLAN(MESH_MAX_RETRIES); + case_WLAN(MESH_CONFIRM_TIMEOUT); + case_WLAN(MESH_INVALID_GTK); + case_WLAN(MESH_INCONSISTENT_PARAM); + case_WLAN(MESH_INVALID_SECURITY); + case_WLAN(MESH_PATH_ERROR); + case_WLAN(MESH_PATH_NOFORWARD); + case_WLAN(MESH_PATH_DEST_UNREACHABLE); + case_WLAN(MAC_EXISTS_IN_MBSS); + case_WLAN(MESH_CHAN_REGULATORY); + case_WLAN(MESH_CHAN); + default: return ""; + } +} static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len) @@ -2270,8 +2326,8 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); - sdata_info(sdata, "deauthenticated from %pM (Reason: %u)\n", - bssid, reason_code); + sdata_info(sdata, "deauthenticated from %pM (Reason: %u=%s)\n", + bssid, reason_code, ieee80211_get_reason_code_string(reason_code)); ieee80211_set_disassoc(sdata, 0, 0, false, NULL); @@ -4340,8 +4396,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, bool report_frame = false; sdata_info(sdata, - "deauthenticating from %pM by local choice (reason=%d)\n", - req->bssid, req->reason_code); + "deauthenticating from %pM by local choice (Reason: %u=%s)\n", + req->bssid, req->reason_code, ieee80211_get_reason_code_string(req->reason_code)); if (ifmgd->auth_data) { drv_mgd_prepare_tx(sdata->local, sdata); @@ -4387,8 +4443,8 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, return -ENOLINK; sdata_info(sdata, - "disassociating from %pM by local choice (reason=%d)\n", - req->bss->bssid, req->reason_code); + "disassociating from %pM by local choice (Reason: %u=%s)\n", + req->bss->bssid, req->reason_code, ieee80211_get_reason_code_string(req->reason_code)); memcpy(bssid, req->bss->bssid, ETH_ALEN); ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC, From e7aceef4ac3180bd93d4c0d3fe23775850b6c31d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 12 Feb 2014 14:21:15 +0100 Subject: [PATCH 021/414] cfg80211: remove NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL There's no driver using this flag and consequently no userspace application is actually looking at it. As it seems unlikely for any driver to start using it, remove it and the (very little) code that used it. Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 7 +------ net/wireless/chan.c | 6 +----- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index a12e6cae5132..ba1f7625625c 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3843,11 +3843,6 @@ enum nl80211_ap_sme_features { * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested * to work properly to suppport receiving regulatory hints from * cellular base stations. - * @NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL: If this is set, an active - * P2P Device (%NL80211_IFTYPE_P2P_DEVICE) requires its own channel - * in the interface combinations, even when it's only used for scan - * and remain-on-channel. This could be due to, for example, the - * remain-on-channel implementation requiring a channel context. * @NL80211_FEATURE_SAE: This driver supports simultaneous authentication of * equals (SAE) with user space SME (NL80211_CMD_AUTHENTICATE) in station * mode @@ -3889,7 +3884,7 @@ enum nl80211_feature_flags { NL80211_FEATURE_HT_IBSS = 1 << 1, NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2, NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3, - NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL = 1 << 4, + /* bit 4 is reserved - don't use */ NL80211_FEATURE_SAE = 1 << 5, NL80211_FEATURE_LOW_PRIORITY_SCAN = 1 << 6, NL80211_FEATURE_SCAN_FLUSH = 1 << 7, diff --git a/net/wireless/chan.c b/net/wireless/chan.c index f8ab7df1ab0d..5946450c5406 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -705,12 +705,8 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_WDS: - /* these interface types don't really have a channel */ - return; case NL80211_IFTYPE_P2P_DEVICE: - if (wdev->wiphy->features & - NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL) - *chanmode = CHAN_MODE_EXCLUSIVE; + /* these interface types don't really have a channel */ return; case NL80211_IFTYPE_UNSPECIFIED: case NUM_NL80211_IFTYPES: From 9900e4843c6c95cc951a642e337478831429be88 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 4 Feb 2014 21:01:25 +0100 Subject: [PATCH 022/414] nl80211: use ie_len in scheduled scan We've already checked the IE length and assigned request->ie based on that, so continue using it to make the code a bit clearer. Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ebea1a197afb..179786494308 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5709,8 +5709,8 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF; } - if (info->attrs[NL80211_ATTR_IE]) { - request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + if (ie_len) { + request->ie_len = ie_len; memcpy((void *)request->ie, nla_data(info->attrs[NL80211_ATTR_IE]), request->ie_len); From 06d181a8fd58031db9c114d920b40d8820380a6e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 4 Feb 2014 20:51:09 +0100 Subject: [PATCH 023/414] mac80211: add NAPI support back NAPI was originally added to mac80211 a long time ago (by John in commit 4e6cbfd09c66 in July 2010), but then removed years later (by Stanislaw in commit 30c97120c6c7 in February 2013). No driver ever used it, so that was fine. Now I'm adding support for NAPI to our driver, so add some code to mac80211 again to support NAPI. John was originally wrapping some (but not nearly all NAPI-related functions), but that doesn't scale very well with the number of functions that are there, some of which are even only inlines. Thus, instead of doing that, let the drivers manage the NAPI struct, except for napi_add() which is needed so mac80211 knows how to call napi_gro_receive(). Also remove some no longer needed definitions that were left when NAPI support was removed. Reviewed-by: Emmanuel Grumbach Reviewed-by: Eyal Shapira Signed-off-by: Johannes Berg --- include/net/mac80211.h | 34 +++++++++++++--------------------- net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/main.c | 12 ++++++++++++ net/mac80211/rx.c | 5 ++++- 4 files changed, 31 insertions(+), 22 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4005c5b4e3b4..2d4d31212eed 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1642,10 +1642,6 @@ enum ieee80211_hw_flags { * the hw can report back. * @max_rate_tries: maximum number of tries for each stage * - * @napi_weight: weight used for NAPI polling. You must specify an - * appropriate value here if a napi_poll operation is provided - * by your driver. - * * @max_rx_aggregation_subframes: maximum buffer size (number of * sub-frames) to be used for A-MPDU block ack receiver * aggregation. @@ -1699,7 +1695,6 @@ struct ieee80211_hw { int vif_data_size; int sta_data_size; int chanctx_data_size; - int napi_weight; u16 queues; u16 max_listen_interval; s8 max_signal; @@ -2622,8 +2617,6 @@ enum ieee80211_roc_type { * callback. They must then call ieee80211_chswitch_done() to indicate * completion of the channel switch. * - * @napi_poll: Poll Rx queue for incoming data frames. - * * @set_antenna: Set antenna configuration (tx_ant, rx_ant) on the device. * Parameters are bitmaps of allowed antennas to use for TX/RX. Drivers may * reject TX/RX mask combinations they cannot support by returning -EINVAL @@ -2882,7 +2875,6 @@ struct ieee80211_ops { void (*flush)(struct ieee80211_hw *hw, u32 queues, bool drop); void (*channel_switch)(struct ieee80211_hw *hw, struct ieee80211_channel_switch *ch_switch); - int (*napi_poll)(struct ieee80211_hw *hw, int budget); int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant); int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); @@ -3164,21 +3156,21 @@ void ieee80211_free_hw(struct ieee80211_hw *hw); */ void ieee80211_restart_hw(struct ieee80211_hw *hw); -/** ieee80211_napi_schedule - schedule NAPI poll +/** + * ieee80211_napi_add - initialize mac80211 NAPI context + * @hw: the hardware to initialize the NAPI context on + * @napi: the NAPI context to initialize + * @napi_dev: dummy NAPI netdevice, here to not waste the space if the + * driver doesn't use NAPI + * @poll: poll function + * @weight: default weight * - * Use this function to schedule NAPI polling on a device. - * - * @hw: the hardware to start polling + * See also netif_napi_add(). */ -void ieee80211_napi_schedule(struct ieee80211_hw *hw); - -/** ieee80211_napi_complete - complete NAPI polling - * - * Use this function to finish NAPI polling on a device. - * - * @hw: the hardware to stop polling - */ -void ieee80211_napi_complete(struct ieee80211_hw *hw); +void ieee80211_napi_add(struct ieee80211_hw *hw, struct napi_struct *napi, + struct net_device *napi_dev, + int (*poll)(struct napi_struct *, int), + int weight); /** * ieee80211_rx - receive frame diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0014b5396ce5..8603dfb52b3a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1242,6 +1242,8 @@ struct ieee80211_local { struct ieee80211_sub_if_data __rcu *p2p_sdata; + struct napi_struct *napi; + /* virtual monitor interface */ struct ieee80211_sub_if_data __rcu *monitor_sdata; struct cfg80211_chan_def monitor_chandef; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 1f7d8422d62d..b055f6a55c68 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1076,6 +1076,18 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) } EXPORT_SYMBOL(ieee80211_register_hw); +void ieee80211_napi_add(struct ieee80211_hw *hw, struct napi_struct *napi, + struct net_device *napi_dev, + int (*poll)(struct napi_struct *, int), + int weight) +{ + struct ieee80211_local *local = hw_to_local(hw); + + netif_napi_add(napi_dev, napi, poll, weight); + local->napi = napi; +} +EXPORT_SYMBOL_GPL(ieee80211_napi_add); + void ieee80211_unregister_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 593062109c50..58e4b7052d17 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1954,7 +1954,10 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) /* deliver to local stack */ skb->protocol = eth_type_trans(skb, dev); memset(skb->cb, 0, sizeof(skb->cb)); - netif_receive_skb(skb); + if (rx->local->napi) + napi_gro_receive(rx->local->napi, skb); + else + netif_receive_skb(skb); } if (xmit_skb) { From 264b8b4e973f8741adf530a388be72af4bfee953 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 8 Jan 2014 16:40:39 +0200 Subject: [PATCH 024/414] Bluetooth: Fix outgoing authentication requirement check The check for HIGH security level dates back to pre-mgmt times when a raw L2CAP socket with HIGH security level was used to trigger dedicated bonding. For legacy pairing checking for the security level was the only way to catch the need to authenticate in all scenarios. With mgmt however, the pair_device command does not use HIGH security but MEDIUM security. Therefore, the existing code would never trigger authentication for a non-SSP connection without an MITM requirement (e.g. if user space provided a NoInputNoOutput IO capability). In such a scenario the mgmt_pair_device command would return success without actually triggering any kind of pairing. This patch updates the authentication requirement check to also consider MEDIUM security level, and thereby ensures that mgmt_pair_device will always trigger authentication. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 5f812455a450..cfcce448957b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1185,9 +1185,12 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev, return 0; /* Only request authentication for SSP connections or non-SSP - * devices with sec_level HIGH or if MITM protection is requested */ + * devices with sec_level MEDIUM or HIGH or if MITM protection + * is requested. + */ if (!hci_conn_ssp_enabled(conn) && !(conn->auth_type & 0x01) && - conn->pending_sec_level != BT_SECURITY_HIGH) + conn->pending_sec_level != BT_SECURITY_HIGH && + conn->pending_sec_level != BT_SECURITY_MEDIUM) return 0; return 1; From d5991585d0bc49dca4ff36d18447bb27ad1ccd73 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:16 -0800 Subject: [PATCH 025/414] Bluetooth: Add LMP feature definitions for Secure Connections support The support for Secure Connections introduces two new controller features and one new host feature. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 4 ++++ include/net/bluetooth/hci_core.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 66c1cd87bfe7..cd40219d32aa 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -282,10 +282,14 @@ enum { #define LMP_SYNC_TRAIN 0x04 #define LMP_SYNC_SCAN 0x08 +#define LMP_SC 0x01 +#define LMP_PING 0x02 + /* Host features */ #define LMP_HOST_SSP 0x01 #define LMP_HOST_LE 0x02 #define LMP_HOST_LE_BREDR 0x04 +#define LMP_HOST_SC 0x08 /* Connection modes */ #define HCI_CM_ACTIVE 0x0000 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index f2f0cf5865c4..bb984d0626b7 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -803,9 +803,12 @@ void hci_conn_del_sysfs(struct hci_conn *conn); #define lmp_csb_slave_capable(dev) ((dev)->features[2][0] & LMP_CSB_SLAVE) #define lmp_sync_train_capable(dev) ((dev)->features[2][0] & LMP_SYNC_TRAIN) #define lmp_sync_scan_capable(dev) ((dev)->features[2][0] & LMP_SYNC_SCAN) +#define lmp_sc_capable(dev) ((dev)->features[2][1] & LMP_SC) +#define lmp_ping_capable(dev) ((dev)->features[2][1] & LMP_PING) /* ----- Host capabilities ----- */ #define lmp_host_ssp_capable(dev) ((dev)->features[1][0] & LMP_HOST_SSP) +#define lmp_host_sc_capable(dev) ((dev)->features[1][0] & LMP_HOST_SC) #define lmp_host_le_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE)) #define lmp_host_le_br_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE_BREDR)) From eb4b95c627258f0b5cee6c26c8e478dda6941e2b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:17 -0800 Subject: [PATCH 026/414] Bluetooth: Add HCI command definition for Secure Connections enabling The Secure Connections feature is optional and host stacks have to manually enable it. This add the HCI command definiton for reading and writing this setting. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index cd40219d32aa..2a35d273de2c 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -937,6 +937,17 @@ struct hci_rp_write_sync_train_params { __le16 sync_train_int; } __packed; +#define HCI_OP_READ_SC_SUPPORT 0x0c79 +struct hci_rp_read_sc_support { + __u8 status; + __u8 support; +} __packed; + +#define HCI_OP_WRITE_SC_SUPPORT 0x0c7a +struct hci_cp_write_sc_support { + __u8 support; +} __packed; + #define HCI_OP_READ_LOCAL_VERSION 0x1001 struct hci_rp_read_local_version { __u8 status; From e2f9913157133c3ffab4b835940927879d541b57 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:18 -0800 Subject: [PATCH 027/414] Bluetooth: Add HCI command definition for extended OOB data The Secure Connections feature introduces the support for P-256 strength pairings (compared to P-192 with Secure Simple Pairing). This however means that for out-of-band pairing the hash and randomizer needs to be differentiated. Two new commands are introduced to handle the possible combinations of P-192 and P-256. This add the HCI command definition for both. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 2a35d273de2c..e4e94bfc5232 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -664,6 +664,15 @@ struct hci_rp_set_csb { #define HCI_OP_START_SYNC_TRAIN 0x0443 +#define HCI_OP_REMOTE_OOB_EXT_DATA_REPLY 0x0445 +struct hci_cp_remote_oob_ext_data_reply { + bdaddr_t bdaddr; + __u8 hash192[16]; + __u8 randomizer192[16]; + __u8 hash256[16]; + __u8 randomizer256[16]; +} __packed; + #define HCI_OP_SNIFF_MODE 0x0803 struct hci_cp_sniff_mode { __le16 handle; @@ -948,6 +957,15 @@ struct hci_cp_write_sc_support { __u8 support; } __packed; +#define HCI_OP_READ_LOCAL_OOB_EXT_DATA 0x0c7d +struct hci_rp_read_local_oob_ext_data { + __u8 status; + __u8 hash192[16]; + __u8 randomizer192[16]; + __u8 hash256[16]; + __u8 randomizer256[16]; +} __packed; + #define HCI_OP_READ_LOCAL_VERSION 0x1001 struct hci_rp_read_local_version { __u8 status; From 11015c7903c74350402f8753339c48bee0186e90 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:19 -0800 Subject: [PATCH 028/414] Bluetooth: Add definitions for new link key types With the introduction of Secure Connections, the list of link key types got extended by P-256 versions of authenticated and unauthenticated link keys. To avoid any confusion the previous authenticated and unauthenticated link key types got ammended with a P912 postfix. And the two new keys have a P256 postfix now. Existing code using the previous definitions has been adjusted. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 6 ++++-- net/bluetooth/hci_conn.c | 4 ++-- net/bluetooth/hci_event.c | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index e4e94bfc5232..8d888bc432c6 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -331,9 +331,11 @@ enum { #define HCI_LK_LOCAL_UNIT 0x01 #define HCI_LK_REMOTE_UNIT 0x02 #define HCI_LK_DEBUG_COMBINATION 0x03 -#define HCI_LK_UNAUTH_COMBINATION 0x04 -#define HCI_LK_AUTH_COMBINATION 0x05 +#define HCI_LK_UNAUTH_COMBINATION_P192 0x04 +#define HCI_LK_AUTH_COMBINATION_P192 0x05 #define HCI_LK_CHANGED_COMBINATION 0x06 +#define HCI_LK_UNAUTH_COMBINATION_P256 0x07 +#define HCI_LK_AUTH_COMBINATION_P256 0x08 /* The spec doesn't define types for SMP keys, the _MASTER suffix is implied */ #define HCI_SMP_STK 0x80 #define HCI_SMP_STK_SLAVE 0x81 diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index ba5366c320da..251f22e32fbf 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -802,12 +802,12 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) /* An authenticated combination key has sufficient security for any security level. */ - if (conn->key_type == HCI_LK_AUTH_COMBINATION) + if (conn->key_type == HCI_LK_AUTH_COMBINATION_P192) goto encrypt; /* An unauthenticated combination key has sufficient security for security level 1 and 2. */ - if (conn->key_type == HCI_LK_UNAUTH_COMBINATION && + if (conn->key_type == HCI_LK_UNAUTH_COMBINATION_P192 && (sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW)) goto encrypt; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index cfcce448957b..defa1252b534 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2633,7 +2633,7 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); if (conn) { - if (key->type == HCI_LK_UNAUTH_COMBINATION && + if (key->type == HCI_LK_UNAUTH_COMBINATION_P192 && conn->auth_type != 0xff && (conn->auth_type & 0x01)) { BT_DBG("%s ignoring unauthenticated key", hdev->name); goto not_found; From 66138ce8e556a8ddd13baf035fb3a8d0d6dd4bb5 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:20 -0800 Subject: [PATCH 029/414] Bluetooth: Add support for handling P-256 derived link keys Before being able to enable Secure Connections support, the core needs to know on how to handle P-256 derived link keys. The difference between authenticated and unauthenticated P-256 derived link keys is the same as its P-192 counter parts. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 6 ++++-- net/bluetooth/hci_event.c | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 251f22e32fbf..cf96b3438a91 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -802,12 +802,14 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) /* An authenticated combination key has sufficient security for any security level. */ - if (conn->key_type == HCI_LK_AUTH_COMBINATION_P192) + if (conn->key_type == HCI_LK_AUTH_COMBINATION_P192 || + conn->key_type == HCI_LK_AUTH_COMBINATION_P256) goto encrypt; /* An unauthenticated combination key has sufficient security for security level 1 and 2. */ - if (conn->key_type == HCI_LK_UNAUTH_COMBINATION_P192 && + if ((conn->key_type == HCI_LK_UNAUTH_COMBINATION_P192 || + conn->key_type == HCI_LK_UNAUTH_COMBINATION_P256) && (sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW)) goto encrypt; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index defa1252b534..b3c5396e0c1b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2633,7 +2633,8 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); if (conn) { - if (key->type == HCI_LK_UNAUTH_COMBINATION_P192 && + if ((key->type == HCI_LK_UNAUTH_COMBINATION_P192 || + key->type == HCI_LK_UNAUTH_COMBINATION_P256) && conn->auth_type != 0xff && (conn->auth_type & 0x01)) { BT_DBG("%s ignoring unauthenticated key", hdev->name); goto not_found; From 40c59fcbcdc25d5b1aafef23b94167c2376b0dce Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:21 -0800 Subject: [PATCH 030/414] Bluetooth: Enable Authenticated Payload Timeout Expired event With Secure Connections capable controllers, the authenticated payload timeout can trigger. Enable the event so the controller informs the host when this happens. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 5e8663c194c1..52e398f37129 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1288,6 +1288,10 @@ static void hci_set_event_mask_page_2(struct hci_request *req) events[2] |= 0x08; /* Truncated Page Complete */ } + /* Enable Authenticated Payload Timeout Expired event if supported */ + if (lmp_ping_capable(hdev)) + events[2] |= 0x80; + hci_req_add(req, HCI_OP_SET_EVENT_MASK_PAGE_2, sizeof(events), events); } From e98d2ce293a941d41b5c8435975ff25a1b858bf9 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:22 -0800 Subject: [PATCH 031/414] Bluetooth: Add flags and setting for Secure Connections support The MGMT_SETTING_SECURE_CONN setting is used to track the support and status for Secure Connections from the management interface. For HCI based tracking HCI_SC_ENABLED flag is used. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/mgmt.h | 1 + net/bluetooth/mgmt.c | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 8d888bc432c6..0253276e88e4 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -122,6 +122,7 @@ enum { HCI_LE_SCAN, HCI_SSP_ENABLED, + HCI_SC_ENABLED, HCI_HS_ENABLED, HCI_LE_ENABLED, HCI_ADVERTISING, diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 518c5c84e39a..4ec17dec62e0 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -94,6 +94,7 @@ struct mgmt_rp_read_index_list { #define MGMT_SETTING_HS 0x00000100 #define MGMT_SETTING_LE 0x00000200 #define MGMT_SETTING_ADVERTISING 0x00000400 +#define MGMT_SETTING_SECURE_CONN 0x00000800 #define MGMT_OP_READ_INFO 0x0004 #define MGMT_READ_INFO_SIZE 0 diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a03ca3ca91bf..b00fa0253cba 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -79,6 +79,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_SET_BREDR, MGMT_OP_SET_STATIC_ADDRESS, MGMT_OP_SET_SCAN_PARAMS, + MGMT_OP_SET_SECURE_CONN, }; static const u16 mgmt_events[] = { @@ -376,6 +377,9 @@ static u32 get_supported_settings(struct hci_dev *hdev) settings |= MGMT_SETTING_SSP; settings |= MGMT_SETTING_HS; } + + if (lmp_sc_capable(hdev)) + settings |= MGMT_SETTING_SECURE_CONN; } if (lmp_le_capable(hdev)) { @@ -423,6 +427,9 @@ static u32 get_current_settings(struct hci_dev *hdev) if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) settings |= MGMT_SETTING_ADVERTISING; + if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) + settings |= MGMT_SETTING_SECURE_CONN; + return settings; } From eac83dc632a7afba72f7084266bc310219486253 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:23 -0800 Subject: [PATCH 032/414] Bluetooth: Add management command for enabling Secure Connections The support for Secure Connections need to be explicitly enabled by userspace. This is required since only userspace that can handle the new link key types should enable support for Secure Connections. This command handling is similar to how Secure Simple Pairing enabling is done. It also tracks the case when Secure Connections support is enabled via raw HCI commands. This makes sure that the host features page is updated as well. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/mgmt.h | 2 + net/bluetooth/hci_event.c | 32 ++++++++++ net/bluetooth/mgmt.c | 106 +++++++++++++++++++++++++++++++ 4 files changed, 141 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index bb984d0626b7..1eb55ec40ac0 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1125,6 +1125,7 @@ void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status); void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); +void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, u8 status); void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 4ec17dec62e0..8a2c78175997 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -370,6 +370,8 @@ struct mgmt_cp_set_scan_params { } __packed; #define MGMT_SET_SCAN_PARAMS_SIZE 4 +#define MGMT_OP_SET_SECURE_CONN 0x002D + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index b3c5396e0c1b..b6f0c241e236 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -461,6 +461,34 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) } } +static void hci_cc_write_sc_support(struct hci_dev *hdev, struct sk_buff *skb) +{ + u8 status = *((u8 *) skb->data); + struct hci_cp_write_sc_support *sent; + + BT_DBG("%s status 0x%2.2x", hdev->name, status); + + sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SC_SUPPORT); + if (!sent) + return; + + if (!status) { + if (sent->support) + hdev->features[1][0] |= LMP_HOST_SC; + else + hdev->features[1][0] &= ~LMP_HOST_SC; + } + + if (test_bit(HCI_MGMT, &hdev->dev_flags)) + mgmt_sc_enable_complete(hdev, sent->support, status); + else if (!status) { + if (sent->support) + set_bit(HCI_SC_ENABLED, &hdev->dev_flags); + else + clear_bit(HCI_SC_ENABLED, &hdev->dev_flags); + } +} + static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_rp_read_local_version *rp = (void *) skb->data; @@ -2147,6 +2175,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_cc_write_ssp_mode(hdev, skb); break; + case HCI_OP_WRITE_SC_SUPPORT: + hci_cc_write_sc_support(hdev, skb); + break; + case HCI_OP_READ_LOCAL_VERSION: hci_cc_read_local_version(hdev, skb); break; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index b00fa0253cba..68a3c998d19c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4006,6 +4006,79 @@ unlock: return err; } +static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_mode *cp = data; + struct pending_cmd *cmd; + u8 status; + int err; + + BT_DBG("request for %s", hdev->name); + + status = mgmt_bredr_support(hdev); + if (status) + return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, + status); + + if (!lmp_sc_capable(hdev)) + return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, + MGMT_STATUS_NOT_SUPPORTED); + + if (cp->val != 0x00 && cp->val != 0x01) + return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, + MGMT_STATUS_INVALID_PARAMS); + + hci_dev_lock(hdev); + + if (!hdev_is_powered(hdev)) { + bool changed; + + if (cp->val) + changed = !test_and_set_bit(HCI_SC_ENABLED, + &hdev->dev_flags); + else + changed = test_and_clear_bit(HCI_SC_ENABLED, + &hdev->dev_flags); + + err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev); + if (err < 0) + goto failed; + + if (changed) + err = new_settings(hdev, sk); + + goto failed; + } + + if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) { + err = cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, + MGMT_STATUS_BUSY); + goto failed; + } + + if (!!cp->val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) { + err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev); + goto failed; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + + err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &cp->val); + if (err < 0) { + mgmt_pending_remove(cmd); + goto failed; + } + +failed: + hci_dev_unlock(hdev); + return err; +} + static bool ltk_is_valid(struct mgmt_ltk_info *key) { if (key->authenticated != 0x00 && key->authenticated != 0x01) @@ -4134,6 +4207,7 @@ static const struct mgmt_handler { { set_bredr, false, MGMT_SETTING_SIZE }, { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE }, { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE }, + { set_secure_conn, false, MGMT_SETTING_SIZE }, }; @@ -4917,6 +4991,38 @@ void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) hci_req_run(&req, NULL); } +void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) +{ + struct cmd_lookup match = { NULL, hdev }; + bool changed = false; + + if (status) { + u8 mgmt_err = mgmt_status(status); + + if (enable && test_and_clear_bit(HCI_SC_ENABLED, + &hdev->dev_flags)) + new_settings(hdev, NULL); + + mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev, + cmd_status_rsp, &mgmt_err); + return; + } + + if (enable) + changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags); + else + changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags); + + mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev, + settings_rsp, &match); + + if (changed) + new_settings(hdev, match.sk); + + if (match.sk) + sock_put(match.sk); +} + static void sk_lookup(struct pending_cmd *cmd, void *data) { struct cmd_lookup *match = data; From a6d0d690e1bd56ce031f38a3144cb9f6ea23456f Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:24 -0800 Subject: [PATCH 033/414] Bluetooth: Enable Secure Connection during power on if configured If support for Secure Connection has been configured, then make sure to send the appropiate HCI command to enable it when powering on the controller. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 52e398f37129..b3b619a448b5 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1363,6 +1363,14 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt) /* Check for Synchronization Train support */ if (lmp_sync_train_capable(hdev)) hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL); + + /* Enable Secure Connections if supported and configured */ + if (lmp_sc_capable(hdev) && + test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) { + u8 support = 0x01; + hci_req_add(req, HCI_OP_WRITE_SC_SUPPORT, + sizeof(support), &support); + } } static int __hci_init(struct hci_dev *hdev) From 8e99113277fb9f7b8b28fbcc866a359d2fa1ba41 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:25 -0800 Subject: [PATCH 034/414] Bluetooth: Limit acceptable link key types to only supported ones The link keys that are loaded by userspace during controller setup should be limited to actual valid and supported types. With the support for Secure Connections, it is limited to types 0x00 - 0x08 at the moment. Reject any other link key types. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 68a3c998d19c..9b162038acb7 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2241,7 +2241,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, for (i = 0; i < key_count; i++) { struct mgmt_link_key_info *key = &cp->keys[i]; - if (key->addr.type != BDADDR_BREDR) + if (key->addr.type != BDADDR_BREDR || key->type > 0x08) return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, MGMT_STATUS_INVALID_PARAMS); } From 4d2d27962642e23f88745b0430d47c3ff75afdd3 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:26 -0800 Subject: [PATCH 035/414] Bluetooth: Add support for local OOB data with Secure Connections For Secure Connections support and the usage of out-of-band pairing, it is needed to read the P-256 hash and randomizer or P-192 hash and randomizer. This change will read P-192 data when Secure Connections is disabled and P-192 and P-256 data when it is enabled. The difference is between using HCI Read Local OOB Data and using the new HCI Read Local OOB Extended Data command. The first one has been introduced with Bluetooth 2.1 and returns only the P-192 data. < HCI Command: Read Local OOB Data (0x03|0x0057) plen 0 > HCI Event: Command Complete (0x0e) plen 36 Read Local OOB Data (0x03|0x0057) ncmd 1 Status: Success (0x00) Hash C from P-192: 975a59baa1c4eee391477cb410b23e6d Randomizer R with P-192: 9ee63b7dec411d3b467c5ae446df7f7d The second command has been introduced with Bluetooth 4.1 and will return P-192 and P-256 data. < HCI Command: Read Local OOB Extended Data (0x03|0x007d) plen 0 > HCI Event: Command Complete (0x0e) plen 68 Read Local OOB Extended Data (0x03|0x007d) ncmd 1 Status: Success (0x00) Hash C from P-192: 6489731804b156fa6355efb8124a1389 Randomizer R with P-192: 4781d5352fb215b2958222b3937b6026 Hash C from P-256: 69ef8a928b9d07fc149e630e74ecb991 Randomizer R with P-256: 4781d5352fb215b2958222b3937b6026 The change for the management interface is transparent and no change is required for existing userspace. The Secure Connections feature needs to be manually enabled. When it is disabled, then userspace only gets the P-192 returned and with Secure Connections enabled, userspace gets P-192 and P-256 in an extended structure. It is also acceptable to just ignore the P-256 data since it is not required to support them. The pairing with out-of-band credentials will still succeed. However then of course no Secure Connection will b established. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 5 ++-- include/net/bluetooth/mgmt.h | 6 +++++ net/bluetooth/hci_event.c | 28 ++++++++++++++++++---- net/bluetooth/mgmt.c | 41 +++++++++++++++++++++++++------- 4 files changed, 65 insertions(+), 15 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 1eb55ec40ac0..bd15eaa4c06e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1129,8 +1129,9 @@ void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, u8 status); void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status); -void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, - u8 *randomizer, u8 status); +void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192, + u8 *randomizer192, u8 *hash256, + u8 *randomizer256, u8 status); void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8 ssp, u8 *eir, u16 eir_len); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 8a2c78175997..036ddc7dc7ed 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -295,6 +295,12 @@ struct mgmt_rp_read_local_oob_data { __u8 hash[16]; __u8 randomizer[16]; } __packed; +struct mgmt_rp_read_local_oob_ext_data { + __u8 hash192[16]; + __u8 randomizer192[16]; + __u8 hash256[16]; + __u8 randomizer256[16]; +} __packed; #define MGMT_OP_ADD_REMOTE_OOB_DATA 0x0021 struct mgmt_cp_add_remote_oob_data { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index b6f0c241e236..d5374d36e9fe 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -932,16 +932,30 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev, hci_dev_unlock(hdev); } -static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev, - struct sk_buff *skb) +static void hci_cc_read_local_oob_data(struct hci_dev *hdev, + struct sk_buff *skb) { struct hci_rp_read_local_oob_data *rp = (void *) skb->data; BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); hci_dev_lock(hdev); - mgmt_read_local_oob_data_reply_complete(hdev, rp->hash, - rp->randomizer, rp->status); + mgmt_read_local_oob_data_complete(hdev, rp->hash, rp->randomizer, + NULL, NULL, rp->status); + hci_dev_unlock(hdev); +} + +static void hci_cc_read_local_oob_ext_data(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data; + + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); + + hci_dev_lock(hdev); + mgmt_read_local_oob_data_complete(hdev, rp->hash192, rp->randomizer192, + rp->hash256, rp->randomizer256, + rp->status); hci_dev_unlock(hdev); } @@ -2248,7 +2262,11 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) break; case HCI_OP_READ_LOCAL_OOB_DATA: - hci_cc_read_local_oob_data_reply(hdev, skb); + hci_cc_read_local_oob_data(hdev, skb); + break; + + case HCI_OP_READ_LOCAL_OOB_EXT_DATA: + hci_cc_read_local_oob_ext_data(hdev, skb); break; case HCI_OP_LE_READ_BUFFER_SIZE: diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9b162038acb7..a7d4ae679ab7 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3078,7 +3078,12 @@ static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev, goto unlock; } - err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL); + if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) + err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA, + 0, NULL); + else + err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL); + if (err < 0) mgmt_pending_remove(cmd); @@ -5077,8 +5082,9 @@ void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) cmd ? cmd->sk : NULL); } -void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, - u8 *randomizer, u8 status) +void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192, + u8 *randomizer192, u8 *hash256, + u8 *randomizer256, u8 status) { struct pending_cmd *cmd; @@ -5092,13 +5098,32 @@ void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, mgmt_status(status)); } else { - struct mgmt_rp_read_local_oob_data rp; + if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) && + hash256 && randomizer256) { + struct mgmt_rp_read_local_oob_ext_data rp; - memcpy(rp.hash, hash, sizeof(rp.hash)); - memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer)); + memcpy(rp.hash192, hash192, sizeof(rp.hash192)); + memcpy(rp.randomizer192, randomizer192, + sizeof(rp.randomizer192)); - cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, - 0, &rp, sizeof(rp)); + memcpy(rp.hash256, hash256, sizeof(rp.hash256)); + memcpy(rp.randomizer256, randomizer256, + sizeof(rp.randomizer256)); + + cmd_complete(cmd->sk, hdev->id, + MGMT_OP_READ_LOCAL_OOB_DATA, 0, + &rp, sizeof(rp)); + } else { + struct mgmt_rp_read_local_oob_data rp; + + memcpy(rp.hash, hash192, sizeof(rp.hash)); + memcpy(rp.randomizer, randomizer192, + sizeof(rp.randomizer)); + + cmd_complete(cmd->sk, hdev->id, + MGMT_OP_READ_LOCAL_OOB_DATA, 0, + &rp, sizeof(rp)); + } } mgmt_pending_remove(cmd); From 5afeac149ebc94485b750eb841d0f971ea9772cd Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:27 -0800 Subject: [PATCH 036/414] Bluetooth: Add debugfs quirk for forcing Secure Connections support The Bluetooth 4.1 specification with Secure Connections support has just been released and controllers with this feature are still in an early stage. A handful of controllers have already support for it, but they do not always identify this feature correctly. This debugfs entry allows to tell the kernel that the controller can be treated as it would fully support Secure Connections. Using debugfs to force Secure Connections support of course does not make this feature magically appear in all controllers. This is a debug functionality for early adopters. Once the majority of controllers matures this quirk will be removed. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_core.c | 51 ++++++++++++++++++++++++++++++++++++- net/bluetooth/mgmt.c | 6 +++-- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 0253276e88e4..2bc19881e250 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -117,6 +117,7 @@ enum { HCI_SERVICE_CACHE, HCI_DEBUG_KEYS, HCI_DUT_MODE, + HCI_FORCE_SC, HCI_UNREGISTER, HCI_USER_CHANNEL, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b3b619a448b5..946631ffe802 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -415,6 +415,52 @@ static int ssp_debug_mode_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(ssp_debug_mode_fops, ssp_debug_mode_get, ssp_debug_mode_set, "%llu\n"); +static ssize_t force_sc_support_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct hci_dev *hdev = file->private_data; + char buf[3]; + + buf[0] = test_bit(HCI_FORCE_SC, &hdev->dev_flags) ? 'Y': 'N'; + buf[1] = '\n'; + buf[2] = '\0'; + return simple_read_from_buffer(user_buf, count, ppos, buf, 2); +} + +static ssize_t force_sc_support_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct hci_dev *hdev = file->private_data; + char buf[32]; + size_t buf_size = min(count, (sizeof(buf)-1)); + bool enable; + + if (test_bit(HCI_UP, &hdev->flags)) + return -EBUSY; + + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + buf[buf_size] = '\0'; + if (strtobool(buf, &enable)) + return -EINVAL; + + if (enable == test_bit(HCI_FORCE_SC, &hdev->dev_flags)) + return -EALREADY; + + change_bit(HCI_FORCE_SC, &hdev->dev_flags); + + return count; +} + +static const struct file_operations force_sc_support_fops = { + .open = simple_open, + .read = force_sc_support_read, + .write = force_sc_support_write, + .llseek = default_llseek, +}; + static int idle_timeout_set(void *data, u64 val) { struct hci_dev *hdev = data; @@ -1365,7 +1411,8 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt) hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL); /* Enable Secure Connections if supported and configured */ - if (lmp_sc_capable(hdev) && + if ((lmp_sc_capable(hdev) || + test_bit(HCI_FORCE_SC, &hdev->dev_flags)) && test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) { u8 support = 0x01; hci_req_add(req, HCI_OP_WRITE_SC_SUPPORT, @@ -1442,6 +1489,8 @@ static int __hci_init(struct hci_dev *hdev) hdev, &auto_accept_delay_fops); debugfs_create_file("ssp_debug_mode", 0644, hdev->debugfs, hdev, &ssp_debug_mode_fops); + debugfs_create_file("force_sc_support", 0644, hdev->debugfs, + hdev, &force_sc_support_fops); } if (lmp_sniff_capable(hdev)) { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a7d4ae679ab7..bbe30c983492 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -378,7 +378,8 @@ static u32 get_supported_settings(struct hci_dev *hdev) settings |= MGMT_SETTING_HS; } - if (lmp_sc_capable(hdev)) + if (lmp_sc_capable(hdev) || + test_bit(HCI_FORCE_SC, &hdev->dev_flags)) settings |= MGMT_SETTING_SECURE_CONN; } @@ -4026,7 +4027,8 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, status); - if (!lmp_sc_capable(hdev)) + if (!lmp_sc_capable(hdev) && + !test_bit(HCI_FORCE_SC, &hdev->dev_flags)) return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, MGMT_STATUS_NOT_SUPPORTED); From 519ca9d017ab7eb4a15787bd8f2d867bebe375bc Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:28 -0800 Subject: [PATCH 037/414] Bluetooth: Provide remote OOB data for Secure Connections When Secure Connections has been enabled it is possible to provide P-192 and/or P-256 data during the pairing process. The internal out-of-band credentials storage has been extended to also hold P-256 data. Initially the P-256 data will be empty and with Secure Connections enabled no P-256 data will be provided. This is according to the specification since it might be possible that the remote side did not provide either of the out-of-band credentials. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 6 ++++-- net/bluetooth/hci_core.c | 6 +++--- net/bluetooth/hci_event.c | 32 ++++++++++++++++++++++++-------- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index bd15eaa4c06e..5948930f92e6 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -114,8 +114,10 @@ struct link_key { struct oob_data { struct list_head list; bdaddr_t bdaddr; - u8 hash[16]; - u8 randomizer[16]; + u8 hash192[16]; + u8 randomizer192[16]; + u8 hash256[16]; + u8 randomizer256[16]; }; #define HCI_MAX_SHORT_NAME_LENGTH 10 diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 946631ffe802..f13c0550f368 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2802,7 +2802,7 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, data = hci_find_remote_oob_data(hdev, bdaddr); if (!data) { - data = kmalloc(sizeof(*data), GFP_ATOMIC); + data = kzalloc(sizeof(*data), GFP_ATOMIC); if (!data) return -ENOMEM; @@ -2810,8 +2810,8 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, list_add(&data->list, &hdev->remote_oob_data); } - memcpy(data->hash, hash, sizeof(data->hash)); - memcpy(data->randomizer, randomizer, sizeof(data->randomizer)); + memcpy(data->hash192, hash, sizeof(data->hash192)); + memcpy(data->randomizer192, randomizer, sizeof(data->randomizer192)); BT_DBG("%s for %pMR", hdev->name, bdaddr); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d5374d36e9fe..da1eca1c43db 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3391,20 +3391,36 @@ static void hci_remote_oob_data_request_evt(struct hci_dev *hdev, data = hci_find_remote_oob_data(hdev, &ev->bdaddr); if (data) { - struct hci_cp_remote_oob_data_reply cp; + if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) { + struct hci_cp_remote_oob_ext_data_reply cp; - bacpy(&cp.bdaddr, &ev->bdaddr); - memcpy(cp.hash, data->hash, sizeof(cp.hash)); - memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer)); + bacpy(&cp.bdaddr, &ev->bdaddr); + memcpy(cp.hash192, data->hash192, sizeof(cp.hash192)); + memcpy(cp.randomizer192, data->randomizer192, + sizeof(cp.randomizer192)); + memcpy(cp.hash256, data->hash256, sizeof(cp.hash256)); + memcpy(cp.randomizer256, data->randomizer256, + sizeof(cp.randomizer256)); - hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp), - &cp); + hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_EXT_DATA_REPLY, + sizeof(cp), &cp); + } else { + struct hci_cp_remote_oob_data_reply cp; + + bacpy(&cp.bdaddr, &ev->bdaddr); + memcpy(cp.hash, data->hash192, sizeof(cp.hash)); + memcpy(cp.randomizer, data->randomizer192, + sizeof(cp.randomizer)); + + hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, + sizeof(cp), &cp); + } } else { struct hci_cp_remote_oob_data_neg_reply cp; bacpy(&cp.bdaddr, &ev->bdaddr); - hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp), - &cp); + hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, + sizeof(cp), &cp); } unlock: From 0798872ef1ad6433362faca1d16a31ad7ad72638 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:29 -0800 Subject: [PATCH 038/414] Bluetooth: Add internal function for storing P-192 and P-256 data Add function to allow adding P-192 and P-256 data to the internal storage. This also fixes a few coding style issues from the previous helper functions for the out-of-band credentials storage. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 9 +++++--- net/bluetooth/hci_core.c | 37 ++++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 5948930f92e6..66e96ebffe97 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -761,9 +761,12 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_remote_oob_data_clear(struct hci_dev *hdev); struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev, - bdaddr_t *bdaddr); -int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, - u8 *randomizer); + bdaddr_t *bdaddr); +int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 *hash, u8 *randomizer); +int hci_add_remote_oob_ext_data(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 *hash192, u8 *randomizer192, + u8 *hash256, u8 *randomizer256); int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr); void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f13c0550f368..499ec1b1095d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2794,15 +2794,14 @@ int hci_remote_oob_data_clear(struct hci_dev *hdev) return 0; } -int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, - u8 *randomizer) +int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 *hash, u8 *randomizer) { struct oob_data *data; data = hci_find_remote_oob_data(hdev, bdaddr); - if (!data) { - data = kzalloc(sizeof(*data), GFP_ATOMIC); + data = kmalloc(sizeof(*data), GFP_ATOMIC); if (!data) return -ENOMEM; @@ -2813,6 +2812,36 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, memcpy(data->hash192, hash, sizeof(data->hash192)); memcpy(data->randomizer192, randomizer, sizeof(data->randomizer192)); + memset(data->hash256, 0, sizeof(data->hash256)); + memset(data->randomizer256, 0, sizeof(data->randomizer256)); + + BT_DBG("%s for %pMR", hdev->name, bdaddr); + + return 0; +} + +int hci_add_remote_oob_ext_data(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 *hash192, u8 *randomizer192, + u8 *hash256, u8 *randomizer256) +{ + struct oob_data *data; + + data = hci_find_remote_oob_data(hdev, bdaddr); + if (!data) { + data = kmalloc(sizeof(*data), GFP_ATOMIC); + if (!data) + return -ENOMEM; + + bacpy(&data->bdaddr, bdaddr); + list_add(&data->list, &hdev->remote_oob_data); + } + + memcpy(data->hash192, hash192, sizeof(data->hash192)); + memcpy(data->randomizer192, randomizer192, sizeof(data->randomizer192)); + + memcpy(data->hash256, hash256, sizeof(data->hash256)); + memcpy(data->randomizer256, randomizer256, sizeof(data->randomizer256)); + BT_DBG("%s for %pMR", hdev->name, bdaddr); return 0; From ec1091131f9b53ea280247b5a01a617ce87d399e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:30 -0800 Subject: [PATCH 039/414] Bluetooth: Add support for remote OOB input of P-256 data The current management interface only allows to provide the remote OOB input of P-192 data. This extends the command to also accept P-256 data as well. To make this backwards compatible, the userspace can decide to only provide P-192 data or the combined P-192 and P-256 data. It is also allowed to leave the P-192 data empty if userspace only has the remote P-256 data. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/mgmt.h | 8 +++++++ net/bluetooth/mgmt.c | 45 +++++++++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 036ddc7dc7ed..e19049fb6c46 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -309,6 +309,14 @@ struct mgmt_cp_add_remote_oob_data { __u8 randomizer[16]; } __packed; #define MGMT_ADD_REMOTE_OOB_DATA_SIZE (MGMT_ADDR_INFO_SIZE + 32) +struct mgmt_cp_add_remote_oob_ext_data { + struct mgmt_addr_info addr; + __u8 hash192[16]; + __u8 randomizer192[16]; + __u8 hash256[16]; + __u8 randomizer256[16]; +} __packed; +#define MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE (MGMT_ADDR_INFO_SIZE + 64) #define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x0022 struct mgmt_cp_remove_remote_oob_data { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bbe30c983492..4b6034fcc902 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3096,23 +3096,46 @@ unlock: static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { - struct mgmt_cp_add_remote_oob_data *cp = data; - u8 status; int err; BT_DBG("%s ", hdev->name); hci_dev_lock(hdev); - err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash, - cp->randomizer); - if (err < 0) - status = MGMT_STATUS_FAILED; - else - status = MGMT_STATUS_SUCCESS; + if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) { + struct mgmt_cp_add_remote_oob_data *cp = data; + u8 status; - err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status, - &cp->addr, sizeof(cp->addr)); + err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, + cp->hash, cp->randomizer); + if (err < 0) + status = MGMT_STATUS_FAILED; + else + status = MGMT_STATUS_SUCCESS; + + err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, + status, &cp->addr, sizeof(cp->addr)); + } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) { + struct mgmt_cp_add_remote_oob_ext_data *cp = data; + u8 status; + + err = hci_add_remote_oob_ext_data(hdev, &cp->addr.bdaddr, + cp->hash192, + cp->randomizer192, + cp->hash256, + cp->randomizer256); + if (err < 0) + status = MGMT_STATUS_FAILED; + else + status = MGMT_STATUS_SUCCESS; + + err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, + status, &cp->addr, sizeof(cp->addr)); + } else { + BT_ERR("add_remote_oob_data: invalid length of %u bytes", len); + err = cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, + MGMT_STATUS_INVALID_PARAMS); + } hci_dev_unlock(hdev); return err; @@ -4202,7 +4225,7 @@ static const struct mgmt_handler { { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE }, { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE }, { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE }, - { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE }, + { add_remote_oob_data, true, MGMT_ADD_REMOTE_OOB_DATA_SIZE }, { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE }, { start_discovery, false, MGMT_START_DISCOVERY_SIZE }, { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE }, From b848079a5e55480e16439af62c94f02ca1e33b08 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 7 Jan 2014 22:23:08 +0800 Subject: [PATCH 040/414] Bluetooth: Convert to use ATTRIBUTE_GROUPS macro Use ATTRIBUTE_GROUPS macro to reduce the number of lines of code. Signed-off-by: Wei Yongjun Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sysfs.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 0b61250cfdf9..555982a78a58 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -49,14 +49,7 @@ static struct attribute *bt_link_attrs[] = { NULL }; -static struct attribute_group bt_link_group = { - .attrs = bt_link_attrs, -}; - -static const struct attribute_group *bt_link_groups[] = { - &bt_link_group, - NULL -}; +ATTRIBUTE_GROUPS(bt_link); static void bt_link_release(struct device *dev) { @@ -182,14 +175,7 @@ static struct attribute *bt_host_attrs[] = { NULL }; -static struct attribute_group bt_host_group = { - .attrs = bt_host_attrs, -}; - -static const struct attribute_group *bt_host_groups[] = { - &bt_host_group, - NULL -}; +ATTRIBUTE_GROUPS(bt_host); static void bt_host_release(struct device *dev) { From eadd663a6ab78df479d116a59368a70dc60d8288 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 13 Jan 2014 17:15:53 +0200 Subject: [PATCH 041/414] Bluetooth: Fix mgmt error code for negative PIN response The NOT_PAIRED status is only really suitable for operations where being paired is a pre-requisite. Using it e.g. for the mgmt_pair_device command seems unintuitive. In the case that either the local or the remote user responds with a negative PIN Code response the "PIN or Key Missing" HCI status will be generated. This patch changes the mapping of this status from the NOT_PAIRED mgmt status to the more intuitive AUTH_FAILED mgmt status. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4b6034fcc902..4ee07b432379 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -128,7 +128,7 @@ static u8 mgmt_status_table[] = { MGMT_STATUS_FAILED, /* Hardware Failure */ MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */ MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */ - MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */ + MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */ MGMT_STATUS_NO_RESOURCES, /* Memory Full */ MGMT_STATUS_TIMEOUT, /* Connection Timeout */ MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */ From eb9a8f3fb6762a4e6ae0aa9e96532c9c544f400e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 15 Jan 2014 22:37:38 -0800 Subject: [PATCH 042/414] Bluetooth: Track Secure Connections support of remote devices It is important to know if Secure Connections support has been enabled for a given remote device. The information is provided in the remote host features page. So track this information and provide a simple helper function to extract the status. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 8 ++++++++ net/bluetooth/hci_event.c | 3 +++ 2 files changed, 11 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 66e96ebffe97..8d225e4ea2ce 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -448,6 +448,7 @@ enum { HCI_CONN_LE_SMP_PEND, HCI_CONN_MGMT_CONNECTED, HCI_CONN_SSP_ENABLED, + HCI_CONN_SC_ENABLED, HCI_CONN_POWER_SAVE, HCI_CONN_REMOTE_OOB, HCI_CONN_6LOWPAN, @@ -460,6 +461,13 @@ static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) test_bit(HCI_CONN_SSP_ENABLED, &conn->flags); } +static inline bool hci_conn_sc_enabled(struct hci_conn *conn) +{ + struct hci_dev *hdev = conn->hdev; + return test_bit(HCI_SC_ENABLED, &hdev->dev_flags) && + test_bit(HCI_CONN_SC_ENABLED, &conn->flags); +} + static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) { struct hci_conn_hash *h = &hdev->conn_hash; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index da1eca1c43db..8c44bbe19add 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2898,6 +2898,9 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev, * features do not indicate SSP support */ clear_bit(HCI_CONN_SSP_ENABLED, &conn->flags); } + + if (ev->features[0] & LMP_HOST_SC) + set_bit(HCI_CONN_SC_ENABLED, &conn->flags); } if (conn->state != BT_CONFIG) From 7b5a9241b780ea2f77e71647bc0d3c9708c18ef1 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 15 Jan 2014 22:37:39 -0800 Subject: [PATCH 043/414] Bluetooth: Introduce requirements for security level 4 The security level 4 is a new strong security requirement that is based around 128-bit equivalent strength for link and encryption keys required using FIPS approved algorithms. Which means that E0, SAFER+ and P-192 are not allowed. Only connections created with P-256 resulting from using Secure Connections support are allowed. This security level needs to be enforced when Secure Connection Only mode is enabled for a controller or a service requires FIPS compliant strong security. Currently it is not possible to enable either of these two cases. This patch just puts in the foundation for being able to handle security level 4 in the future. It should be noted that devices or services with security level 4 requirement can only communicate using Bluetooth 4.1 controllers with support for Secure Connections. There is no backward compatibilty if used with older hardware. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/bluetooth.h | 1 + include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_conn.c | 18 +++++++++++++----- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index f4f9ee466791..904777c1cd24 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -65,6 +65,7 @@ struct bt_security { #define BT_SECURITY_LOW 1 #define BT_SECURITY_MEDIUM 2 #define BT_SECURITY_HIGH 3 +#define BT_SECURITY_FIPS 4 #define BT_DEFER_SETUP 7 diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 2bc19881e250..0064a9aa5df1 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -313,6 +313,7 @@ enum { #define HCI_LM_TRUSTED 0x0008 #define HCI_LM_RELIABLE 0x0010 #define HCI_LM_SECURE 0x0020 +#define HCI_LM_FIPS 0x0040 /* Authentication types */ #define HCI_AT_NO_BONDING 0x00 diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index cf96b3438a91..0266bd8e4913 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -800,10 +800,17 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) if (!(conn->link_mode & HCI_LM_AUTH)) goto auth; - /* An authenticated combination key has sufficient security for any - security level. */ - if (conn->key_type == HCI_LK_AUTH_COMBINATION_P192 || - conn->key_type == HCI_LK_AUTH_COMBINATION_P256) + /* An authenticated FIPS approved combination key has sufficient + * security for security level 4. */ + if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256 && + sec_level == BT_SECURITY_FIPS) + goto encrypt; + + /* An authenticated combination key has sufficient security for + security level 3. */ + if ((conn->key_type == HCI_LK_AUTH_COMBINATION_P192 || + conn->key_type == HCI_LK_AUTH_COMBINATION_P256) && + sec_level == BT_SECURITY_HIGH) goto encrypt; /* An unauthenticated combination key has sufficient security for @@ -818,7 +825,8 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) is generated using maximum PIN code length (16). For pre 2.1 units. */ if (conn->key_type == HCI_LK_COMBINATION && - (sec_level != BT_SECURITY_HIGH || conn->pin_length == 16)) + (sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW || + conn->pin_length == 16)) goto encrypt; auth: From 7d513e9243afd01df315db45ffe96a6e3688e612 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 15 Jan 2014 22:37:40 -0800 Subject: [PATCH 044/414] Bluetooth: Handle security level 4 for L2CAP connections With the introduction of security level 4, the L2CAP sockets need to be made aware of this new level. This change ensures that the pairing requirements are set correctly for these connections. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_core.c | 11 ++++++++--- net/bluetooth/l2cap_sock.c | 10 ++++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index dbc4a89984ca..c695083eee2b 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -91,6 +91,7 @@ struct l2cap_conninfo { #define L2CAP_LM_TRUSTED 0x0008 #define L2CAP_LM_RELIABLE 0x0010 #define L2CAP_LM_SECURE 0x0020 +#define L2CAP_LM_FIPS 0x0040 /* L2CAP command codes */ #define L2CAP_COMMAND_REJ 0x01 diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b0ad2c752d73..3f0dd552cb2b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -737,6 +737,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) case L2CAP_CHAN_RAW: switch (chan->sec_level) { case BT_SECURITY_HIGH: + case BT_SECURITY_FIPS: return HCI_AT_DEDICATED_BONDING_MITM; case BT_SECURITY_MEDIUM: return HCI_AT_DEDICATED_BONDING; @@ -749,7 +750,8 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) if (chan->sec_level == BT_SECURITY_LOW) chan->sec_level = BT_SECURITY_SDP; } - if (chan->sec_level == BT_SECURITY_HIGH) + if (chan->sec_level == BT_SECURITY_HIGH || + chan->sec_level == BT_SECURITY_FIPS) return HCI_AT_NO_BONDING_MITM; else return HCI_AT_NO_BONDING; @@ -759,7 +761,8 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) if (chan->sec_level == BT_SECURITY_LOW) chan->sec_level = BT_SECURITY_SDP; - if (chan->sec_level == BT_SECURITY_HIGH) + if (chan->sec_level == BT_SECURITY_HIGH || + chan->sec_level == BT_SECURITY_FIPS) return HCI_AT_NO_BONDING_MITM; else return HCI_AT_NO_BONDING; @@ -768,6 +771,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) default: switch (chan->sec_level) { case BT_SECURITY_HIGH: + case BT_SECURITY_FIPS: return HCI_AT_GENERAL_BONDING_MITM; case BT_SECURITY_MEDIUM: return HCI_AT_GENERAL_BONDING; @@ -7206,7 +7210,8 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) if (encrypt == 0x00) { if (chan->sec_level == BT_SECURITY_MEDIUM) { __set_chan_timer(chan, L2CAP_ENC_TIMEOUT); - } else if (chan->sec_level == BT_SECURITY_HIGH) + } else if (chan->sec_level == BT_SECURITY_HIGH || + chan->sec_level == BT_SECURITY_FIPS) l2cap_chan_close(chan, ECONNREFUSED); } else { if (chan->sec_level == BT_SECURITY_MEDIUM) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index d58f76bcebd1..fe086b4efc0c 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -432,6 +432,10 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE; break; + case BT_SECURITY_FIPS: + opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | + L2CAP_LM_SECURE | L2CAP_LM_FIPS; + break; default: opt = 0; break; @@ -445,6 +449,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, if (put_user(opt, (u32 __user *) optval)) err = -EFAULT; + break; case L2CAP_CONNINFO: @@ -699,6 +704,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, break; } + if (opt & L2CAP_LM_FIPS) { + err = -EINVAL; + break; + } + if (opt & L2CAP_LM_AUTH) chan->sec_level = BT_SECURITY_LOW; if (opt & L2CAP_LM_ENCRYPT) From 2c068e0b924c6fabd9a2ac59bc451b4b656cbae3 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 15 Jan 2014 22:37:41 -0800 Subject: [PATCH 045/414] Bluetooth: Handle security level 4 for RFCOMM connections With the introduction of security level 4, the RFCOMM sockets need to be made aware of this new level. This change ensures that the pairing requirements are set correctly for these connections. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/rfcomm.h | 1 + net/bluetooth/rfcomm/core.c | 4 +++- net/bluetooth/rfcomm/sock.c | 12 +++++++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index 486213a1aed8..c312cfc4e922 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -295,6 +295,7 @@ struct rfcomm_conninfo { #define RFCOMM_LM_TRUSTED 0x0008 #define RFCOMM_LM_RELIABLE 0x0010 #define RFCOMM_LM_SECURE 0x0020 +#define RFCOMM_LM_FIPS 0x0040 #define rfcomm_pi(sk) ((struct rfcomm_pinfo *) sk) diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index facd8a79c038..ba115d472f7b 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -216,6 +216,7 @@ static int rfcomm_check_security(struct rfcomm_dlc *d) switch (d->sec_level) { case BT_SECURITY_HIGH: + case BT_SECURITY_FIPS: auth_type = HCI_AT_GENERAL_BONDING_MITM; break; case BT_SECURITY_MEDIUM: @@ -2085,7 +2086,8 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt) set_bit(RFCOMM_SEC_PENDING, &d->flags); rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT); continue; - } else if (d->sec_level == BT_SECURITY_HIGH) { + } else if (d->sec_level == BT_SECURITY_HIGH || + d->sec_level == BT_SECURITY_FIPS) { set_bit(RFCOMM_ENC_DROP, &d->flags); continue; } diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 3c2d3e4aa2f5..fb8158af1f39 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -648,6 +648,11 @@ static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __u break; } + if (opt & RFCOMM_LM_FIPS) { + err = -EINVAL; + break; + } + if (opt & RFCOMM_LM_AUTH) rfcomm_pi(sk)->sec_level = BT_SECURITY_LOW; if (opt & RFCOMM_LM_ENCRYPT) @@ -762,7 +767,11 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u break; case BT_SECURITY_HIGH: opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT | - RFCOMM_LM_SECURE; + RFCOMM_LM_SECURE; + break; + case BT_SECURITY_FIPS: + opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT | + RFCOMM_LM_SECURE | RFCOMM_LM_FIPS; break; default: opt = 0; @@ -774,6 +783,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u if (put_user(opt, (u32 __user *) optval)) err = -EFAULT; + break; case RFCOMM_CONNINFO: From 134c2a89af22f500b1d7525d663fddda345ff01e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 15 Jan 2014 22:37:42 -0800 Subject: [PATCH 046/414] Bluetooth: Add debugfs entry to show Secure Connections Only mode For debugging purposes of Secure Connection Only support a simple debugfs entry is used to indicate if this mode is active or not. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_core.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 0064a9aa5df1..232c07804ca8 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -124,6 +124,7 @@ enum { HCI_LE_SCAN, HCI_SSP_ENABLED, HCI_SC_ENABLED, + HCI_SC_ONLY, HCI_HS_ENABLED, HCI_LE_ENABLED, HCI_ADVERTISING, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 499ec1b1095d..369d30750417 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -461,6 +461,24 @@ static const struct file_operations force_sc_support_fops = { .llseek = default_llseek, }; +static ssize_t sc_only_mode_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct hci_dev *hdev = file->private_data; + char buf[3]; + + buf[0] = test_bit(HCI_SC_ONLY, &hdev->dev_flags) ? 'Y': 'N'; + buf[1] = '\n'; + buf[2] = '\0'; + return simple_read_from_buffer(user_buf, count, ppos, buf, 2); +} + +static const struct file_operations sc_only_mode_fops = { + .open = simple_open, + .read = sc_only_mode_read, + .llseek = default_llseek, +}; + static int idle_timeout_set(void *data, u64 val) { struct hci_dev *hdev = data; @@ -1491,6 +1509,8 @@ static int __hci_init(struct hci_dev *hdev) hdev, &ssp_debug_mode_fops); debugfs_create_file("force_sc_support", 0644, hdev->debugfs, hdev, &force_sc_support_fops); + debugfs_create_file("sc_only_mode", 0444, hdev->debugfs, + hdev, &sc_only_mode_fops); } if (lmp_sniff_capable(hdev)) { From b131237ca3995edad9efc162d0bc959c3b1dddc2 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 16 Jan 2014 15:37:11 +0100 Subject: [PATCH 047/414] Bluetooth: Enable Atheros 0cf3:311e for firmware upload The device will bind to btusb without firmware, but with the original buggy firmware device discovery does not work. No devices are detected. Device descriptor without firmware: T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=311e Rev= 0.01 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms with firmware: T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=311e Rev= 0.02 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Oliver Neukum Signed-off-by: Marcel Holtmann --- drivers/bluetooth/ath3k.c | 2 ++ drivers/bluetooth/btusb.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 106d1d8e16ad..99ea2ee5326f 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -77,6 +77,7 @@ static const struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x0CF3, 0x3004) }, { USB_DEVICE(0x0CF3, 0x3008) }, { USB_DEVICE(0x0CF3, 0x311D) }, + { USB_DEVICE(0x0CF3, 0x311E) }, { USB_DEVICE(0x0CF3, 0x817a) }, { USB_DEVICE(0x13d3, 0x3375) }, { USB_DEVICE(0x04CA, 0x3004) }, @@ -122,6 +123,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x311E), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index baeaaed299e4..cc7ddd7e662f 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -144,6 +144,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, From 1e56f1eb2bbeab0ddc3a1e536d2a0065cfe4c131 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 16 Jan 2014 16:02:58 +0100 Subject: [PATCH 048/414] Bluetooth: Add firmware update for Atheros 0cf3:311f The device is not functional without firmware. The device without firmware: T: Bus=02 Lev=02 Prnt=02 Port=05 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=311f Rev=00.01 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb The device with firmware: T: Bus=02 Lev=02 Prnt=02 Port=05 Cnt=01 Dev#= 4 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=3007 Rev=00.01 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb Signed-off-by: Oliver Neukum Signed-off-by: Marcel Holtmann --- drivers/bluetooth/ath3k.c | 2 ++ drivers/bluetooth/btusb.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 99ea2ee5326f..41ec6f9a8252 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -78,6 +78,7 @@ static const struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x0CF3, 0x3008) }, { USB_DEVICE(0x0CF3, 0x311D) }, { USB_DEVICE(0x0CF3, 0x311E) }, + { USB_DEVICE(0x0CF3, 0x311F) }, { USB_DEVICE(0x0CF3, 0x817a) }, { USB_DEVICE(0x13d3, 0x3375) }, { USB_DEVICE(0x04CA, 0x3004) }, @@ -124,6 +125,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311E), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x311F), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index cc7ddd7e662f..5926a9db44b4 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -145,6 +145,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x311f), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, From 162b49e75cf2c6858852e7a0ae2c2e30e51f0e09 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Jan 2014 20:45:10 +0200 Subject: [PATCH 049/414] Bluetooth: Reorder L2CAP functions to avoid forward declarations This patch moves the l2cap_conn_add, is_valid_psm and l2cap_chan_connect functions further down in l2cap_core.c. The patch doesn't contain anything else except the relocation of these functions. By moving the functions further down the patch enables a subsequent patch that adds a pending RX queue to be implemented without a forward declaration of a function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 415 ++++++++++++++++++------------------- 1 file changed, 207 insertions(+), 208 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 3f0dd552cb2b..317a5737daf6 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1722,66 +1722,6 @@ static void security_timeout(struct work_struct *work) } } -static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) -{ - struct l2cap_conn *conn = hcon->l2cap_data; - struct hci_chan *hchan; - - if (conn) - return conn; - - hchan = hci_chan_create(hcon); - if (!hchan) - return NULL; - - conn = kzalloc(sizeof(struct l2cap_conn), GFP_KERNEL); - if (!conn) { - hci_chan_del(hchan); - return NULL; - } - - kref_init(&conn->ref); - hcon->l2cap_data = conn; - conn->hcon = hcon; - hci_conn_get(conn->hcon); - conn->hchan = hchan; - - BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan); - - switch (hcon->type) { - case LE_LINK: - if (hcon->hdev->le_mtu) { - conn->mtu = hcon->hdev->le_mtu; - break; - } - /* fall through */ - default: - conn->mtu = hcon->hdev->acl_mtu; - break; - } - - conn->feat_mask = 0; - - if (hcon->type == ACL_LINK) - conn->hs_enabled = test_bit(HCI_HS_ENABLED, - &hcon->hdev->dev_flags); - - spin_lock_init(&conn->lock); - mutex_init(&conn->chan_lock); - - INIT_LIST_HEAD(&conn->chan_l); - INIT_LIST_HEAD(&conn->users); - - if (hcon->type == LE_LINK) - INIT_DELAYED_WORK(&conn->security_timer, security_timeout); - else - INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); - - conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; - - return conn; -} - static void l2cap_conn_free(struct kref *ref) { struct l2cap_conn *conn = container_of(ref, struct l2cap_conn, ref); @@ -1852,154 +1792,6 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, return c1; } -static bool is_valid_psm(u16 psm, u8 dst_type) -{ - if (!psm) - return false; - - if (bdaddr_type_is_le(dst_type)) - return (psm <= 0x00ff); - - /* PSM must be odd and lsb of upper byte must be 0 */ - return ((psm & 0x0101) == 0x0001); -} - -int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, - bdaddr_t *dst, u8 dst_type) -{ - struct l2cap_conn *conn; - struct hci_conn *hcon; - struct hci_dev *hdev; - __u8 auth_type; - int err; - - BT_DBG("%pMR -> %pMR (type %u) psm 0x%2.2x", &chan->src, dst, - dst_type, __le16_to_cpu(psm)); - - hdev = hci_get_route(dst, &chan->src); - if (!hdev) - return -EHOSTUNREACH; - - hci_dev_lock(hdev); - - l2cap_chan_lock(chan); - - if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid && - chan->chan_type != L2CAP_CHAN_RAW) { - err = -EINVAL; - goto done; - } - - if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) { - err = -EINVAL; - goto done; - } - - switch (chan->mode) { - case L2CAP_MODE_BASIC: - break; - case L2CAP_MODE_LE_FLOWCTL: - l2cap_le_flowctl_init(chan); - break; - case L2CAP_MODE_ERTM: - case L2CAP_MODE_STREAMING: - if (!disable_ertm) - break; - /* fall through */ - default: - err = -ENOTSUPP; - goto done; - } - - switch (chan->state) { - case BT_CONNECT: - case BT_CONNECT2: - case BT_CONFIG: - /* Already connecting */ - err = 0; - goto done; - - case BT_CONNECTED: - /* Already connected */ - err = -EISCONN; - goto done; - - case BT_OPEN: - case BT_BOUND: - /* Can connect */ - break; - - default: - err = -EBADFD; - goto done; - } - - /* Set destination address and psm */ - bacpy(&chan->dst, dst); - chan->dst_type = dst_type; - - chan->psm = psm; - chan->dcid = cid; - - auth_type = l2cap_get_auth_type(chan); - - if (bdaddr_type_is_le(dst_type)) - hcon = hci_connect(hdev, LE_LINK, dst, dst_type, - chan->sec_level, auth_type); - else - hcon = hci_connect(hdev, ACL_LINK, dst, dst_type, - chan->sec_level, auth_type); - - if (IS_ERR(hcon)) { - err = PTR_ERR(hcon); - goto done; - } - - conn = l2cap_conn_add(hcon); - if (!conn) { - hci_conn_drop(hcon); - err = -ENOMEM; - goto done; - } - - if (cid && __l2cap_get_chan_by_dcid(conn, cid)) { - hci_conn_drop(hcon); - err = -EBUSY; - goto done; - } - - /* Update source addr of the socket */ - bacpy(&chan->src, &hcon->src); - chan->src_type = bdaddr_type(hcon, hcon->src_type); - - l2cap_chan_unlock(chan); - l2cap_chan_add(conn, chan); - l2cap_chan_lock(chan); - - /* l2cap_chan_add takes its own ref so we can drop this one */ - hci_conn_drop(hcon); - - l2cap_state_change(chan, BT_CONNECT); - __set_chan_timer(chan, chan->ops->get_sndtimeo(chan)); - - if (hcon->state == BT_CONNECTED) { - if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { - __clear_chan_timer(chan); - if (l2cap_chan_check_security(chan)) - l2cap_state_change(chan, BT_CONNECTED); - } else - l2cap_do_start(chan); - } - - err = 0; - -done: - l2cap_chan_unlock(chan); - hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; -} - static void l2cap_monitor_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, @@ -7136,6 +6928,213 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) } } +static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) +{ + struct l2cap_conn *conn = hcon->l2cap_data; + struct hci_chan *hchan; + + if (conn) + return conn; + + hchan = hci_chan_create(hcon); + if (!hchan) + return NULL; + + conn = kzalloc(sizeof(struct l2cap_conn), GFP_KERNEL); + if (!conn) { + hci_chan_del(hchan); + return NULL; + } + + kref_init(&conn->ref); + hcon->l2cap_data = conn; + conn->hcon = hcon; + hci_conn_get(conn->hcon); + conn->hchan = hchan; + + BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan); + + switch (hcon->type) { + case LE_LINK: + if (hcon->hdev->le_mtu) { + conn->mtu = hcon->hdev->le_mtu; + break; + } + /* fall through */ + default: + conn->mtu = hcon->hdev->acl_mtu; + break; + } + + conn->feat_mask = 0; + + if (hcon->type == ACL_LINK) + conn->hs_enabled = test_bit(HCI_HS_ENABLED, + &hcon->hdev->dev_flags); + + spin_lock_init(&conn->lock); + mutex_init(&conn->chan_lock); + + INIT_LIST_HEAD(&conn->chan_l); + INIT_LIST_HEAD(&conn->users); + + if (hcon->type == LE_LINK) + INIT_DELAYED_WORK(&conn->security_timer, security_timeout); + else + INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); + + conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; + + return conn; +} + +static bool is_valid_psm(u16 psm, u8 dst_type) { + if (!psm) + return false; + + if (bdaddr_type_is_le(dst_type)) + return (psm <= 0x00ff); + + /* PSM must be odd and lsb of upper byte must be 0 */ + return ((psm & 0x0101) == 0x0001); +} + +int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, + bdaddr_t *dst, u8 dst_type) +{ + struct l2cap_conn *conn; + struct hci_conn *hcon; + struct hci_dev *hdev; + __u8 auth_type; + int err; + + BT_DBG("%pMR -> %pMR (type %u) psm 0x%2.2x", &chan->src, dst, + dst_type, __le16_to_cpu(psm)); + + hdev = hci_get_route(dst, &chan->src); + if (!hdev) + return -EHOSTUNREACH; + + hci_dev_lock(hdev); + + l2cap_chan_lock(chan); + + if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid && + chan->chan_type != L2CAP_CHAN_RAW) { + err = -EINVAL; + goto done; + } + + if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) { + err = -EINVAL; + goto done; + } + + switch (chan->mode) { + case L2CAP_MODE_BASIC: + break; + case L2CAP_MODE_LE_FLOWCTL: + l2cap_le_flowctl_init(chan); + break; + case L2CAP_MODE_ERTM: + case L2CAP_MODE_STREAMING: + if (!disable_ertm) + break; + /* fall through */ + default: + err = -ENOTSUPP; + goto done; + } + + switch (chan->state) { + case BT_CONNECT: + case BT_CONNECT2: + case BT_CONFIG: + /* Already connecting */ + err = 0; + goto done; + + case BT_CONNECTED: + /* Already connected */ + err = -EISCONN; + goto done; + + case BT_OPEN: + case BT_BOUND: + /* Can connect */ + break; + + default: + err = -EBADFD; + goto done; + } + + /* Set destination address and psm */ + bacpy(&chan->dst, dst); + chan->dst_type = dst_type; + + chan->psm = psm; + chan->dcid = cid; + + auth_type = l2cap_get_auth_type(chan); + + if (bdaddr_type_is_le(dst_type)) + hcon = hci_connect(hdev, LE_LINK, dst, dst_type, + chan->sec_level, auth_type); + else + hcon = hci_connect(hdev, ACL_LINK, dst, dst_type, + chan->sec_level, auth_type); + + if (IS_ERR(hcon)) { + err = PTR_ERR(hcon); + goto done; + } + + conn = l2cap_conn_add(hcon); + if (!conn) { + hci_conn_drop(hcon); + err = -ENOMEM; + goto done; + } + + if (cid && __l2cap_get_chan_by_dcid(conn, cid)) { + hci_conn_drop(hcon); + err = -EBUSY; + goto done; + } + + /* Update source addr of the socket */ + bacpy(&chan->src, &hcon->src); + chan->src_type = bdaddr_type(hcon, hcon->src_type); + + l2cap_chan_unlock(chan); + l2cap_chan_add(conn, chan); + l2cap_chan_lock(chan); + + /* l2cap_chan_add takes its own ref so we can drop this one */ + hci_conn_drop(hcon); + + l2cap_state_change(chan, BT_CONNECT); + __set_chan_timer(chan, chan->ops->get_sndtimeo(chan)); + + if (hcon->state == BT_CONNECTED) { + if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { + __clear_chan_timer(chan); + if (l2cap_chan_check_security(chan)) + l2cap_state_change(chan, BT_CONNECTED); + } else + l2cap_do_start(chan); + } + + err = 0; + +done: + l2cap_chan_unlock(chan); + hci_dev_unlock(hdev); + hci_dev_put(hdev); + return err; +} + /* ---- L2CAP interface with lower layer (HCI) ---- */ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) From 61a939c68ee033d43be3aa436d95eb8afdd16142 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Jan 2014 20:45:11 +0200 Subject: [PATCH 050/414] Bluetooth: Queue incoming ACL data until BT_CONNECTED state is reached This patch adds a queue for incoming L2CAP data that's received before l2cap_connect_cfm is called and processes the data once l2cap_connect_cfm is called. This way we ensure that we have e.g. all remote features before processing L2CAP signaling data (which is very important for making the correct security decisions). The processing of the pending rx data needs to be done through queue_work since unlike l2cap_recv_acldata, l2cap_connect_cfm is called with the hci_dev lock held which could cause potential deadlocks. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 3 +++ net/bluetooth/l2cap_core.c | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index c695083eee2b..85cf40acc47e 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -624,6 +624,9 @@ struct l2cap_conn { __u32 rx_len; __u8 tx_ident; + struct sk_buff_head pending_rx; + struct work_struct pending_rx_work; + __u8 disc_reason; struct delayed_work security_timer; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 317a5737daf6..cd534599fbfa 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1550,6 +1550,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) } mutex_unlock(&conn->chan_lock); + + queue_work(hcon->hdev->workqueue, &conn->pending_rx_work); } /* Notify sockets that we cannot guaranty reliability anymore */ @@ -1675,6 +1677,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) kfree_skb(conn->rx_skb); + skb_queue_purge(&conn->pending_rx); + flush_work(&conn->pending_rx_work); + l2cap_unregister_all_users(conn); mutex_lock(&conn->chan_lock); @@ -6880,9 +6885,16 @@ drop: static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) { struct l2cap_hdr *lh = (void *) skb->data; + struct hci_conn *hcon = conn->hcon; u16 cid, len; __le16 psm; + if (hcon->state != BT_CONNECTED) { + BT_DBG("queueing pending rx skb"); + skb_queue_tail(&conn->pending_rx, skb); + return; + } + skb_pull(skb, L2CAP_HDR_SIZE); cid = __le16_to_cpu(lh->cid); len = __le16_to_cpu(lh->len); @@ -6928,6 +6940,18 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) } } +static void process_pending_rx(struct work_struct *work) +{ + struct l2cap_conn *conn = container_of(work, struct l2cap_conn, + pending_rx_work); + struct sk_buff *skb; + + BT_DBG(""); + + while ((skb = skb_dequeue(&conn->pending_rx))) + l2cap_recv_frame(conn, skb); +} + static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) { struct l2cap_conn *conn = hcon->l2cap_data; @@ -6983,6 +7007,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) else INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); + skb_queue_head_init(&conn->pending_rx); + INIT_WORK(&conn->pending_rx_work, process_pending_rx); + conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; return conn; From 03a0c5d61c878e3196b80fa9dc9fbae0fb2eb8f8 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 18 Jan 2014 21:32:59 +0200 Subject: [PATCH 051/414] Bluetooth: Remove useless l2cap_seq_list_remove function The only user of l2cap_seq_list_remove() was l2cap_seq_list_pop() which only removes the head, meaning only the "else if (seq_list->head == seq)" branch was ever being used. This patch moves the code from this branch straight into l2cap_seq_list_pop() and removes the (now useless) l2cap_seq_list_remove(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 48 ++++++++++---------------------------- 1 file changed, 12 insertions(+), 36 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index cd534599fbfa..138394ad3e51 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -330,44 +330,20 @@ static inline bool l2cap_seq_list_contains(struct l2cap_seq_list *seq_list, return seq_list->list[seq & seq_list->mask] != L2CAP_SEQ_LIST_CLEAR; } -static u16 l2cap_seq_list_remove(struct l2cap_seq_list *seq_list, u16 seq) -{ - u16 mask = seq_list->mask; - - if (seq_list->head == L2CAP_SEQ_LIST_CLEAR) { - /* In case someone tries to pop the head of an empty list */ - return L2CAP_SEQ_LIST_CLEAR; - } else if (seq_list->head == seq) { - /* Head can be removed in constant time */ - seq_list->head = seq_list->list[seq & mask]; - seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR; - - if (seq_list->head == L2CAP_SEQ_LIST_TAIL) { - seq_list->head = L2CAP_SEQ_LIST_CLEAR; - seq_list->tail = L2CAP_SEQ_LIST_CLEAR; - } - } else { - /* Walk the list to find the sequence number */ - u16 prev = seq_list->head; - while (seq_list->list[prev & mask] != seq) { - prev = seq_list->list[prev & mask]; - if (prev == L2CAP_SEQ_LIST_TAIL) - return L2CAP_SEQ_LIST_CLEAR; - } - - /* Unlink the number from the list and clear it */ - seq_list->list[prev & mask] = seq_list->list[seq & mask]; - seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR; - if (seq_list->tail == seq) - seq_list->tail = prev; - } - return seq; -} - static inline u16 l2cap_seq_list_pop(struct l2cap_seq_list *seq_list) { - /* Remove the head in constant time */ - return l2cap_seq_list_remove(seq_list, seq_list->head); + u16 seq = seq_list->head; + u16 mask = seq_list->mask; + + seq_list->head = seq_list->list[seq & mask]; + seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR; + + if (seq_list->head == L2CAP_SEQ_LIST_TAIL) { + seq_list->head = L2CAP_SEQ_LIST_CLEAR; + seq_list->tail = L2CAP_SEQ_LIST_CLEAR; + } + + return seq; } static void l2cap_seq_list_clear(struct l2cap_seq_list *seq_list) From 2338a7e0440d646c194d421748ea36665e648384 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 24 Jan 2014 10:35:40 +0200 Subject: [PATCH 052/414] Bluetooth: Rename L2CAP_CHAN_CONN_FIX_A2MP to L2CAP_CHAN_FIXED There's no reason why A2MP should need or deserve its on channel type. Instead we should be able to group all fixed CID users under a single channel type and reuse as much code as possible for them. Where CID specific exceptions are needed the chan-scid value can be used. This patch renames the current A2MP channel type to a generic one and thereby paves the way to allow converting ATT and SMP (and any future fixed channel protocols) to use the new channel type. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/a2mp.c | 8 ++++++-- net/bluetooth/l2cap_core.c | 15 ++++++--------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 85cf40acc47e..ae482f41594a 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -651,7 +651,7 @@ struct l2cap_user { #define L2CAP_CHAN_RAW 1 #define L2CAP_CHAN_CONN_LESS 2 #define L2CAP_CHAN_CONN_ORIENTED 3 -#define L2CAP_CHAN_CONN_FIX_A2MP 4 +#define L2CAP_CHAN_FIXED 4 /* ----- L2CAP socket info ----- */ #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index efcd108822c4..f986b9968bdb 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -235,7 +235,7 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb, BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); - if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) + if (chan->scid == L2CAP_CID_A2MP) continue; l2cap_chan_lock(chan); @@ -726,7 +726,11 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked) BT_DBG("chan %p", chan); - chan->chan_type = L2CAP_CHAN_CONN_FIX_A2MP; + chan->chan_type = L2CAP_CHAN_FIXED; + chan->scid = L2CAP_CID_A2MP; + chan->dcid = L2CAP_CID_A2MP; + chan->omtu = L2CAP_A2MP_DEFAULT_MTU; + chan->imtu = L2CAP_A2MP_DEFAULT_MTU; chan->flush_to = L2CAP_DEFAULT_FLUSH_TO; chan->ops = &a2mp_chan_ops; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 138394ad3e51..cd28057d2903 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -519,11 +519,8 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) chan->omtu = L2CAP_DEFAULT_MTU; break; - case L2CAP_CHAN_CONN_FIX_A2MP: - chan->scid = L2CAP_CID_A2MP; - chan->dcid = L2CAP_CID_A2MP; - chan->omtu = L2CAP_A2MP_DEFAULT_MTU; - chan->imtu = L2CAP_A2MP_DEFAULT_MTU; + case L2CAP_CHAN_FIXED: + /* Caller will set CID and CID specific MTU values */ break; default: @@ -571,7 +568,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) chan->conn = NULL; - if (chan->chan_type != L2CAP_CHAN_CONN_FIX_A2MP) + if (chan->scid != L2CAP_CID_A2MP) hci_conn_drop(conn->hcon); if (mgr && mgr->bredr_chan == chan) @@ -1310,7 +1307,7 @@ static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err) __clear_ack_timer(chan); } - if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) { + if (chan->scid == L2CAP_CID_A2MP) { l2cap_state_change(chan, BT_DISCONN); return; } @@ -1508,7 +1505,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) l2cap_chan_lock(chan); - if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) { + if (chan->scid == L2CAP_CID_A2MP) { l2cap_chan_unlock(chan); continue; } @@ -7245,7 +7242,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) BT_DBG("chan %p scid 0x%4.4x state %s", chan, chan->scid, state_to_string(chan->state)); - if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) { + if (chan->scid == L2CAP_CID_A2MP) { l2cap_chan_unlock(chan); continue; } From 21626e6214f92aaae580052c760dc85f83b5faef Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 24 Jan 2014 10:35:41 +0200 Subject: [PATCH 053/414] Bluetooth: Switch ATT channels to use L2CAP_CHAN_FIXED ATT channels are not connection oriented so having them use L2CAP_CHAN_CONN_ORIENTED is quite confusing. Instead, use the new L2CAP_CHAN_FIXED type and ensure that the MTU and CID values get properly set. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 21 +++++++++------------ net/bluetooth/l2cap_sock.c | 9 +++++++++ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index cd28057d2903..e5c5c7427c41 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -498,18 +498,10 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) switch (chan->chan_type) { case L2CAP_CHAN_CONN_ORIENTED: - if (conn->hcon->type == LE_LINK) { - if (chan->dcid == L2CAP_CID_ATT) { - chan->omtu = L2CAP_DEFAULT_MTU; - chan->scid = L2CAP_CID_ATT; - } else { - chan->scid = l2cap_alloc_cid(conn); - } - } else { - /* Alloc CID for connection-oriented socket */ - chan->scid = l2cap_alloc_cid(conn); + /* Alloc CID for connection-oriented socket */ + chan->scid = l2cap_alloc_cid(conn); + if (conn->hcon->type == ACL_LINK) chan->omtu = L2CAP_DEFAULT_MTU; - } break; case L2CAP_CHAN_CONN_LESS: @@ -7025,7 +7017,12 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, goto done; } - if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) { + if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !psm) { + err = -EINVAL; + goto done; + } + + if (chan->chan_type == L2CAP_CHAN_FIXED && !cid) { err = -EINVAL; goto done; } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index fe086b4efc0c..04abd26a3466 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -101,6 +101,15 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) if (!bdaddr_type_is_valid(la.l2_bdaddr_type)) return -EINVAL; + if (la.l2_cid) { + /* When the socket gets created it defaults to + * CHAN_CONN_ORIENTED, so we need to overwrite the + * default here. + */ + chan->chan_type = L2CAP_CHAN_FIXED; + chan->omtu = L2CAP_DEFAULT_MTU; + } + if (bdaddr_type_is_le(la.l2_bdaddr_type)) { if (!enable_lecoc && la.l2_psm) return -EINVAL; From e0c888ad739513b9baae5c25e85dd6490595e5be Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 25 Jan 2014 17:10:07 -0500 Subject: [PATCH 054/414] Bluetooth: Fix BT_SECURITY socket option for fixed channels (ATT) The BT_SECURITY option should also be allowed for fixed channels, so punch the appropriate hole for it when checking for the channel type. The main user of fixed CID user space sockets is right now ATT (which is broken without this patch). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_sock.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 04abd26a3466..7ad346ea06ed 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -513,6 +513,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, switch (optname) { case BT_SECURITY: if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED && + chan->chan_type != L2CAP_CHAN_FIXED && chan->chan_type != L2CAP_CHAN_RAW) { err = -EINVAL; break; @@ -769,6 +770,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, switch (optname) { case BT_SECURITY: if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED && + chan->chan_type != L2CAP_CHAN_FIXED && chan->chan_type != L2CAP_CHAN_RAW) { err = -EINVAL; break; From 7a8e5a31ecd50ace4fce57304c8fdd206f013fde Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 25 Jan 2014 17:10:09 -0500 Subject: [PATCH 055/414] Bluetooth: Fix CID initialization for fixed channels Fixed channels have the same source and destination CID. Ensure that the values get properly initialized when receiving incoming connections and deriving values from the parent socket. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 2 -- net/bluetooth/l2cap_sock.c | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index e5c5c7427c41..cc340700573e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1462,8 +1462,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) if (!chan) goto clean; - chan->dcid = L2CAP_CID_ATT; - bacpy(&chan->src, &hcon->src); bacpy(&chan->dst, &hcon->dst); chan->src_type = bdaddr_type(hcon, hcon->src_type); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 7ad346ea06ed..ae4f6b593fc0 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1470,6 +1470,11 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) chan->tx_credits = pchan->tx_credits; chan->rx_credits = pchan->rx_credits; + if (chan->chan_type == L2CAP_CHAN_FIXED) { + chan->scid = pchan->scid; + chan->dcid = pchan->scid; + } + security_sk_clone(parent, sk); } else { switch (sk->sk_type) { From d1d79413ec066b9d13390590be3ff684e2dd3631 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 27 Jan 2014 15:11:33 -0800 Subject: [PATCH 056/414] Bluetooth: Fix respecting le_default_mps value There's a le_default_mps variable that can be modified through debugfs but it was never actually used for determining our MPS value. This patch fixes the MPS initialization to use the variable instead of a fixed value. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index cc340700573e..5a30fc72f4ba 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -482,7 +482,7 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan) chan->sdu_len = 0; chan->tx_credits = 0; chan->rx_credits = le_max_credits; - chan->mps = min_t(u16, chan->imtu, L2CAP_LE_DEFAULT_MPS); + chan->mps = min_t(u16, chan->imtu, le_default_mps); skb_queue_head_init(&chan->tx_q); } From dfd9774c5ad4abe9d51e52056e441eaf983b9080 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 27 Jan 2014 15:11:34 -0800 Subject: [PATCH 057/414] Bluetooth: Fix disconnecting L2CAP channel for credits violation The L2CAP specification requires us to disconnect a channel if the remote device sends us data when it doesn't have any credits to do so. This patch makes sure that we send the appropriate L2CAP Disconnect request in this situation. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 5a30fc72f4ba..fbc9709abccf 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -6635,6 +6635,7 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) if (!chan->rx_credits) { BT_ERR("No credits to receive LE L2CAP data"); + l2cap_send_disconn_req(chan, ECONNRESET); return -ENOBUFS; } From 0f1bfe4e5eb8db9841b57ade1384b9a8ffcd38c3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 27 Jan 2014 15:11:35 -0800 Subject: [PATCH 058/414] Bluetooth: Fix disconnecting L2CAP when a credits overflow occurs The L2CAP specification requires us to disconnect an L2CAP channel if the remote side gives us credits beyond 65535. This patch makes sure we disconnect the channel in such a situation. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index fbc9709abccf..d2ef49b54aa2 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -42,6 +42,8 @@ #include "amp.h" #include "6lowpan.h" +#define LE_FLOWCTL_MAX_CREDITS 65535 + bool disable_ertm; static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD; @@ -5473,7 +5475,7 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn, { struct l2cap_le_credits *pkt; struct l2cap_chan *chan; - u16 cid, credits; + u16 cid, credits, max_credits; if (cmd_len != sizeof(*pkt)) return -EPROTO; @@ -5488,6 +5490,17 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn, if (!chan) return -EBADSLT; + max_credits = LE_FLOWCTL_MAX_CREDITS - chan->tx_credits; + if (credits > max_credits) { + BT_ERR("LE credits overflow"); + l2cap_send_disconn_req(chan, ECONNRESET); + + /* Return 0 so that we don't trigger an unnecessary + * command reject packet. + */ + return 0; + } + chan->tx_credits += credits; while (chan->tx_credits && !skb_queue_empty(&chan->tx_q)) { From 61202e4de92d9bf7169dd5f2ef2d6c6e5683ec53 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Jan 2014 15:16:48 -0800 Subject: [PATCH 059/414] Bluetooth: Free up l2cap_chan->sport when initiating a connection The sport variable is used to track the allocation of the local PSM database to ensure no two sockets take the same local PSM. It is acquired upon bind() but needs to be freed up if the socket ends up becoming a client one. This patch adds the clearing of the value when l2cap_chan_connect is called. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d2ef49b54aa2..f583988a4653 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7126,6 +7126,13 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, l2cap_state_change(chan, BT_CONNECT); __set_chan_timer(chan, chan->ops->get_sndtimeo(chan)); + /* Release chan->sport so that it can be reused by other + * sockets (as it's only used for listening sockets). + */ + write_lock(&chan_list_lock); + chan->sport = 0; + write_unlock(&chan_list_lock); + if (hcon->state == BT_CONNECTED) { if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { __clear_chan_timer(chan); From b783fbc3a55691f978b9f78d552a0d7e7d2705ad Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Jan 2014 15:16:49 -0800 Subject: [PATCH 060/414] Bluetooth: Refuse peer L2CAP address reading when not connected When we're not connected the peer address information is undefined. This patch fixes the remote address getting to return a proper error in case the state is anything else than BT_CONNECTED. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_sock.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index ae4f6b593fc0..b0aaa651a5ba 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -366,6 +366,9 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, BT_DBG("sock %p, sk %p", sock, sk); + if (peer && sk->sk_state != BT_CONNECTED) + return -ENOTCONN; + memset(la, 0, sizeof(struct sockaddr_l2)); addr->sa_family = AF_BLUETOOTH; *len = sizeof(struct sockaddr_l2); From 35364c99d20edc7329843e2a6dad6851d77eafd7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Jan 2014 15:16:50 -0800 Subject: [PATCH 061/414] Bluetooth: Refuse peer RFCOMM address reading when not connected When we're not connected the peer address information is undefined. This patch fixes the remote address getting to return a proper error in case the sate is anything else than BT_CONNECTED. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/sock.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index fb8158af1f39..00573fb79030 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -528,6 +528,9 @@ static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int * BT_DBG("sock %p, sk %p", sock, sk); + if (peer && sk->sk_state != BT_CONNECTED) + return -ENOTCONN; + memset(sa, 0, sizeof(*sa)); sa->rc_family = AF_BLUETOOTH; sa->rc_channel = rfcomm_pi(sk)->channel; From d7e5e76b6f4c5848ad3093493bdb226c27d8350e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Jan 2014 15:16:51 -0800 Subject: [PATCH 062/414] Bluetooth: Always use l2cap_chan->psm for returning PSM to user space The l2cap_chan->psm value is always set to a valid value for a connection oriented channel. The l2cap_chan->sport is used for tracking local PSM allocations but will not always have a proper value, such as with connected sockets derived from a listening socket. This patch fixes the sock_getname callback to always use chan->psm when returning address information. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_sock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index b0aaa651a5ba..27d3d6d48b6e 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -373,13 +373,13 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, addr->sa_family = AF_BLUETOOTH; *len = sizeof(struct sockaddr_l2); + la->l2_psm = chan->psm; + if (peer) { - la->l2_psm = chan->psm; bacpy(&la->l2_bdaddr, &chan->dst); la->l2_cid = cpu_to_le16(chan->dcid); la->l2_bdaddr_type = chan->dst_type; } else { - la->l2_psm = chan->sport; bacpy(&la->l2_bdaddr, &chan->src); la->l2_cid = cpu_to_le16(chan->scid); la->l2_bdaddr_type = chan->src_type; From 7b25c9b3c90150164f36b16cc0107d774eaec68f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Jan 2014 15:28:04 -0800 Subject: [PATCH 063/414] Bluetooth: Remove unnecessary check for chan->psm Now that ATT sockets have been converted to use the new L2CAP_CHAN_FIXED type there is no need to have an extra check for chan->psm in the l2cap_chan_close function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index f583988a4653..66fbac91eaed 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -666,10 +666,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) case BT_CONNECTED: case BT_CONFIG: - /* ATT uses L2CAP_CHAN_CONN_ORIENTED so we must also - * check for chan->psm. - */ - if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && chan->psm) { + if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) { __set_chan_timer(chan, chan->ops->get_sndtimeo(chan)); l2cap_send_disconn_req(chan, reason); } else From 40456644295998321b8743b72c9cc0e4db937959 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 28 Jan 2014 15:39:01 -0800 Subject: [PATCH 064/414] Bluetooth: Increment management interface revision This patch increments the management interface revision due to the various fixes, improvements and other changes that have been made. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4ee07b432379..bde8e675c5ea 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -34,7 +34,7 @@ #include "smp.h" #define MGMT_VERSION 1 -#define MGMT_REVISION 4 +#define MGMT_REVISION 5 static const u16 mgmt_commands[] = { MGMT_OP_READ_INDEX_LIST, From 0cf73b9fa51be32042dad09953f7a82f19933e97 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 29 Jan 2014 13:55:59 -0800 Subject: [PATCH 065/414] Bluetooth: Enable LTK distribution to slave devices So far we've only been requesting the LTK to be distributed to the master (initiator) of pairing, which is usually enough since it's the master that will establish future connections and initiate encryption. However, in the case that both devices support switching to the opposing role (which seems to be increasingly common) pairing will have to performed again since the "new" master will not have all information. As there is no real harm in it, this patch updates the code to always try distributing the LTK also to the slave device, thereby enabling role switches for future connections. Signed-off-by: Johan Hedberg Acked-by: Vinicius Gomes Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 45007362683b..9b1167007653 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -216,7 +216,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, req->io_capability = conn->hcon->io_capability; req->oob_flag = SMP_OOB_NOT_PRESENT; req->max_key_size = SMP_MAX_ENC_KEY_SIZE; - req->init_key_dist = 0; + req->init_key_dist = dist_keys; req->resp_key_dist = dist_keys; req->auth_req = (authreq & AUTH_REQ_MASK); return; @@ -225,7 +225,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, rsp->io_capability = conn->hcon->io_capability; rsp->oob_flag = SMP_OOB_NOT_PRESENT; rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE; - rsp->init_key_dist = 0; + rsp->init_key_dist = req->init_key_dist & dist_keys; rsp->resp_key_dist = req->resp_key_dist & dist_keys; rsp->auth_req = (authreq & AUTH_REQ_MASK); } From e834004b8a940ab28dace6043985ae2adf305661 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 30 Jan 2014 11:16:50 -0800 Subject: [PATCH 066/414] Bluetooth: Remove Simultaneous LE & BR/EDR flags from AD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Starting with the 4.1 Core Specification these flags are no longer used and should always be cleared. From volume 3, part C, section 13.1.1: "The 'Simultaneous LE and BR/EDR to Same Device Capable (Controller)' and ‘Simultaneous LE and BR/EDR to Same Device Capable (Host)’ bits in the Flags AD type shall be set to ‘0’." Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bde8e675c5ea..111b1296a2b8 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -637,14 +637,8 @@ static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr) flags |= get_adv_discov_flags(hdev); - if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) { - if (lmp_le_br_capable(hdev)) - flags |= LE_AD_SIM_LE_BREDR_CTRL; - if (lmp_host_le_br_capable(hdev)) - flags |= LE_AD_SIM_LE_BREDR_HOST; - } else { + if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) flags |= LE_AD_NO_BREDR; - } if (flags) { BT_DBG("adv flags 0x%02x", flags); From f813f1be1f82a09720e94533f46ac79276eb037d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 30 Jan 2014 19:39:57 -0800 Subject: [PATCH 067/414] Bluetooth: Fix long_term_keys debugfs output The code was previously iterating the wrong list (and what's worse casting entries to a type which they were not) and also missing a proper line terminator when printing each entry. The code now also prints the LTK type in hex for easier comparison with the kernel-defined values. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 369d30750417..8094a41c9a26 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -620,9 +620,9 @@ static int long_term_keys_show(struct seq_file *f, void *ptr) struct list_head *p, *n; hci_dev_lock(hdev); - list_for_each_safe(p, n, &hdev->link_keys) { + list_for_each_safe(p, n, &hdev->long_term_keys) { struct smp_ltk *ltk = list_entry(p, struct smp_ltk, list); - seq_printf(f, "%pMR (type %u) %u %u %u %.4x %*phN %*phN\\n", + seq_printf(f, "%pMR (type %u) %u 0x%02x %u %.4x %*phN %*phN\n", <k->bdaddr, ltk->bdaddr_type, ltk->authenticated, ltk->type, ltk->enc_size, __le16_to_cpu(ltk->ediv), 8, ltk->rand, 16, ltk->val); From 21b93b75ad1090dd9aed69b56292648bac6666a9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 30 Jan 2014 19:39:58 -0800 Subject: [PATCH 068/414] Bluetooth: Make LTK key type check more readable Instead of magic bitwise operations simply compare with the two possible type values that we are interested in. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 8094a41c9a26..754a59079de9 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2717,7 +2717,7 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, if (!new_key) return 0; - if (type & HCI_SMP_LTK) + if (type == HCI_SMP_LTK || type == HCI_SMP_LTK_SLAVE) mgmt_new_ltk(hdev, key, 1); return 0; From a513e260ce25eaa5e8c6b834a70085be1d6f40c0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 30 Jan 2014 19:39:59 -0800 Subject: [PATCH 069/414] Bluetooth: Remove unnecessary LTK type check from hci_add_ltk All callers of hci_add_ltk pass a valid value to it. There are no places where e.g. user space, the controller or the remote peer would be able to cause invalid values to be passed. Therefore, just remove the potentially confusing check from the beginning of the function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 754a59079de9..180473d965f6 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2692,9 +2692,6 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, { struct smp_ltk *key, *old_key; - if (!(type & HCI_SMP_STK) && !(type & HCI_SMP_LTK)) - return 0; - old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type); if (old_key) key = old_key; From 98a0b845c63cb74e90a72d1e864ea4be968bdd83 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 30 Jan 2014 19:40:00 -0800 Subject: [PATCH 070/414] Bluetooth: Fix differentiating stored master vs slave LTK types If LTK distribution happens in both directions we will have two LTKs for the same remote device: one which is used when we're connecting as master and another when we're connecting as slave. When looking up LTKs from the locally stored list we shouldn't blindly return the first match but also consider which type of key is in question. If we do not do this we may end up selecting an incorrect encryption key for a connection. This patch fixes the issue by always specifying to the LTK lookup functions whether we're looking for a master or a slave key. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 5 +++-- net/bluetooth/hci_core.c | 22 ++++++++++++++++++---- net/bluetooth/hci_event.c | 2 +- net/bluetooth/smp.c | 3 ++- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 8d225e4ea2ce..378e2f32cfa0 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -757,12 +757,13 @@ int hci_link_keys_clear(struct hci_dev *hdev); struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); -struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]); +struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8], + bool master); int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, int new_key, u8 authenticated, u8 tk[16], u8 enc_size, __le16 ediv, u8 rand[8]); struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 addr_type); + u8 addr_type, bool master); int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_smp_ltks_clear(struct hci_dev *hdev); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 180473d965f6..d370b432aea6 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2605,7 +2605,16 @@ static bool hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn, return false; } -struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]) +static bool ltk_type_master(u8 type) +{ + if (type == HCI_SMP_STK || type == HCI_SMP_LTK) + return true; + + return false; +} + +struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8], + bool master) { struct smp_ltk *k; @@ -2614,6 +2623,9 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]) memcmp(rand, k->rand, sizeof(k->rand))) continue; + if (ltk_type_master(k->type) != master) + continue; + return k; } @@ -2621,13 +2633,14 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]) } struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 addr_type) + u8 addr_type, bool master) { struct smp_ltk *k; list_for_each_entry(k, &hdev->long_term_keys, list) if (addr_type == k->bdaddr_type && - bacmp(bdaddr, &k->bdaddr) == 0) + bacmp(bdaddr, &k->bdaddr) == 0 && + ltk_type_master(k->type) == master) return k; return NULL; @@ -2691,8 +2704,9 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, ediv, u8 rand[8]) { struct smp_ltk *key, *old_key; + bool master = ltk_type_master(type); - old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type); + old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type, master); if (old_key) key = old_key; else { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8c44bbe19add..7bb8094a3ff2 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3650,7 +3650,7 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) if (conn == NULL) goto not_found; - ltk = hci_find_ltk(hdev, ev->ediv, ev->random); + ltk = hci_find_ltk(hdev, ev->ediv, ev->random, conn->out); if (ltk == NULL) goto not_found; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 9b1167007653..efe51ccdc615 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -699,7 +699,8 @@ static u8 smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level) struct smp_ltk *key; struct hci_conn *hcon = conn->hcon; - key = hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type); + key = hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type, + hcon->out); if (!key) return 0; From 1e406eefbe41467c00973939c2b61b37bf0e1323 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 30 Jan 2014 18:22:04 -0300 Subject: [PATCH 071/414] Bluetooth: Save connection interval parameters in hci_conn This patch creates two new fields in struct hci_conn to save the minimum and maximum connection interval values used to establish the connection this object represents. This change is required in order to know what parameters the connection is currently using. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_conn.c | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 378e2f32cfa0..b9676cc1a59d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -334,6 +334,8 @@ struct hci_conn { __u8 passkey_entered; __u16 disc_timeout; __u16 setting; + __u16 le_conn_min_interval; + __u16 le_conn_max_interval; unsigned long flags; __u8 remote_cap; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 0266bd8e4913..7f148c975736 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -558,8 +558,8 @@ static int hci_create_le_conn(struct hci_conn *conn) bacpy(&cp.peer_addr, &conn->dst); cp.peer_addr_type = conn->dst_type; cp.own_address_type = conn->src_type; - cp.conn_interval_min = cpu_to_le16(hdev->le_conn_min_interval); - cp.conn_interval_max = cpu_to_le16(hdev->le_conn_max_interval); + cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval); + cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval); cp.supervision_timeout = __constant_cpu_to_le16(0x002a); cp.min_ce_len = __constant_cpu_to_le16(0x0000); cp.max_ce_len = __constant_cpu_to_le16(0x0000); @@ -624,6 +624,8 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, conn->sec_level = BT_SECURITY_LOW; conn->pending_sec_level = sec_level; conn->auth_type = auth_type; + conn->le_conn_min_interval = hdev->le_conn_min_interval; + conn->le_conn_max_interval = hdev->le_conn_max_interval; err = hci_create_le_conn(conn); if (err) From 5c136e90a45e3d8e050b212f8f40f2d81f096879 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 30 Jan 2014 18:22:05 -0300 Subject: [PATCH 072/414] Bluetooth: Group list_head fields from strcut hci_dev together This patch groups the list_head fields from struct hci_dev together and removes empty lines between them. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b9676cc1a59d..2e1d184bd8d3 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -259,18 +259,15 @@ struct hci_dev { __u32 req_status; __u32 req_result; - struct list_head mgmt_pending; struct discovery_state discovery; struct hci_conn_hash conn_hash; + + struct list_head mgmt_pending; struct list_head blacklist; - struct list_head uuids; - struct list_head link_keys; - struct list_head long_term_keys; - struct list_head remote_oob_data; struct hci_dev_stats stat; From 9bb3c01fdb2201d405dfff8950145640b2355ec4 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 30 Jan 2014 18:22:08 -0300 Subject: [PATCH 073/414] Bluetooth: Introduce le_conn_failed() helper This patch moves connection attempt failure code to its own function so it can be reused in the next patch. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7f148c975736..7ef5bffb61aa 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -514,6 +514,21 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) } EXPORT_SYMBOL(hci_get_route); +/* This function requires the caller holds hdev->lock */ +static void le_conn_failed(struct hci_conn *conn, u8 status) +{ + struct hci_dev *hdev = conn->hdev; + + conn->state = BT_CLOSED; + + mgmt_connect_failed(hdev, &conn->dst, conn->type, conn->dst_type, + status); + + hci_proto_connect_cfm(conn, status); + + hci_conn_del(conn); +} + static void create_le_conn_complete(struct hci_dev *hdev, u8 status) { struct hci_conn *conn; @@ -530,14 +545,7 @@ static void create_le_conn_complete(struct hci_dev *hdev, u8 status) if (!conn) goto done; - conn->state = BT_CLOSED; - - mgmt_connect_failed(hdev, &conn->dst, conn->type, conn->dst_type, - status); - - hci_proto_connect_cfm(conn, status); - - hci_conn_del(conn); + le_conn_failed(conn, status); done: hci_dev_unlock(hdev); From b1de97d8c06d9d8d38e85dc5b0cf3630372e702c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 31 Jan 2014 11:55:21 -0800 Subject: [PATCH 074/414] Bluetooth: Add management setting for use of debug keys When the controller has been enabled to allow usage of debug keys, then clearly identify that in the current settings information. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/mgmt.h | 1 + net/bluetooth/mgmt.c | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index e19049fb6c46..f87f5d784c3b 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -95,6 +95,7 @@ struct mgmt_rp_read_index_list { #define MGMT_SETTING_LE 0x00000200 #define MGMT_SETTING_ADVERTISING 0x00000400 #define MGMT_SETTING_SECURE_CONN 0x00000800 +#define MGMT_SETTING_DEBUG_KEYS 0x00001000 #define MGMT_OP_READ_INFO 0x0004 #define MGMT_READ_INFO_SIZE 0 diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 111b1296a2b8..91ffecd1727e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -364,6 +364,7 @@ static u32 get_supported_settings(struct hci_dev *hdev) settings |= MGMT_SETTING_POWERED; settings |= MGMT_SETTING_PAIRABLE; + settings |= MGMT_SETTING_DEBUG_KEYS; if (lmp_bredr_capable(hdev)) { settings |= MGMT_SETTING_CONNECTABLE; @@ -431,6 +432,9 @@ static u32 get_current_settings(struct hci_dev *hdev) if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) settings |= MGMT_SETTING_SECURE_CONN; + if (test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags)) + settings |= MGMT_SETTING_DEBUG_KEYS; + return settings; } @@ -2207,6 +2211,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, { struct mgmt_cp_load_link_keys *cp = data; u16 key_count, expected_len; + bool changed; int i; BT_DBG("request for %s", hdev->name); @@ -2246,9 +2251,12 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, hci_link_keys_clear(hdev); if (cp->debug_keys) - set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); + changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); else - clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); + changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); + + if (changed) + new_settings(hdev, NULL); for (i = 0; i < key_count; i++) { struct mgmt_link_key_info *key = &cp->keys[i]; From 4e39ac81366583486b857c88656409e56befefdf Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 31 Jan 2014 11:55:22 -0800 Subject: [PATCH 075/414] Bluetooth: Add management command to allow use of debug keys Originally allowing the use of debug keys was done via the Load Link Keys management command. However this is BR/EDR specific and to be flexible and allow extending this to LE as well, make this an independent command. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/mgmt.h | 2 ++ net/bluetooth/mgmt.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index f87f5d784c3b..dfab094fab73 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -387,6 +387,8 @@ struct mgmt_cp_set_scan_params { #define MGMT_OP_SET_SECURE_CONN 0x002D +#define MGMT_OP_SET_DEBUG_KEYS 0x002E + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 91ffecd1727e..70a3a7e917b7 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -80,6 +80,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_SET_STATIC_ADDRESS, MGMT_OP_SET_SCAN_PARAMS, MGMT_OP_SET_SECURE_CONN, + MGMT_OP_SET_DEBUG_KEYS, }; static const u16 mgmt_events[] = { @@ -4111,6 +4112,38 @@ failed: return err; } +static int set_debug_keys(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_mode *cp = data; + bool changed; + int err; + + BT_DBG("request for %s", hdev->name); + + if (cp->val != 0x00 && cp->val != 0x01) + return cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS, + MGMT_STATUS_INVALID_PARAMS); + + hci_dev_lock(hdev); + + if (cp->val) + changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); + else + changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); + + err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev); + if (err < 0) + goto unlock; + + if (changed) + err = new_settings(hdev, sk); + +unlock: + hci_dev_unlock(hdev); + return err; +} + static bool ltk_is_valid(struct mgmt_ltk_info *key) { if (key->authenticated != 0x00 && key->authenticated != 0x01) @@ -4240,6 +4273,7 @@ static const struct mgmt_handler { { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE }, { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE }, { set_secure_conn, false, MGMT_SETTING_SIZE }, + { set_debug_keys, false, MGMT_SETTING_SIZE }, }; From 626bee82b8f306baf8d37fb3f9208b861708a1a5 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 31 Jan 2014 11:55:23 -0800 Subject: [PATCH 076/414] Bluetooth: Remove use_debug_keys debugfs entry Since the use of debug keys can now be identified from the current settings information, this debugfs entry is no longer necessary. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index d370b432aea6..7a44c8c1037a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -285,24 +285,6 @@ static const struct file_operations link_keys_fops = { .release = single_release, }; -static ssize_t use_debug_keys_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct hci_dev *hdev = file->private_data; - char buf[3]; - - buf[0] = test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags) ? 'Y': 'N'; - buf[1] = '\n'; - buf[2] = '\0'; - return simple_read_from_buffer(user_buf, count, ppos, buf, 2); -} - -static const struct file_operations use_debug_keys_fops = { - .open = simple_open, - .read = use_debug_keys_read, - .llseek = default_llseek, -}; - static int dev_class_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; @@ -1494,8 +1476,6 @@ static int __hci_init(struct hci_dev *hdev) hdev, &inquiry_cache_fops); debugfs_create_file("link_keys", 0400, hdev->debugfs, hdev, &link_keys_fops); - debugfs_create_file("use_debug_keys", 0444, hdev->debugfs, - hdev, &use_debug_keys_fops); debugfs_create_file("dev_class", 0444, hdev->debugfs, hdev, &dev_class_fops); debugfs_create_file("voice_setting", 0444, hdev->debugfs, From dc8357cc72976f2fbe955e2ad4bba9e0e8ba5022 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 31 Jan 2014 16:24:27 -0800 Subject: [PATCH 077/414] Bluetooth: Remove one level of indentation from hci_encrypt_change_evt The function already has an unlock label which means the one extra level on indentation is not useful and just makes the code more complex. So remove it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 51 ++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 7bb8094a3ff2..62aea2edc231 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1988,35 +1988,36 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); - if (conn) { - if (!ev->status) { - if (ev->encrypt) { - /* Encryption implies authentication */ - conn->link_mode |= HCI_LM_AUTH; - conn->link_mode |= HCI_LM_ENCRYPT; - conn->sec_level = conn->pending_sec_level; - } else - conn->link_mode &= ~HCI_LM_ENCRYPT; - } + if (!conn) + goto unlock; - clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); - - if (ev->status && conn->state == BT_CONNECTED) { - hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE); - hci_conn_drop(conn); - goto unlock; - } - - if (conn->state == BT_CONFIG) { - if (!ev->status) - conn->state = BT_CONNECTED; - - hci_proto_connect_cfm(conn, ev->status); - hci_conn_drop(conn); + if (!ev->status) { + if (ev->encrypt) { + /* Encryption implies authentication */ + conn->link_mode |= HCI_LM_AUTH; + conn->link_mode |= HCI_LM_ENCRYPT; + conn->sec_level = conn->pending_sec_level; } else - hci_encrypt_cfm(conn, ev->status, ev->encrypt); + conn->link_mode &= ~HCI_LM_ENCRYPT; } + clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); + + if (ev->status && conn->state == BT_CONNECTED) { + hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE); + hci_conn_drop(conn); + goto unlock; + } + + if (conn->state == BT_CONFIG) { + if (!ev->status) + conn->state = BT_CONNECTED; + + hci_proto_connect_cfm(conn, ev->status); + hci_conn_drop(conn); + } else + hci_encrypt_cfm(conn, ev->status, ev->encrypt); + unlock: hci_dev_unlock(hdev); } From abf76bad8fb503fb21fb0eba854fa048c75ff123 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 31 Jan 2014 16:24:28 -0800 Subject: [PATCH 078/414] Bluetooth: Track the AES-CCM encryption status of LE and BR/EDR links When encryption for LE links has been enabled, it will always be use AES-CCM encryption. In case of BR/EDR Secure Connections, the link will also use AES-CCM encryption. In both cases track the AES-CCM status in the connection flags. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_event.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2e1d184bd8d3..6854384b1f25 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -448,6 +448,7 @@ enum { HCI_CONN_MGMT_CONNECTED, HCI_CONN_SSP_ENABLED, HCI_CONN_SC_ENABLED, + HCI_CONN_AES_CCM, HCI_CONN_POWER_SAVE, HCI_CONN_REMOTE_OOB, HCI_CONN_6LOWPAN, diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 62aea2edc231..36c9a488ac56 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1997,8 +1997,14 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->link_mode |= HCI_LM_AUTH; conn->link_mode |= HCI_LM_ENCRYPT; conn->sec_level = conn->pending_sec_level; - } else + + if ((conn->type == ACL_LINK && ev->encrypt == 0x02) || + conn->type == LE_LINK) + set_bit(HCI_CONN_AES_CCM, &conn->flags); + } else { conn->link_mode &= ~HCI_LM_ENCRYPT; + clear_bit(HCI_CONN_AES_CCM, &conn->flags); + } } clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); From f8159247755e77d8264ccce84054ff893275115e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 31 Jan 2014 18:42:16 -0800 Subject: [PATCH 079/414] Bluetooth: Remove check for valid LTK authenticated parameter The LTK authenticated parameter is the key type of the LTK and similar to link keys there is no need to check the currently supported values. For possible future improvements, the kernel will only use key types it knows about and just ignore all the other ones. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 70a3a7e917b7..8030eeb44382 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4146,8 +4146,6 @@ unlock: static bool ltk_is_valid(struct mgmt_ltk_info *key) { - if (key->authenticated != 0x00 && key->authenticated != 0x01) - return false; if (key->master != 0x00 && key->master != 0x01) return false; if (!bdaddr_type_is_le(key->addr.type)) From d40f3eef0b9b70d15d5fd0031c0633d4a9ed78cd Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 31 Jan 2014 18:42:17 -0800 Subject: [PATCH 080/414] Bluetooth: Rename authentication to key_type in mgmt_ltk_info The field is not a boolean, it is actually a field for a key type. So name it properly. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/mgmt.h | 2 +- net/bluetooth/mgmt.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index dfab094fab73..4303fa90b7c1 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -182,7 +182,7 @@ struct mgmt_cp_load_link_keys { struct mgmt_ltk_info { struct mgmt_addr_info addr; - __u8 authenticated; + __u8 type; __u8 master; __u8 enc_size; __le16 ediv; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 8030eeb44382..8c94841072a8 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4207,7 +4207,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, type = HCI_SMP_LTK_SLAVE; hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, - type, 0, key->authenticated, key->val, + type, 0, key->type, key->val, key->enc_size, key->ediv, key->rand); } @@ -4648,7 +4648,7 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent) ev.store_hint = persistent; bacpy(&ev.key.addr.bdaddr, &key->bdaddr); ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type); - ev.key.authenticated = key->authenticated; + ev.key.type = key->authenticated; ev.key.enc_size = key->enc_size; ev.key.ediv = key->ediv; From 03c515d7486b7a519728340d4b04baaad16bf806 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 31 Jan 2014 18:42:18 -0800 Subject: [PATCH 081/414] Bluetooth: Remove __packed from struct smp_ltk The struct smp_ltk does not need to be packed and so remove __packed. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 6854384b1f25..4e878780fa01 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -101,7 +101,7 @@ struct smp_ltk { __le16 ediv; u8 rand[8]; u8 val[16]; -} __packed; +}; struct link_key { struct list_head list; From 0ab04a9c0e8e37ca495fb08c8b83615c5f144551 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 1 Feb 2014 09:19:57 -0800 Subject: [PATCH 082/414] Bluetooth: Add management command for Secure Connection Only Mode With support for Secure Connections it is possible to switch the controller into a mode that is called Secure Connections Only. In this mode only security level 4 connections are allowed (with the exception of security level 0 approved services). This patch just introduces the management command and setting of the right internal flags to enable this mode. It does not yet enforce it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 8c94841072a8..ce7ef339b1c4 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4043,7 +4043,7 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, { struct mgmt_mode *cp = data; struct pending_cmd *cmd; - u8 status; + u8 val, status; int err; BT_DBG("request for %s", hdev->name); @@ -4058,7 +4058,7 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, MGMT_STATUS_NOT_SUPPORTED); - if (cp->val != 0x00 && cp->val != 0x01) + if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02) return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, MGMT_STATUS_INVALID_PARAMS); @@ -4067,12 +4067,18 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) { bool changed; - if (cp->val) + if (cp->val) { changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags); - else + if (cp->val == 0x02) + set_bit(HCI_SC_ONLY, &hdev->dev_flags); + else + clear_bit(HCI_SC_ONLY, &hdev->dev_flags); + } else { changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags); + clear_bit(HCI_SC_ONLY, &hdev->dev_flags); + } err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev); if (err < 0) @@ -4090,7 +4096,10 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, goto failed; } - if (!!cp->val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) { + val = !!cp->val; + + if (val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags) && + (cp->val == 0x02) == test_bit(HCI_SC_ONLY, &hdev->dev_flags)) { err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev); goto failed; } @@ -4101,12 +4110,17 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, goto failed; } - err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &cp->val); + err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &val); if (err < 0) { mgmt_pending_remove(cmd); goto failed; } + if (cp->val == 0x02) + set_bit(HCI_SC_ONLY, &hdev->dev_flags); + else + clear_bit(HCI_SC_ONLY, &hdev->dev_flags); + failed: hci_dev_unlock(hdev); return err; @@ -5063,19 +5077,24 @@ void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) if (status) { u8 mgmt_err = mgmt_status(status); - if (enable && test_and_clear_bit(HCI_SC_ENABLED, - &hdev->dev_flags)) - new_settings(hdev, NULL); + if (enable) { + if (test_and_clear_bit(HCI_SC_ENABLED, + &hdev->dev_flags)) + new_settings(hdev, NULL); + clear_bit(HCI_SC_ONLY, &hdev->dev_flags); + } mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev, cmd_status_rsp, &mgmt_err); return; } - if (enable) + if (enable) { changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags); - else + } else { changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags); + clear_bit(HCI_SC_ONLY, &hdev->dev_flags); + } mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev, settings_rsp, &match); From 9cb2e030e6a0787f5c216702e6e78dd85ffe04c4 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 1 Feb 2014 11:32:25 -0800 Subject: [PATCH 083/414] Bluetooth: Include security level 4 in connections check This check is only used for RFCOMM connections and most likely no RFCOMM based profile will require security level 4 secure connection security policy. In case it ever does make sure that seucrity level 4 is treated as sufficient security level. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7ef5bffb61aa..801820f12226 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -860,13 +860,17 @@ int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level) { BT_DBG("hcon %p", conn); - if (sec_level != BT_SECURITY_HIGH) - return 1; /* Accept if non-secure is required */ - - if (conn->sec_level == BT_SECURITY_HIGH) + /* Accept if non-secure or higher security level is required */ + if (sec_level != BT_SECURITY_HIGH && sec_level != BT_SECURITY_FIPS) return 1; - return 0; /* Reject not secure link */ + /* Accept if secure or higher security level is already present */ + if (conn->sec_level == BT_SECURITY_HIGH || + conn->sec_level == BT_SECURITY_FIPS) + return 1; + + /* Reject not secure link */ + return 0; } EXPORT_SYMBOL(hci_conn_check_secure); From 914a6ffe42259267239a23d4f23ef06b0a0369a4 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 1 Feb 2014 11:52:02 -0800 Subject: [PATCH 084/414] Bluetooth: Track if link is using P-256 authenticated combination key When the ACL link is using P-256 authenticated combination key, mark the link mode as HCI_LM_FIPS. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 36c9a488ac56..d2c6878a9d6a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1998,6 +1998,10 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->link_mode |= HCI_LM_ENCRYPT; conn->sec_level = conn->pending_sec_level; + /* P-256 authentication key implies FIPS */ + if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256) + conn->link_mode |= HCI_LM_FIPS; + if ((conn->type == ACL_LINK && ev->encrypt == 0x02) || conn->type == LE_LINK) set_bit(HCI_CONN_AES_CCM, &conn->flags); From 424ef94311512ef48a5464d173ef83862e4653cb Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 31 Jan 2014 19:02:30 -0800 Subject: [PATCH 085/414] Bluetooth: Add constants for LTK key types The LTK key types available right now are unauthenticated and authenticated ones. Provide two simple constants for it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 232c07804ca8..352d3d7d06bb 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -346,6 +346,10 @@ enum { #define HCI_SMP_LTK 0x82 #define HCI_SMP_LTK_SLAVE 0x83 +/* Long Term Key types */ +#define HCI_LTK_UNAUTH 0x00 +#define HCI_LTK_AUTH 0x01 + /* ---- HCI Error Codes ---- */ #define HCI_ERROR_AUTH_FAILURE 0x05 #define HCI_ERROR_CONNECTION_TIMEOUT 0x08 From 15819a7065ac46eb804498bb7ccbba60d8f7d4d5 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 3 Feb 2014 13:56:18 -0300 Subject: [PATCH 086/414] Bluetooth: Introduce connection parameters list This patch adds to hdev the connection parameters list (hdev->le_ conn_params). The elements from this list (struct hci_conn_params) contains the connection parameters (for now, minimum and maximum connection interval) that should be used during the connection establishment. Moreover, this patch adds helper functions to manipulate hdev->le_ conn_params list. Some of these functions are also declared in hci_core.h since they will be used outside hci_core.c in upcoming patches. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 18 ++++++++ net/bluetooth/hci_core.c | 77 ++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4e878780fa01..92fa75fce29d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -269,6 +269,7 @@ struct hci_dev { struct list_head link_keys; struct list_head long_term_keys; struct list_head remote_oob_data; + struct list_head le_conn_params; struct hci_dev_stats stat; @@ -373,6 +374,16 @@ struct hci_chan { __u8 state; }; +struct hci_conn_params { + struct list_head list; + + bdaddr_t addr; + u8 addr_type; + + u16 conn_min_interval; + u16 conn_max_interval; +}; + extern struct list_head hci_dev_list; extern struct list_head hci_cb_list; extern rwlock_t hci_dev_list_lock; @@ -751,6 +762,13 @@ int hci_blacklist_clear(struct hci_dev *hdev); int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); +struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, + bdaddr_t *addr, u8 addr_type); +void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, + u16 conn_min_interval, u16 conn_max_interval); +void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); +void hci_conn_params_clear(struct hci_dev *hdev); + int hci_uuids_clear(struct hci_dev *hdev); int hci_link_keys_clear(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 7a44c8c1037a..e7746690d620 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2924,6 +2924,81 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) return mgmt_device_unblocked(hdev, bdaddr, type); } +/* This function requires the caller holds hdev->lock */ +struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, + bdaddr_t *addr, u8 addr_type) +{ + struct hci_conn_params *params; + + list_for_each_entry(params, &hdev->le_conn_params, list) { + if (bacmp(¶ms->addr, addr) == 0 && + params->addr_type == addr_type) { + return params; + } + } + + return NULL; +} + +/* This function requires the caller holds hdev->lock */ +void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, + u16 conn_min_interval, u16 conn_max_interval) +{ + struct hci_conn_params *params; + + params = hci_conn_params_lookup(hdev, addr, addr_type); + if (params) { + params->conn_min_interval = conn_min_interval; + params->conn_max_interval = conn_max_interval; + return; + } + + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) { + BT_ERR("Out of memory"); + return; + } + + bacpy(¶ms->addr, addr); + params->addr_type = addr_type; + params->conn_min_interval = conn_min_interval; + params->conn_max_interval = conn_max_interval; + + list_add(¶ms->list, &hdev->le_conn_params); + + BT_DBG("addr %pMR (type %u) conn_min_interval 0x%.4x " + "conn_max_interval 0x%.4x", addr, addr_type, conn_min_interval, + conn_max_interval); +} + +/* This function requires the caller holds hdev->lock */ +void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) +{ + struct hci_conn_params *params; + + params = hci_conn_params_lookup(hdev, addr, addr_type); + if (!params) + return; + + list_del(¶ms->list); + kfree(params); + + BT_DBG("addr %pMR (type %u)", addr, addr_type); +} + +/* This function requires the caller holds hdev->lock */ +void hci_conn_params_clear(struct hci_dev *hdev) +{ + struct hci_conn_params *params, *tmp; + + list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) { + list_del(¶ms->list); + kfree(params); + } + + BT_DBG("All LE connection parameters were removed"); +} + static void inquiry_complete(struct hci_dev *hdev, u8 status) { if (status) { @@ -3034,6 +3109,7 @@ struct hci_dev *hci_alloc_dev(void) INIT_LIST_HEAD(&hdev->link_keys); INIT_LIST_HEAD(&hdev->long_term_keys); INIT_LIST_HEAD(&hdev->remote_oob_data); + INIT_LIST_HEAD(&hdev->le_conn_params); INIT_LIST_HEAD(&hdev->conn_hash.list); INIT_WORK(&hdev->rx_work, hci_rx_work); @@ -3219,6 +3295,7 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_link_keys_clear(hdev); hci_smp_ltks_clear(hdev); hci_remote_oob_data_clear(hdev); + hci_conn_params_clear(hdev); hci_dev_unlock(hdev); hci_dev_put(hdev); From 4292f1f3370193fd3f2e4f849211fd9596ce832f Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 3 Feb 2014 13:56:19 -0300 Subject: [PATCH 087/414] Bluetooth: Use connection parameters if any This patch changes hci_connect_le() so it uses the connection parameters specified for the certain device. If no parameters were configured, we use the default values. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 801820f12226..67972928a623 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -586,6 +586,7 @@ static int hci_create_le_conn(struct hci_conn *conn) static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, u8 dst_type, u8 sec_level, u8 auth_type) { + struct hci_conn_params *params; struct hci_conn *conn; int err; @@ -632,8 +633,15 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, conn->sec_level = BT_SECURITY_LOW; conn->pending_sec_level = sec_level; conn->auth_type = auth_type; - conn->le_conn_min_interval = hdev->le_conn_min_interval; - conn->le_conn_max_interval = hdev->le_conn_max_interval; + + params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); + if (params) { + conn->le_conn_min_interval = params->conn_min_interval; + conn->le_conn_max_interval = params->conn_max_interval; + } else { + conn->le_conn_min_interval = hdev->le_conn_min_interval; + conn->le_conn_max_interval = hdev->le_conn_max_interval; + } err = hci_create_le_conn(conn); if (err) From 5045388ceec19979e816f229f07547ec7067ccd5 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 5 Feb 2014 19:12:24 +0200 Subject: [PATCH 088/414] iwlwifi: pcie: clean iwl_pcie_[rt]xq_inc_wr_ptr a bit The various code blocks in iwl_pcie_[rt]xq_inc_wr_ptr finally do the same things, so just merge them all and make the functions cleaner. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/rx.c | 45 +++++++----------- drivers/net/wireless/iwlwifi/pcie/tx.c | 63 ++++++++++++-------------- 2 files changed, 46 insertions(+), 62 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 41f684deff97..cf49f6ce0ff8 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -155,37 +155,26 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans, if (rxq->need_update == 0) goto exit_unlock; - if (trans->cfg->base_params->shadow_reg_enable) { - /* shadow register enabled */ - /* Device expects a multiple of 8 */ - rxq->write_actual = (rxq->write & ~0x7); - iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual); - } else { - /* If power-saving is in use, make sure device is awake */ - if (test_bit(STATUS_TPOWER_PMI, &trans->status)) { - reg = iwl_read32(trans, CSR_UCODE_DRV_GP1); + /* + * explicitly wake up the NIC if: + * 1. shadow registers aren't enabled + * 2. there is a chance that the NIC is asleep + */ + if (!trans->cfg->base_params->shadow_reg_enable && + test_bit(STATUS_TPOWER_PMI, &trans->status)) { + reg = iwl_read32(trans, CSR_UCODE_DRV_GP1); - if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { - IWL_DEBUG_INFO(trans, - "Rx queue requesting wakeup," - " GP1 = 0x%x\n", reg); - iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - goto exit_unlock; - } - - rxq->write_actual = (rxq->write & ~0x7); - iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR, - rxq->write_actual); - - /* Else device is assumed to be awake */ - } else { - /* Device expects a multiple of 8 */ - rxq->write_actual = (rxq->write & ~0x7); - iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR, - rxq->write_actual); + if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + IWL_DEBUG_INFO(trans, "Rx queue requesting wakeup, GP1 = 0x%x\n", + reg); + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + goto exit_unlock; } } + + rxq->write_actual = round_down(rxq->write, 8); + iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual); rxq->need_update = 0; exit_unlock: diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 254126447c68..e476d9eda61a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -296,43 +296,38 @@ void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq) if (txq->need_update == 0) return; - if (trans->cfg->base_params->shadow_reg_enable || - txq_id == trans_pcie->cmd_queue) { - /* shadow register enabled */ - iwl_write32(trans, HBUS_TARG_WRPTR, - txq->q.write_ptr | (txq_id << 8)); - } else { - /* if we're trying to save power */ - if (test_bit(STATUS_TPOWER_PMI, &trans->status)) { - /* wake up nic if it's powered down ... - * uCode will wake up, and interrupt us again, so next - * time we'll skip this part. */ - reg = iwl_read32(trans, CSR_UCODE_DRV_GP1); - - if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { - IWL_DEBUG_INFO(trans, - "Tx queue %d requesting wakeup," - " GP1 = 0x%x\n", txq_id, reg); - iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - return; - } - - IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id, - txq->q.write_ptr); - - iwl_write_direct32(trans, HBUS_TARG_WRPTR, - txq->q.write_ptr | (txq_id << 8)); - + /* + * explicitly wake up the NIC if: + * 1. shadow registers aren't enabled + * 2. NIC is woken up for CMD regardless of shadow outside this function + * 3. there is a chance that the NIC is asleep + */ + if (!trans->cfg->base_params->shadow_reg_enable && + txq_id != trans_pcie->cmd_queue && + test_bit(STATUS_TPOWER_PMI, &trans->status)) { /* - * else not in power-save mode, - * uCode will never sleep when we're - * trying to tx (during RFKILL, we're not trying to tx). + * wake up nic if it's powered down ... + * uCode will wake up, and interrupt us again, so next + * time we'll skip this part. */ - } else - iwl_write32(trans, HBUS_TARG_WRPTR, - txq->q.write_ptr | (txq_id << 8)); + reg = iwl_read32(trans, CSR_UCODE_DRV_GP1); + + if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + IWL_DEBUG_INFO(trans, "Tx queue %d requesting wakeup, GP1 = 0x%x\n", + txq_id, reg); + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + return; + } } + + /* + * if not in power-save mode, uCode will never sleep when we're + * trying to tx (during RFKILL, we're not trying to tx). + */ + IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id, txq->q.write_ptr); + iwl_write32(trans, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); + txq->need_update = 0; } From e5209263df94a41090199c95b21939139760fd85 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Jan 2014 23:38:59 +0100 Subject: [PATCH 089/414] iwlwifi: make various things const There are a number of things in the .data section that should really be in .rodata, for example all ops structs and strings. Mark everything const that can be, leaving the .data section pretty much empty. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/agn.h | 4 ++-- drivers/net/wireless/iwlwifi/dvm/devices.c | 2 +- drivers/net/wireless/iwlwifi/dvm/mac80211.c | 2 +- drivers/net/wireless/iwlwifi/dvm/rx.c | 2 +- drivers/net/wireless/iwlwifi/iwl-trans.h | 2 +- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 3 +-- drivers/net/wireless/iwlwifi/mvm/ops.c | 2 +- drivers/net/wireless/iwlwifi/mvm/utils.c | 4 ++-- drivers/net/wireless/iwlwifi/pcie/internal.h | 2 +- 10 files changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index 562772d85102..c160dad03037 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h @@ -109,7 +109,7 @@ extern const struct iwl_dvm_cfg iwl_dvm_6030_cfg; struct iwl_ucode_capabilities; -extern struct ieee80211_ops iwlagn_hw_ops; +extern const struct ieee80211_ops iwlagn_hw_ops; static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd) { @@ -480,7 +480,7 @@ do { \ } while (0) #endif /* CONFIG_IWLWIFI_DEBUG */ -extern const char *iwl_dvm_cmd_strings[REPLY_MAX]; +extern const char *const iwl_dvm_cmd_strings[REPLY_MAX]; static inline const char *iwl_dvm_get_cmd_string(u8 cmd) { diff --git a/drivers/net/wireless/iwlwifi/dvm/devices.c b/drivers/net/wireless/iwlwifi/dvm/devices.c index 7b140e487deb..758c54eeb206 100644 --- a/drivers/net/wireless/iwlwifi/dvm/devices.c +++ b/drivers/net/wireless/iwlwifi/dvm/devices.c @@ -317,7 +317,7 @@ static const struct iwl_sensitivity_ranges iwl5000_sensitivity = { .nrg_th_cca = 62, }; -static struct iwl_sensitivity_ranges iwl5150_sensitivity = { +static const struct iwl_sensitivity_ranges iwl5150_sensitivity = { .min_nrg_cck = 95, .auto_corr_min_ofdm = 90, .auto_corr_min_ofdm_mrc = 170, diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index c24d1d3d55f6..f57608943ca6 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -1564,7 +1564,7 @@ static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "leave\n"); } -struct ieee80211_ops iwlagn_hw_ops = { +const struct ieee80211_ops iwlagn_hw_ops = { .tx = iwlagn_mac_tx, .start = iwlagn_mac_start, .stop = iwlagn_mac_stop, diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index 7a1bc1c547e1..cd8377346aff 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c @@ -39,7 +39,7 @@ #define IWL_CMD_ENTRY(x) [x] = #x -const char *iwl_dvm_cmd_strings[REPLY_MAX] = { +const char *const iwl_dvm_cmd_strings[REPLY_MAX] = { IWL_CMD_ENTRY(REPLY_ALIVE), IWL_CMD_ENTRY(REPLY_ERROR), IWL_CMD_ENTRY(REPLY_ECHO), diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 7b19274b550f..8cdb0dd618a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -393,7 +393,7 @@ struct iwl_trans_config { bool rx_buf_size_8k; bool bc_table_dword; unsigned int queue_watchdog_timeout; - const char **command_names; + const char *const *command_names; }; struct iwl_trans; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index ba4dcabf7c4a..42f70469e73b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -2233,7 +2233,7 @@ static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw, } #endif -struct ieee80211_ops iwl_mvm_hw_ops = { +const struct ieee80211_ops iwl_mvm_hw_ops = { .tx = iwl_mvm_mac_tx, .ampdu_action = iwl_mvm_mac_ampdu_action, .start = iwl_mvm_mac_start, diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index ebea5f2e2741..bde8190bb6c4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -91,8 +91,7 @@ enum iwl_mvm_tx_fifo { IWL_MVM_TX_FIFO_MCAST = 5, }; -extern struct ieee80211_ops iwl_mvm_hw_ops; -extern const struct iwl_mvm_power_ops pm_mac_ops; +extern const struct ieee80211_ops iwl_mvm_hw_ops; /** * struct iwl_mvm_mod_params - module parameters for iwlmvm diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index a46f0b8b0870..ae347fb16a5d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -245,7 +245,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { #undef RX_HANDLER #define CMD(x) [x] = #x -static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { +static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(MVM_ALIVE), CMD(REPLY_ERROR), CMD(INIT_COMPLETE_NOTIF), diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index f4598cb2dd2e..2021b57189bc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -289,8 +289,8 @@ u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx) return last_idx; } -static struct { - char *name; +static const struct { + const char *name; u8 num; } advanced_lookup[] = { { "NMI_INTERRUPT_WDG", 0x34 }, diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index e851f26fd44c..3120bc5bb12d 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -304,7 +304,7 @@ struct iwl_trans_pcie { bool bc_table_dword; u32 rx_page_order; - const char **command_names; + const char *const *command_names; /* queue watchdog */ unsigned long wd_timeout; From 7b1dd048b53053d4c6339d1e6043fa7bb82ff93d Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 4 Feb 2014 15:32:43 +0200 Subject: [PATCH 090/414] iwlwifi: mvm: propagate LDPC / STBC status to radiotap This will allow to get sniffer captures with correct settings for these HT / VHT capabilities. Also set the corresponding HAVE_MCS / VHT_KNOWN bits in the registration to mac80211. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h | 3 ++- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 4 ++++ drivers/net/wireless/iwlwifi/mvm/rs.c | 2 +- drivers/net/wireless/iwlwifi/mvm/rx.c | 8 ++++++++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h index 85057219cc43..39148b5bb332 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h @@ -257,7 +257,8 @@ enum { /* Bit 17-18: (0) SS, (1) SS*2 */ #define RATE_MCS_STBC_POS 17 -#define RATE_MCS_STBC_MSK (1 << RATE_MCS_STBC_POS) +#define RATE_MCS_HT_STBC_MSK (3 << RATE_MCS_STBC_POS) +#define RATE_MCS_VHT_STBC_MSK (1 << RATE_MCS_STBC_POS) /* Bit 19: (0) Beamforming is off, (1) Beamforming is on */ #define RATE_MCS_BF_POS 19 diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 42f70469e73b..2a1b4b628e2f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -68,6 +68,7 @@ #include #include #include +#include #include #include "iwl-op-mode.h" @@ -280,6 +281,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->queues = mvm->first_agg_queue; hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; + hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC | + IEEE80211_RADIOTAP_MCS_HAVE_STBC; + hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC; hw->rate_control_algorithm = "iwl-mvm-rs"; /* diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 32bb8075121c..a6d0ab129c6b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2595,7 +2595,7 @@ static int rs_pretty_print_rate(char *buf, const u32 rate) return sprintf(buf, "%s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s%s\n", type, rs_pretty_ant(ant), bw, mcs, nss, (rate & RATE_MCS_SGI_MSK) ? "SGI " : "NGI ", - (rate & RATE_MCS_STBC_MSK) ? "STBC " : "", + (rate & RATE_MCS_HT_STBC_MSK) ? "STBC " : "", (rate & RATE_MCS_LDPC_MSK) ? "LDPC " : "", (rate & RATE_MCS_BF_MSK) ? "BF " : "", (rate & RATE_MCS_ZLF_MSK) ? "ZLF " : ""); diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index fa3c1393e103..817d3e0b37e2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -368,15 +368,23 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, rx_status.flag |= RX_FLAG_SHORT_GI; if (rate_n_flags & RATE_HT_MCS_GF_MSK) rx_status.flag |= RX_FLAG_HT_GF; + if (rate_n_flags & RATE_MCS_LDPC_MSK) + rx_status.flag |= RX_FLAG_LDPC; if (rate_n_flags & RATE_MCS_HT_MSK) { + u8 stbc = (rate_n_flags & RATE_MCS_HT_STBC_MSK) >> + RATE_MCS_STBC_POS; rx_status.flag |= RX_FLAG_HT; rx_status.rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; + rx_status.flag |= stbc << RX_FLAG_STBC_SHIFT; } else if (rate_n_flags & RATE_MCS_VHT_MSK) { + u8 stbc = (rate_n_flags & RATE_MCS_VHT_STBC_MSK) >> + RATE_MCS_STBC_POS; rx_status.vht_nss = ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> RATE_VHT_MCS_NSS_POS) + 1; rx_status.rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; rx_status.flag |= RX_FLAG_VHT; + rx_status.flag |= stbc << RX_FLAG_STBC_SHIFT; } else { rx_status.rate_idx = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, From 63f7535d6eb80a465d353c414d14560367c34fb2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 31 Jan 2014 14:56:18 +0100 Subject: [PATCH 091/414] iwlwifi: mvm: use IEEE80211_TX_CTRL_PORT_CTRL_PROTO flag Instead of checking the SKB protocol against EAP, check the IEEE80211_TX_CTRL_PORT_CTRL_PROTO flag that more generally indicates whether or not the frame is a port control frame. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 8d18bf23e4bf..852d9d87a14c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -122,7 +122,7 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, * it */ WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU); - } else if (skb->protocol == cpu_to_be16(ETH_P_PAE)) { + } else if (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO) { tx_cmd->pm_frame_timeout = cpu_to_le16(2); } else { tx_cmd->pm_frame_timeout = 0; From f3c221f6ea17f4fea250ac17c7f27ecb71e62465 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 9 Jan 2014 13:12:54 +0200 Subject: [PATCH 092/414] iwlwifi: mvm: add debugfs for prph reg read/write Allow reading/writing prph registers. The address is set in the first argument of the write operation. second argument is optional and can be used for writing. e.g. echo '0xA01234 0x99' > /sys/kernel/debug/ieee80211/phy0/iwlwifi/iwlmvm/prph_reg will write 0x99 into reg 0xA01234 cat /sys/kernel/debug/ieee80211/phy0/iwlwifi/iwlmvm/prph_reg will show its current value (probably 0x99) Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 44 ++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + 2 files changed, 45 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 6853e5efe522..9b9833720a24 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -907,6 +907,49 @@ static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf, #define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \ MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode) +static ssize_t +iwl_dbgfs_prph_reg_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + int pos = 0; + char buf[32]; + const size_t bufsz = sizeof(buf); + + if (!mvm->dbgfs_prph_reg_addr) + return -EINVAL; + + pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n", + mvm->dbgfs_prph_reg_addr, + iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr)); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t +iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf, + size_t count, loff_t *ppos) +{ + u8 args; + u32 value; + + args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value); + /* if we only want to set the reg address - nothing more to do */ + if (args == 1) + goto out; + + /* otherwise, make sure we have both address and value */ + if (args != 2) + return -EINVAL; + + iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value); +out: + return count; +} + +MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64); + /* Device wide debugfs entries */ MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16); MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8); @@ -951,6 +994,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, S_IWUSR | S_IRUSR); + MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR); MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR); #ifdef CONFIG_IWLWIFI_BCAST_FILTERING diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index bde8190bb6c4..29d11d93441d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -518,6 +518,7 @@ struct iwl_mvm { #ifdef CONFIG_IWLWIFI_DEBUGFS struct dentry *debugfs_dir; u32 dbgfs_sram_offset, dbgfs_sram_len; + u32 dbgfs_prph_reg_addr; bool disable_power_off; bool disable_power_off_d3; From 7303dd7f312f0d07a4bf45c62608d5233b5e8062 Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Mon, 3 Feb 2014 21:57:28 +0200 Subject: [PATCH 093/414] iwlwifi: mvm: Enable power save on BSS and P2P client in DCM New FW enables support for power save on BSS and P2P client MACs simultaneously when they function on different channels (DCM). Enable this case in the driver after examining new TLV flag - IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM. Still power management is not allowed on both MACs if they function on a same channel. Remove another redundant TLV flag - IWL_UCODE_TLV_FLAGS_P2P_PS that is not in use anymore. Remove bound_vif_cnt as redundant. Signed-off-by: Alexander Bondar Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw.h | 6 +-- .../net/wireless/iwlwifi/mvm/debugfs-vif.c | 2 +- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 6 --- drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 - drivers/net/wireless/iwlwifi/mvm/power.c | 48 +++++++++++++++---- 5 files changed, 44 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index f80ba586c253..b0d09987540d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -92,8 +92,8 @@ * @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API * @IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command * containing CAM (Continuous Active Mode) indication. - * @IWL_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a - * single bound interface). + * @IWL_UCODE_TLV_FLAGS_P2P_BSS_PS_DCM: support power save on BSS station and + * P2P client interfaces simultaneously if they are in different bindings. * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save * @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering. * @IWL_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients @@ -118,7 +118,7 @@ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_SCHED_SCAN = BIT(17), IWL_UCODE_TLV_FLAGS_STA_KEY_CMD = BIT(19), IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD = BIT(20), - IWL_UCODE_TLV_FLAGS_P2P_PS = BIT(21), + IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM = BIT(22), IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24), IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26), IWL_UCODE_TLV_FLAGS_BCAST_FILTERING = BIT(29), diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index 29b4396018b1..f64e972191eb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -591,7 +591,7 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM && ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) || (vif->type == NL80211_IFTYPE_STATION && vif->p2p && - mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS))) + mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM))) MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR | S_IRUSR); diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 2a1b4b628e2f..83da68c8b4a9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1305,7 +1305,6 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, mvmvif->ap_ibss_active = true; /* power updated needs to be done before quotas */ - mvm->bound_vif_cnt++; iwl_mvm_power_update_mac(mvm, vif); ret = iwl_mvm_update_quotas(mvm, vif); @@ -1324,7 +1323,6 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, return 0; out_quota_failed: - mvm->bound_vif_cnt--; iwl_mvm_power_update_mac(mvm, vif); mvmvif->ap_ibss_active = false; iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); @@ -1361,7 +1359,6 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); iwl_mvm_binding_remove_vif(mvm, vif); - mvm->bound_vif_cnt--; iwl_mvm_power_update_mac(mvm, vif); iwl_mvm_mac_ctxt_remove(mvm, vif); @@ -2095,7 +2092,6 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, * Power state must be updated before quotas, * otherwise fw will complain. */ - mvm->bound_vif_cnt++; iwl_mvm_power_update_mac(mvm, vif); /* Setting the quota at this stage is only required for monitor @@ -2113,7 +2109,6 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, out_remove_binding: iwl_mvm_binding_remove_vif(mvm, vif); - mvm->bound_vif_cnt--; iwl_mvm_power_update_mac(mvm, vif); out_unlock: mutex_unlock(&mvm->mutex); @@ -2146,7 +2141,6 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, } iwl_mvm_binding_remove_vif(mvm, vif); - mvm->bound_vif_cnt--; iwl_mvm_power_update_mac(mvm, vif); out_unlock: diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 29d11d93441d..823765ea89a9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -587,8 +587,6 @@ struct iwl_mvm { u8 first_agg_queue; u8 last_agg_queue; - u8 bound_vif_cnt; - /* Indicate if device power save is allowed */ bool ps_disabled; /* Indicate if device power management is allowed */ diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 4da1ea44f39a..def6ec5173b9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -425,7 +425,7 @@ static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm, return 0; if (vif->p2p && - !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS)) + !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)) return 0; iwl_mvm_power_build_cmd(mvm, vif, &cmd); @@ -511,8 +511,11 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, struct iwl_power_constraint { struct ieee80211_vif *bf_vif; struct ieee80211_vif *bss_vif; + u16 bss_phyctx_id; + u16 p2p_phyctx_id; bool pm_disabled; bool ps_disabled; + struct iwl_mvm *mvm; }; static void iwl_mvm_power_iterator(void *_data, u8 *mac, @@ -520,6 +523,7 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_power_constraint *power_iterator = _data; + struct iwl_mvm *mvm = power_iterator->mvm; switch (ieee80211_vif_type_p2p(vif)) { case NL80211_IFTYPE_P2P_DEVICE: @@ -539,11 +543,28 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac, break; case NL80211_IFTYPE_P2P_CLIENT: - /* no BSS power mgmt if we have a P2P client*/ - power_iterator->pm_disabled = true; + if (mvmvif->phy_ctxt) + power_iterator->p2p_phyctx_id = mvmvif->phy_ctxt->id; + + IWL_DEBUG_POWER(mvm, "p2p: p2p_id=%d, bss_id=%d\n", + power_iterator->p2p_phyctx_id, + power_iterator->bss_phyctx_id); + if (!(mvm->fw->ucode_capa.flags & + IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)) { + /* no BSS power mgmt if we have a P2P client*/ + power_iterator->pm_disabled = true; + } else if (power_iterator->p2p_phyctx_id < MAX_PHYS && + power_iterator->bss_phyctx_id < MAX_PHYS && + power_iterator->p2p_phyctx_id == + power_iterator->bss_phyctx_id) { + power_iterator->pm_disabled = true; + } break; case NL80211_IFTYPE_STATION: + if (mvmvif->phy_ctxt) + power_iterator->bss_phyctx_id = mvmvif->phy_ctxt->id; + /* we should have only one BSS vif */ WARN_ON(power_iterator->bss_vif); power_iterator->bss_vif = vif; @@ -551,6 +572,17 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac, if (mvmvif->bf_data.bf_enabled && !WARN_ON(power_iterator->bf_vif)) power_iterator->bf_vif = vif; + + IWL_DEBUG_POWER(mvm, "bss: p2p_id=%d, bss_id=%d\n", + power_iterator->p2p_phyctx_id, + power_iterator->bss_phyctx_id); + if (mvm->fw->ucode_capa.flags & + IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM && + (power_iterator->p2p_phyctx_id < MAX_PHYS && + power_iterator->bss_phyctx_id < MAX_PHYS && + power_iterator->p2p_phyctx_id == + power_iterator->bss_phyctx_id)) + power_iterator->pm_disabled = true; break; default: @@ -572,16 +604,16 @@ iwl_mvm_power_get_global_constraint(struct iwl_mvm *mvm, ieee80211_iterate_active_interfaces_atomic(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_power_iterator, constraint); - - /* TODO: remove this and determine this variable in the iterator */ - if (mvm->bound_vif_cnt > 1) - constraint->pm_disabled = true; } int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_power_constraint constraint = {}; + struct iwl_power_constraint constraint = { + .p2p_phyctx_id = MAX_PHYS, + .bss_phyctx_id = MAX_PHYS, + .mvm = mvm, + }; bool ba_enable; int ret; From 77db0a3c27dc0f027e5f3956f4ba77246c89a548 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Tue, 4 Feb 2014 14:21:38 +0200 Subject: [PATCH 094/414] iwlwifi: mvm: new NVM format in family 8000 Support the changes below: - Fields and sections structure were changed. - the NVM file built from DWord instead of Words. - sections header format was changed. Signed-off-by: Eran Harary Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-drv.c | 6 + drivers/net/wireless/iwlwifi/iwl-drv.h | 14 ++ .../net/wireless/iwlwifi/iwl-eeprom-parse.h | 5 +- drivers/net/wireless/iwlwifi/iwl-fw.h | 8 +- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 237 ++++++++++++++---- drivers/net/wireless/iwlwifi/iwl-nvm-parse.h | 3 +- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 4 +- drivers/net/wireless/iwlwifi/mvm/nvm.c | 63 +++-- 8 files changed, 270 insertions(+), 70 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index b3bc30b4292b..662d9936485c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -728,6 +728,12 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, if (tlv_len != sizeof(u32)) goto invalid_tlv_len; drv->fw.phy_config = le32_to_cpup((__le32 *)tlv_data); + drv->fw.valid_tx_ant = (drv->fw.phy_config & + FW_PHY_CFG_TX_CHAIN) >> + FW_PHY_CFG_TX_CHAIN_POS; + drv->fw.valid_rx_ant = (drv->fw.phy_config & + FW_PHY_CFG_RX_CHAIN) >> + FW_PHY_CFG_RX_CHAIN_POS; break; case IWL_UCODE_TLV_SECURE_SEC_RT: iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR, diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h index 592c01e11013..3c72cb710b0c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/iwlwifi/iwl-drv.h @@ -70,6 +70,20 @@ #define DRV_COPYRIGHT "Copyright(c) 2003- 2014 Intel Corporation" #define DRV_AUTHOR "" +/* radio config bits (actual values from NVM definition) */ +#define NVM_RF_CFG_DASH_MSK(x) (x & 0x3) /* bits 0-1 */ +#define NVM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */ +#define NVM_RF_CFG_TYPE_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */ +#define NVM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */ +#define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ +#define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ + +#define NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(x) (x & 0xF) +#define NVM_RF_CFG_DASH_MSK_FAMILY_8000(x) ((x >> 4) & 0xF) +#define NVM_RF_CFG_STEP_MSK_FAMILY_8000(x) ((x >> 8) & 0xF) +#define NVM_RF_CFG_TYPE_MSK_FAMILY_8000(x) ((x >> 12) & 0xFFF) +#define NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(x) ((x >> 24) & 0xF) +#define NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(x) ((x >> 28) & 0xF) /** * DOC: Driver system flows - drv component diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h index e3c7deafabe6..f0548b8a64b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h @@ -81,16 +81,17 @@ struct iwl_nvm_data { bool sku_cap_band_24GHz_enable; bool sku_cap_band_52GHz_enable; bool sku_cap_11n_enable; + bool sku_cap_11ac_enable; bool sku_cap_amt_enable; bool sku_cap_ipan_enable; - u8 radio_cfg_type; + u16 radio_cfg_type; u8 radio_cfg_step; u8 radio_cfg_dash; u8 radio_cfg_pnum; u8 valid_tx_ant, valid_rx_ant; - u16 nvm_version; + u32 nvm_version; s8 max_tx_pwr_half_dbm; struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index b0d09987540d..73671072d0f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -288,6 +288,8 @@ struct iwl_fw { struct iwl_tlv_calib_ctrl default_calib[IWL_UCODE_TYPE_MAX]; u32 phy_config; + u8 valid_tx_ant; + u8 valid_rx_ant; bool mvm_fw; @@ -296,14 +298,12 @@ struct iwl_fw { static inline u8 iwl_fw_valid_tx_ant(const struct iwl_fw *fw) { - return (fw->phy_config & FW_PHY_CFG_TX_CHAIN) >> - FW_PHY_CFG_TX_CHAIN_POS; + return fw->valid_tx_ant; } static inline u8 iwl_fw_valid_rx_ant(const struct iwl_fw *fw) { - return (fw->phy_config & FW_PHY_CFG_RX_CHAIN) >> - FW_PHY_CFG_RX_CHAIN_POS; + return fw->valid_rx_ant; } #endif /* __iwl_fw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 42780971aa04..df3ea60c87d9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -71,7 +71,7 @@ enum wkp_nvm_offsets { /* NVM HW-Section offset (in words) definitions */ HW_ADDR = 0x15, -/* NVM SW-Section offset (in words) definitions */ + /* NVM SW-Section offset (in words) definitions */ NVM_SW_SECTION = 0x1C0, NVM_VERSION = 0, RADIO_CFG = 1, @@ -79,11 +79,32 @@ enum wkp_nvm_offsets { N_HW_ADDRS = 3, NVM_CHANNELS = 0x1E0 - NVM_SW_SECTION, -/* NVM calibration section offset (in words) definitions */ + /* NVM calibration section offset (in words) definitions */ NVM_CALIB_SECTION = 0x2B8, XTAL_CALIB = 0x316 - NVM_CALIB_SECTION }; +enum family_8000_nvm_offsets { + /* NVM HW-Section offset (in words) definitions */ + HW_ADDR0_FAMILY_8000 = 0x12, + HW_ADDR1_FAMILY_8000 = 0x16, + MAC_ADDRESS_OVERRIDE_FAMILY_8000 = 1, + + /* NVM SW-Section offset (in words) definitions */ + NVM_SW_SECTION_FAMILY_8000 = 0x1C0, + NVM_VERSION_FAMILY_8000 = 0, + RADIO_CFG_FAMILY_8000 = 2, + SKU_FAMILY_8000 = 4, + N_HW_ADDRS_FAMILY_8000 = 5, + + /* NVM REGULATORY -Section offset (in words) definitions */ + NVM_CHANNELS_FAMILY_8000 = 0, + + /* NVM calibration section offset (in words) definitions */ + NVM_CALIB_SECTION_FAMILY_8000 = 0x2B8, + XTAL_CALIB_FAMILY_8000 = 0x316 - NVM_CALIB_SECTION_FAMILY_8000 +}; + /* SKU Capabilities (actual values from NVM definition) */ enum nvm_sku_bits { NVM_SKU_CAP_BAND_24GHZ = BIT(0), @@ -92,14 +113,6 @@ enum nvm_sku_bits { NVM_SKU_CAP_11AC_ENABLE = BIT(3), }; -/* radio config bits (actual values from NVM definition) */ -#define NVM_RF_CFG_DASH_MSK(x) (x & 0x3) /* bits 0-1 */ -#define NVM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */ -#define NVM_RF_CFG_TYPE_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */ -#define NVM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */ -#define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ -#define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ - /* * These are the channel numbers in the order that they are stored in the NVM */ @@ -112,7 +125,17 @@ static const u8 iwl_nvm_channels[] = { 149, 153, 157, 161, 165 }; +static const u8 iwl_nvm_channels_family_8000[] = { + /* 2.4 GHz */ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + /* 5 GHz */ + 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, + 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, + 149, 153, 157, 161, 165, 169, 173, 177, 181 +}; + #define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels) +#define IWL_NUM_CHANNELS_FAMILY_8000 ARRAY_SIZE(iwl_nvm_channels_family_8000) #define NUM_2GHZ_CHANNELS 14 #define FIRST_2GHZ_HT_MINUS 5 #define LAST_2GHZ_HT_PLUS 9 @@ -179,13 +202,23 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, struct ieee80211_channel *channel; u16 ch_flags; bool is_5ghz; + int num_of_ch; + const u8 *nvm_chan; - for (ch_idx = 0; ch_idx < IWL_NUM_CHANNELS; ch_idx++) { + if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { + num_of_ch = IWL_NUM_CHANNELS; + nvm_chan = &iwl_nvm_channels[0]; + } else { + num_of_ch = IWL_NUM_CHANNELS_FAMILY_8000; + nvm_chan = &iwl_nvm_channels_family_8000[0]; + } + + for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx); if (!(ch_flags & NVM_CHANNEL_VALID)) { IWL_DEBUG_EEPROM(dev, "Ch. %d Flags %x [%sGHz] - No traffic\n", - iwl_nvm_channels[ch_idx], + nvm_chan[ch_idx], ch_flags, (ch_idx >= NUM_2GHZ_CHANNELS) ? "5.2" : "2.4"); @@ -195,7 +228,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, channel = &data->channels[n_channels]; n_channels++; - channel->hw_value = iwl_nvm_channels[ch_idx]; + channel->hw_value = nvm_chan[ch_idx]; channel->band = (ch_idx < NUM_2GHZ_CHANNELS) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; channel->center_freq = @@ -206,11 +239,11 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, channel->flags = IEEE80211_CHAN_NO_HT40; if (ch_idx < NUM_2GHZ_CHANNELS && (ch_flags & NVM_CHANNEL_40MHZ)) { - if (iwl_nvm_channels[ch_idx] <= LAST_2GHZ_HT_PLUS) + if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS) channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; - if (iwl_nvm_channels[ch_idx] >= FIRST_2GHZ_HT_MINUS) + if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS) channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; - } else if (iwl_nvm_channels[ch_idx] <= LAST_5GHZ_HT && + } else if (nvm_chan[ch_idx] <= LAST_5GHZ_HT && (ch_flags & NVM_CHANNEL_40MHZ)) { if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0) channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; @@ -302,14 +335,23 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, } static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, - struct iwl_nvm_data *data, const __le16 *nvm_sw, - bool enable_vht, u8 tx_chains, u8 rx_chains) + struct iwl_nvm_data *data, + const __le16 *ch_section, bool enable_vht, + u8 tx_chains, u8 rx_chains) { - int n_channels = iwl_init_channel_map(dev, cfg, data, - &nvm_sw[NVM_CHANNELS]); + int n_channels; int n_used = 0; struct ieee80211_supported_band *sband; + if (cfg->device_family != IWL_DEVICE_FAMILY_8000) + n_channels = iwl_init_channel_map( + dev, cfg, data, + &ch_section[NVM_CHANNELS]); + else + n_channels = iwl_init_channel_map( + dev, cfg, data, + &ch_section[NVM_CHANNELS_FAMILY_8000]); + sband = &data->bands[IEEE80211_BAND_2GHZ]; sband->band = IEEE80211_BAND_2GHZ; sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS]; @@ -335,35 +377,122 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, n_used, n_channels); } +static int iwl_get_sku(const struct iwl_cfg *cfg, + const __le16 *nvm_sw) +{ + if (cfg->device_family != IWL_DEVICE_FAMILY_8000) + return le16_to_cpup(nvm_sw + SKU); + else + return le32_to_cpup((__le32 *)(nvm_sw + SKU_FAMILY_8000)); +} + +static int iwl_get_nvm_version(const struct iwl_cfg *cfg, + const __le16 *nvm_sw) +{ + if (cfg->device_family != IWL_DEVICE_FAMILY_8000) + return le16_to_cpup(nvm_sw + NVM_VERSION); + else + return le32_to_cpup((__le32 *)(nvm_sw + + NVM_VERSION_FAMILY_8000)); +} + +static int iwl_get_radio_cfg(const struct iwl_cfg *cfg, + const __le16 *nvm_sw) +{ + if (cfg->device_family != IWL_DEVICE_FAMILY_8000) + return le16_to_cpup(nvm_sw + RADIO_CFG); + else + return le32_to_cpup((__le32 *)(nvm_sw + RADIO_CFG_FAMILY_8000)); +} + +#define N_HW_ADDRS_MASK_FAMILY_8000 0xF +static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg, + const __le16 *nvm_sw) +{ + if (cfg->device_family != IWL_DEVICE_FAMILY_8000) + return le16_to_cpup(nvm_sw + N_HW_ADDRS); + else + return le32_to_cpup((__le32 *)(nvm_sw + N_HW_ADDRS_FAMILY_8000)) + & N_HW_ADDRS_MASK_FAMILY_8000; +} + +static void iwl_set_radio_cfg(const struct iwl_cfg *cfg, + struct iwl_nvm_data *data, + u32 radio_cfg) +{ + if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { + data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg); + data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg); + data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg); + data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg); + data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK(radio_cfg); + data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK(radio_cfg); + return; + } + + /* set the radio configuration for family 8000 */ + data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK_FAMILY_8000(radio_cfg); + data->radio_cfg_step = NVM_RF_CFG_STEP_MSK_FAMILY_8000(radio_cfg); + data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK_FAMILY_8000(radio_cfg); + data->radio_cfg_pnum = NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(radio_cfg); + data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(radio_cfg); + data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(radio_cfg); +} + +static void iwl_set_hw_address(const struct iwl_cfg *cfg, + struct iwl_nvm_data *data, + const __le16 *nvm_sec) +{ + u8 hw_addr[ETH_ALEN]; + + if (cfg->device_family != IWL_DEVICE_FAMILY_8000) + memcpy(hw_addr, nvm_sec + HW_ADDR, ETH_ALEN); + else + memcpy(hw_addr, nvm_sec + MAC_ADDRESS_OVERRIDE_FAMILY_8000, + ETH_ALEN); + + /* The byte order is little endian 16 bit, meaning 214365 */ + data->hw_addr[0] = hw_addr[1]; + data->hw_addr[1] = hw_addr[0]; + data->hw_addr[2] = hw_addr[3]; + data->hw_addr[3] = hw_addr[2]; + data->hw_addr[4] = hw_addr[5]; + data->hw_addr[5] = hw_addr[4]; +} + struct iwl_nvm_data * iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, const __le16 *nvm_hw, const __le16 *nvm_sw, - const __le16 *nvm_calib, u8 tx_chains, u8 rx_chains) + const __le16 *nvm_calib, const __le16 *regulatory, + const __le16 *mac_override, u8 tx_chains, u8 rx_chains) { struct iwl_nvm_data *data; - u8 hw_addr[ETH_ALEN]; - u16 radio_cfg, sku; + u32 sku; + u32 radio_cfg; - data = kzalloc(sizeof(*data) + - sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS, - GFP_KERNEL); + if (cfg->device_family != IWL_DEVICE_FAMILY_8000) + data = kzalloc(sizeof(*data) + + sizeof(struct ieee80211_channel) * + IWL_NUM_CHANNELS, + GFP_KERNEL); + else + data = kzalloc(sizeof(*data) + + sizeof(struct ieee80211_channel) * + IWL_NUM_CHANNELS_FAMILY_8000, + GFP_KERNEL); if (!data) return NULL; - data->nvm_version = le16_to_cpup(nvm_sw + NVM_VERSION); + data->nvm_version = iwl_get_nvm_version(cfg, nvm_sw); - radio_cfg = le16_to_cpup(nvm_sw + RADIO_CFG); - data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg); - data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg); - data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg); - data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg); - data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK(radio_cfg); - data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK(radio_cfg); + radio_cfg = iwl_get_radio_cfg(cfg, nvm_sw); + iwl_set_radio_cfg(cfg, data, radio_cfg); - sku = le16_to_cpup(nvm_sw + SKU); + sku = iwl_get_sku(cfg, nvm_sw); data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ; data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ; data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE; + data->sku_cap_11ac_enable = sku & NVM_SKU_CAP_11AC_ENABLE; if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) data->sku_cap_11n_enable = false; @@ -380,22 +509,34 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, return NULL; } - data->n_hw_addrs = le16_to_cpup(nvm_sw + N_HW_ADDRS); + data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw); - data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB); - data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1); + if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { + /* Checking for required sections */ + if (!nvm_calib) { + IWL_ERR_DEV(dev, + "Can't parse empty Calib NVM sections\n"); + return NULL; + } + /* in family 8000 Xtal calibration values moved to OTP */ + data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB); + data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1); + } - /* The byte order is little endian 16 bit, meaning 214365 */ - memcpy(hw_addr, nvm_hw + HW_ADDR, ETH_ALEN); - data->hw_addr[0] = hw_addr[1]; - data->hw_addr[1] = hw_addr[0]; - data->hw_addr[2] = hw_addr[3]; - data->hw_addr[3] = hw_addr[2]; - data->hw_addr[4] = hw_addr[5]; - data->hw_addr[5] = hw_addr[4]; + if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { + iwl_set_hw_address(cfg, data, nvm_hw); - iwl_init_sbands(dev, cfg, data, nvm_sw, sku & NVM_SKU_CAP_11AC_ENABLE, - tx_chains, rx_chains); + iwl_init_sbands(dev, cfg, data, nvm_sw, + sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains, + rx_chains); + } else { + /* MAC address in family 8000 */ + iwl_set_hw_address(cfg, data, mac_override); + + iwl_init_sbands(dev, cfg, data, regulatory, + sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains, + rx_chains); + } data->calib_version = 255; diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h index 0c4399aba8c6..c9c45a39d212 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h @@ -75,6 +75,7 @@ struct iwl_nvm_data * iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, const __le16 *nvm_hw, const __le16 *nvm_sw, - const __le16 *nvm_calib, u8 tx_chains, u8 rx_chains); + const __le16 *nvm_calib, const __le16 *regulatory, + const __le16 *mac_override, u8 tx_chains, u8 rx_chains); #endif /* __iwl_nvm_parse_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index a7c88f1402e9..4d808a91ea7f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -306,7 +306,6 @@ struct iwl_phy_cfg_cmd { #define PHY_CFG_RX_CHAIN_B BIT(13) #define PHY_CFG_RX_CHAIN_C BIT(14) -#define NVM_MAX_NUM_SECTIONS 11 /* Target of the NVM_ACCESS_CMD */ enum { @@ -318,8 +317,11 @@ enum { /* Section types for NVM_ACCESS_CMD */ enum { NVM_SECTION_TYPE_SW = 1, + NVM_SECTION_TYPE_REGULATORY = 3, NVM_SECTION_TYPE_CALIBRATION = 4, NVM_SECTION_TYPE_PRODUCTION = 5, + NVM_SECTION_TYPE_MAC_OVERRIDE = 11, + NVM_MAX_NUM_SECTIONS = 12, }; /** diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 2d5251b3600c..e80e81a3f828 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -228,13 +228,23 @@ static struct iwl_nvm_data * iwl_parse_nvm_sections(struct iwl_mvm *mvm) { struct iwl_nvm_section *sections = mvm->nvm_sections; - const __le16 *hw, *sw, *calib; + const __le16 *hw, *sw, *calib, *regulatory, *mac_override; /* Checking for required sections */ - if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || - !mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) { - IWL_ERR(mvm, "Can't parse empty NVM sections\n"); - return NULL; + if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { + if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || + !mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) { + IWL_ERR(mvm, "Can't parse empty NVM sections\n"); + return NULL; + } + } else { + if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || + !mvm->nvm_sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data || + !mvm->nvm_sections[NVM_SECTION_TYPE_REGULATORY].data) { + IWL_ERR(mvm, + "Can't parse empty family 8000 NVM sections\n"); + return NULL; + } } if (WARN_ON(!mvm->cfg)) @@ -243,7 +253,12 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data; sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data; calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data; + regulatory = (const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY].data; + mac_override = + (const __le16 *)sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data; + return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib, + regulatory, mac_override, iwl_fw_valid_tx_ant(mvm->fw), iwl_fw_valid_rx_ant(mvm->fw)); } @@ -285,6 +300,8 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) #define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) #define NVM_WORD2_ID(x) (x >> 12) +#define NVM_WORD2_LEN_FAMILY_8000(x) (2 * ((x & 0xFF) << 8 | x >> 8)) +#define NVM_WORD1_ID_FAMILY_8000(x) (x >> 4) IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n"); @@ -335,8 +352,16 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) break; } - section_size = 2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1)); - section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2)); + if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { + section_size = + 2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1)); + section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2)); + } else { + section_size = 2 * NVM_WORD2_LEN_FAMILY_8000( + le16_to_cpu(file_sec->word2)); + section_id = NVM_WORD1_ID_FAMILY_8000( + le16_to_cpu(file_sec->word1)); + } if (section_size > IWL_MAX_NVM_SECTION_SIZE) { IWL_ERR(mvm, "ERROR - section too large (%d)\n", @@ -406,6 +431,8 @@ int iwl_nvm_init(struct iwl_mvm *mvm) { int ret, i, section; u8 *nvm_buffer, *temp; + int nvm_to_read[NVM_MAX_NUM_SECTIONS]; + int num_of_sections_to_read; if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS)) return -EINVAL; @@ -418,12 +445,20 @@ int iwl_nvm_init(struct iwl_mvm *mvm) return ret; } else { /* list of NVM sections we are allowed/need to read */ - int nvm_to_read[] = { - mvm->cfg->nvm_hw_section_num, - NVM_SECTION_TYPE_SW, - NVM_SECTION_TYPE_CALIBRATION, - NVM_SECTION_TYPE_PRODUCTION, - }; + if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { + nvm_to_read[0] = mvm->cfg->nvm_hw_section_num; + nvm_to_read[1] = NVM_SECTION_TYPE_SW; + nvm_to_read[2] = NVM_SECTION_TYPE_CALIBRATION; + nvm_to_read[3] = NVM_SECTION_TYPE_PRODUCTION; + num_of_sections_to_read = 4; + } else { + nvm_to_read[0] = NVM_SECTION_TYPE_SW; + nvm_to_read[1] = NVM_SECTION_TYPE_CALIBRATION; + nvm_to_read[2] = NVM_SECTION_TYPE_PRODUCTION; + nvm_to_read[3] = NVM_SECTION_TYPE_REGULATORY; + nvm_to_read[4] = NVM_SECTION_TYPE_MAC_OVERRIDE; + num_of_sections_to_read = 5; + } /* Read From FW NVM */ IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n"); @@ -433,7 +468,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm) GFP_KERNEL); if (!nvm_buffer) return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) { + for (i = 0; i < num_of_sections_to_read; i++) { section = nvm_to_read[i]; /* we override the constness for initial read */ ret = iwl_nvm_read_section(mvm, section, nvm_buffer); From 4ed735e7599e60add8b04669a3ff6af69a31f769 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 12 Feb 2014 21:47:44 +0100 Subject: [PATCH 095/414] iwlwifi: remove iwl_fw_valid_(tx|rx)_ant inlines These inlines are pretty pointless now as they just return a fixed struct value, remove them - the code even gets shorter. Signed-off-by: Johannes Berg Reviewed-by: Eran Harary Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw.h | 10 ---------- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 2 +- drivers/net/wireless/iwlwifi/mvm/fw.c | 6 +++--- drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 2 +- drivers/net/wireless/iwlwifi/mvm/nvm.c | 4 ++-- drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c | 4 ++-- drivers/net/wireless/iwlwifi/mvm/rs.c | 18 +++++++++--------- drivers/net/wireless/iwlwifi/mvm/scan.c | 4 ++-- drivers/net/wireless/iwlwifi/mvm/tx.c | 2 +- drivers/net/wireless/iwlwifi/mvm/utils.c | 2 +- 10 files changed, 22 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 73671072d0f6..af6b4528d499 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -296,14 +296,4 @@ struct iwl_fw { struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; }; -static inline u8 iwl_fw_valid_tx_ant(const struct iwl_fw *fw) -{ - return fw->valid_tx_ant; -} - -static inline u8 iwl_fw_valid_rx_ant(const struct iwl_fw *fw) -{ - return fw->valid_rx_ant; -} - #endif /* __iwl_fw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 9b9833720a24..3278b4890823 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -591,7 +591,7 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, return -EINVAL; if (scan_rx_ant > ANT_ABC) return -EINVAL; - if (scan_rx_ant & ~iwl_fw_valid_rx_ant(mvm->fw)) + if (scan_rx_ant & ~mvm->fw->valid_rx_ant) return -EINVAL; mvm->scan_rx_ant = scan_rx_ant; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index bae75b308fc0..4f398e63f44a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -320,7 +320,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) } /* Send TX valid antennas before triggering calibrations */ - ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw)); + ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); if (ret) goto error; @@ -422,7 +422,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (ret) IWL_ERR(mvm, "Failed to initialize Smart Fifo\n"); - ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw)); + ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); if (ret) goto error; @@ -507,7 +507,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm) goto error; } - ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw)); + ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); if (ret) goto error; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 5c21aabb40cb..9ccec10bba16 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -952,7 +952,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, TX_CMD_FLG_TSF); mvm->mgmt_last_antenna_idx = - iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw), + iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant, mvm->mgmt_last_antenna_idx); beacon_cmd.tx.rate_n_flags = diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index e80e81a3f828..cf2d09f53782 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -259,8 +259,8 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib, regulatory, mac_override, - iwl_fw_valid_tx_ant(mvm->fw), - iwl_fw_valid_rx_ant(mvm->fw)); + mvm->fw->valid_tx_ant, + mvm->fw->valid_rx_ant); } #define MAX_NVM_FILE_LEN 16384 diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c index b7268c0b3333..237efe0ac1c4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c @@ -156,13 +156,13 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, idle_cnt = chains_static; active_cnt = chains_dynamic; - cmd->rxchain_info = cpu_to_le32(iwl_fw_valid_rx_ant(mvm->fw) << + cmd->rxchain_info = cpu_to_le32(mvm->fw->valid_rx_ant << PHY_RX_CHAIN_VALID_POS); cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS); cmd->rxchain_info |= cpu_to_le32(active_cnt << PHY_RX_CHAIN_MIMO_CNT_POS); - cmd->txchain_info = cpu_to_le32(iwl_fw_valid_tx_ant(mvm->fw)); + cmd->txchain_info = cpu_to_le32(mvm->fw->valid_tx_ant); } /* diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index a6d0ab129c6b..77c6e36c71cd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -166,7 +166,7 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (sta->smps_mode == IEEE80211_SMPS_STATIC) return false; - if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 2) + if (num_of_ant(mvm->fw->valid_tx_ant) < 2) return false; if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) @@ -917,7 +917,7 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta, if (num_of_ant(rate->ant) > 1) - rate->ant = first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); + rate->ant = first_antenna(mvm->fw->valid_tx_ant); /* Relevant in both switching to SISO or Legacy */ rate->sgi = false; @@ -1477,7 +1477,7 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm, const struct rs_tx_column *curr_col = &rs_tx_columns[tbl->column]; const struct rs_tx_column *next_col; allow_column_func_t allow_func; - u8 valid_ants = iwl_fw_valid_tx_ant(mvm->fw); + u8 valid_ants = mvm->fw->valid_tx_ant; const u16 *expected_tpt_tbl; s32 tpt, max_expected_tpt; @@ -2089,7 +2089,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, i = lq_sta->last_txrate_idx; - valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); + valid_tx_ant = mvm->fw->valid_tx_ant; if (!lq_sta->search_better_tbl) active_tbl = lq_sta->active_tbl; @@ -2319,7 +2319,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, /* These values will be overridden later */ lq_sta->lq.single_stream_ant_msk = - first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); + first_antenna(mvm->fw->valid_tx_ant); lq_sta->lq.dual_stream_ant_msk = ANT_AB; /* as default allow aggregation for all tids */ @@ -2445,7 +2445,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, memcpy(&rate, initial_rate, sizeof(rate)); - valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); + valid_tx_ant = mvm->fw->valid_tx_ant; if (is_siso(&rate)) { num_rates = RS_INITIAL_SISO_NUM_RATES; @@ -2676,9 +2676,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, desc += sprintf(buff+desc, "fixed rate 0x%X\n", lq_sta->dbg_fixed_rate); desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n", - (iwl_fw_valid_tx_ant(mvm->fw) & ANT_A) ? "ANT_A," : "", - (iwl_fw_valid_tx_ant(mvm->fw) & ANT_B) ? "ANT_B," : "", - (iwl_fw_valid_tx_ant(mvm->fw) & ANT_C) ? "ANT_C" : ""); + (mvm->fw->valid_tx_ant & ANT_A) ? "ANT_A," : "", + (mvm->fw->valid_tx_ant & ANT_B) ? "ANT_B," : "", + (mvm->fw->valid_tx_ant & ANT_C) ? "ANT_C" : ""); desc += sprintf(buff+desc, "lq type %s\n", (is_legacy(rate)) ? "legacy" : is_vht(rate) ? "VHT" : "HT"); diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index bf4e773c6f46..cea935b9afa6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -82,7 +82,7 @@ static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) if (mvm->scan_rx_ant != ANT_NONE) rx_ant = mvm->scan_rx_ant; else - rx_ant = iwl_fw_valid_rx_ant(mvm->fw); + rx_ant = mvm->fw->valid_rx_ant; rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS; rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS; rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_SEL_POS; @@ -124,7 +124,7 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band, u32 tx_ant; mvm->scan_last_antenna_idx = - iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw), + iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant, mvm->scan_last_antenna_idx); tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS; diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 852d9d87a14c..b83ef6ad1242 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -207,7 +207,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx); mvm->mgmt_last_antenna_idx = - iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw), + iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant, mvm->mgmt_last_antenna_idx); rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 2021b57189bc..c81a7fb6276c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -587,7 +587,7 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, lockdep_assert_held(&mvm->mutex); /* SMPS is irrelevant for NICs that don't have at least 2 RX antenna */ - if (num_of_ant(iwl_fw_valid_rx_ant(mvm->fw)) == 1) + if (num_of_ant(mvm->fw->valid_rx_ant) == 1) return; if (vif->type == NL80211_IFTYPE_AP) From ffa702647c0ed534be042542d492f4ed94d178f8 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 11 Feb 2014 16:37:34 +0200 Subject: [PATCH 096/414] iwlwifi: mvm: don't dump log of second CPU when not relevant The new API for ALIVE notification was misunderstood. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 4f398e63f44a..979b35bae056 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -130,7 +130,6 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, } else { palive2 = (void *)pkt->data; - mvm->support_umac_log = true; mvm->error_event_table = le32_to_cpu(palive2->error_event_table_ptr); mvm->log_event_table = @@ -141,6 +140,9 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, alive_data->valid = le16_to_cpu(palive2->status) == IWL_ALIVE_STATUS_OK; + if (mvm->umac_error_event_table) + mvm->support_umac_log = true; + IWL_DEBUG_FW(mvm, "Alive VER2 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n", le16_to_cpu(palive2->status), palive2->ver_type, From d85dad75566674ca8012715ac00a84ced3697972 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 13 Feb 2014 13:27:42 +0100 Subject: [PATCH 097/414] mac80211: remove erroneous comment about RX radiotap header There's no way the driver can pre-build the radiotap header, so remove the comment stating that it can. Reported-by: Jouni Malinen Signed-off-by: Johannes Berg --- include/net/mac80211.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 2d4d31212eed..a6bcc39e146e 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -66,10 +66,6 @@ * * Secondly, when the hardware handles fragmentation, the frame handed to * the driver from mac80211 is the MSDU, not the MPDU. - * - * Finally, for received frames, the driver is able to indicate that it has - * filled a radiotap header and put that in front of the frame; if it does - * not do so then mac80211 may add this under certain circumstances. */ /** From 2c34752ad965d8628db050a1f66ac774f692edcd Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 5 Feb 2014 13:58:32 -0800 Subject: [PATCH 098/414] ath10k: print out size of wmi-ready-event message Show message length and expected length. Helps debug firmware mismatch issues. Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 7298c0677b0b..b3c5a1faad43 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2071,11 +2071,11 @@ static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb) memcpy(ar->mac_addr, ev->mac_addr.addr, ETH_ALEN); ath10k_dbg(ATH10K_DBG_WMI, - "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d\n", + "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d skb->len %i ev-sz %zu\n", __le32_to_cpu(ev->sw_version), __le32_to_cpu(ev->abi_version), ev->mac_addr.addr, - __le32_to_cpu(ev->status)); + __le32_to_cpu(ev->status), skb->len, sizeof(*ev)); complete(&ar->wmi.unified_ready); return 0; From c6b56b03a7e8b1148e52b1175fde16a1ecc8ac4a Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 5 Feb 2014 13:58:33 -0800 Subject: [PATCH 099/414] ath10k: add more debugging for receive errors Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 11 +++++++++++ drivers/net/wireless/ath/ath10k/txrx.c | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index fe8bd1b59f0e..6a548a25bda6 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -937,6 +937,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, } if (ath10k_htt_rx_has_decrypt_err(msdu_head)) { + ath10k_dbg(ATH10K_DBG_HTT, + "htt rx dropping due to decrypt-err\n"); ath10k_htt_rx_free_msdu_chain(msdu_head); continue; } @@ -975,6 +977,15 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, info.skb = msdu_head; info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head); info.mic_err = ath10k_htt_rx_has_mic_err(msdu_head); + + if (info.fcs_err) + ath10k_dbg(ATH10K_DBG_HTT, + "htt rx has FCS err\n"); + + if (info.mic_err) + ath10k_dbg(ATH10K_DBG_HTT, + "htt rx has MIC err\n"); + info.signal = ATH10K_DEFAULT_NOISE_FLOOR; info.signal += rx->ppdu.combined_rssi; diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 74f45fa6f428..b11e478e2e8f 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -259,7 +259,7 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info) status->freq = ch->center_freq; ath10k_dbg(ATH10K_DBG_DATA, - "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u\n", + "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i\n", info->skb, info->skb->len, status->flag == 0 ? "legacy" : "", @@ -271,7 +271,7 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info) status->rate_idx, status->vht_nss, status->freq, - status->band); + status->band, status->flag, info->fcs_err); ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ", info->skb->data, info->skb->len); From 75fb2f94f2115a616c6066b55c35495482514608 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 5 Feb 2014 13:58:34 -0800 Subject: [PATCH 100/414] ath10k: better tx/rx debugging Make it easier to grep for htt rx errors. Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 17 ++++++++++------- drivers/net/wireless/ath/ath10k/htt_tx.c | 4 ++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 6a548a25bda6..5d073d9afbbf 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -324,7 +324,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, msdu->len + skb_tailroom(msdu), DMA_FROM_DEVICE); - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx: ", + ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ", msdu->data, msdu->len + skb_tailroom(msdu)); rx_desc = (struct htt_rx_desc *)msdu->data; @@ -417,8 +417,8 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, next->len + skb_tailroom(next), DMA_FROM_DEVICE); - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx: ", - next->data, + ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, + "htt rx chained: ", next->data, next->len + skb_tailroom(next)); skb_trim(next, 0); @@ -751,7 +751,7 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info) /* This shouldn't happen. If it does than it may be a FW bug. */ if (skb->next) { - ath10k_warn("received chained non A-MSDU frame\n"); + ath10k_warn("htt rx received chained non A-MSDU frame\n"); ath10k_htt_rx_free_msdu_chain(skb->next); skb->next = NULL; } @@ -947,6 +947,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, /* Skip mgmt frames while we handle this in WMI */ if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL) { + ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n"); ath10k_htt_rx_free_msdu_chain(msdu_head); continue; } @@ -962,6 +963,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, } if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) { + ath10k_dbg(ATH10K_DBG_HTT, + "htt rx CAC running\n"); ath10k_htt_rx_free_msdu_chain(msdu_head); continue; } @@ -969,7 +972,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, /* FIXME: we do not support chaining yet. * this needs investigation */ if (msdu_chaining) { - ath10k_warn("msdu_chaining is true\n"); + ath10k_warn("htt rx msdu_chaining is true\n"); ath10k_htt_rx_free_msdu_chain(msdu_head); continue; } @@ -1106,7 +1109,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, skb_trim(info.skb, info.skb->len - trim); - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt frag mpdu: ", + ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ", info.skb->data, info.skb->len); ath10k_process_rx(htt->ar, &info); @@ -1127,7 +1130,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) if (!IS_ALIGNED((unsigned long)skb->data, 4)) ath10k_warn("unaligned htt message, expect trouble\n"); - ath10k_dbg(ATH10K_DBG_HTT, "HTT RX, msg_type: 0x%0X\n", + ath10k_dbg(ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n", resp->hdr.msg_type); switch (resp->hdr.msg_type) { case HTT_T2H_MSG_TYPE_VERSION_CONF: { diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index f1d36d2d2723..acaa046dc93b 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -460,9 +460,9 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) DMA_TO_DEVICE); } - ath10k_dbg(ATH10K_DBG_HTT, "msdu 0x%llx\n", + ath10k_dbg(ATH10K_DBG_HTT, "tx-msdu 0x%llx\n", (unsigned long long) ATH10K_SKB_CB(msdu)->paddr); - ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "msdu: ", + ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "tx-msdu: ", msdu->data, msdu->len); skb_put(txdesc, desc_len); From 7c61385454b639a68e434496c1cae9ec4d98d99e Mon Sep 17 00:00:00 2001 From: Bartosz Markowski Date: Tue, 11 Feb 2014 08:37:06 +0100 Subject: [PATCH 101/414] ath10k: remove excessive rx msdu len check This throw a lot of pointless warnings in case of DFS (radar detection) and PHYERR events from firmware, when firmware may actually insert more data, than we assume. Besides of being noisy this debug does not protect or check anything usefull currently. It was introduced long time ago while debugging aggregations. So just removing it. Signed-off-by: Bartosz Markowski Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 5d073d9afbbf..820c8ba3b1ec 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -430,12 +430,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, msdu_chaining = 1; } - if (msdu_len > 0) { - /* This may suggest FW bug? */ - ath10k_warn("htt rx msdu len not consumed (%d)\n", - msdu_len); - } - last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) & RX_MSDU_END_INFO0_LAST_MSDU; From 36786024df993f0fb5e7d1b56058c4f48f24d5e8 Mon Sep 17 00:00:00 2001 From: Marek Kwaczynski Date: Mon, 10 Feb 2014 11:25:25 +0100 Subject: [PATCH 102/414] ath10k: Set proper nss value for the peer It was found during testing the nss calculation does not cover all corner cases. Station could request eq. only MCS8 and MCS9 (nss=2 specific). Next num_rates=2 so the driver sets nss=(max((2+7)/8, 1))=1. Which is wrong. The in-driver calculation was introduced prior (commit ddcc347b70 mac80211: fix rx_nss calculation for drivers with hw rc). Since it's fixed, use mac80211 provided value from now. End user will experience lower throuhputs than expected if the nss is wrongly calculated. Signed-off-by: Marek Kwaczynski Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 144b4d605267..e6bf2e8da770 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1149,7 +1149,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, arg->peer_ht_rates.rates[n++] = i; arg->peer_ht_rates.num_rates = n; - arg->peer_num_spatial_streams = max((n+7) / 8, 1); + arg->peer_num_spatial_streams = sta->rx_nss; ath10k_dbg(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n", arg->addr, From fc36e3ffcdd0ef214008d459bf8d8bff159ce16f Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 10 Feb 2014 17:14:22 +0100 Subject: [PATCH 103/414] ath10k: fix device initialization routine Hardware CUS232 version 2 has some issues with cold reset that lead to Data Bus Errors or system hangs in some cases. It's safer to use warm reset when possible as it shouldn't trigger the aforementioned issues. Prefer warm reset over cold reset. However since warm reset doesn't work after FW crash make sure to fallback to cold reset when booting up the HW. Signed-off-by: Michal Kazior Signed-off-by: Marek Puzyniak Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/hw.h | 6 ++ drivers/net/wireless/ath/ath10k/pci.c | 134 ++++++++++++++++++++++++-- 2 files changed, 133 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index f1505a25d810..35fc44e281f5 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -205,8 +205,11 @@ enum ath10k_mcast2ucast_mode { #define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x0006c000 #define PCIE_LOCAL_BASE_ADDRESS 0x00080000 +#define SOC_RESET_CONTROL_ADDRESS 0x00000000 #define SOC_RESET_CONTROL_OFFSET 0x00000000 #define SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001 +#define SOC_RESET_CONTROL_CE_RST_MASK 0x00040000 +#define SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040 #define SOC_CPU_CLOCK_OFFSET 0x00000020 #define SOC_CPU_CLOCK_STANDARD_LSB 0 #define SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 @@ -216,6 +219,8 @@ enum ath10k_mcast2ucast_mode { #define SOC_LPO_CAL_OFFSET 0x000000e0 #define SOC_LPO_CAL_ENABLE_LSB 20 #define SOC_LPO_CAL_ENABLE_MASK 0x00100000 +#define SOC_LF_TIMER_CONTROL0_ADDRESS 0x00000050 +#define SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0x00000004 #define SOC_CHIP_ID_ADDRESS 0x000000ec #define SOC_CHIP_ID_REV_LSB 8 @@ -273,6 +278,7 @@ enum ath10k_mcast2ucast_mode { #define PCIE_INTR_CAUSE_ADDRESS 0x000c #define PCIE_INTR_CLR_ADDRESS 0x0014 #define SCRATCH_3_ADDRESS 0x0030 +#define CPU_INTR_ADDRESS 0x0010 /* Firmware indications to the Host via SCRATCH_3 register. */ #define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 9179c88007d1..486412b9fec2 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -64,7 +64,8 @@ static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info, int num); static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info); static void ath10k_pci_stop_ce(struct ath10k *ar); -static int ath10k_pci_device_reset(struct ath10k *ar); +static int ath10k_pci_cold_reset(struct ath10k *ar); +static int ath10k_pci_warm_reset(struct ath10k *ar); static int ath10k_pci_wait_for_target_init(struct ath10k *ar); static int ath10k_pci_init_irq(struct ath10k *ar); static int ath10k_pci_deinit_irq(struct ath10k *ar); @@ -1500,7 +1501,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) * configuration during init. If ringbuffers are freed and the device * were to access them this could lead to memory corruption on the * host. */ - ath10k_pci_device_reset(ar); + ath10k_pci_warm_reset(ar); ar_pci->started = 0; } @@ -1991,7 +1992,94 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) ath10k_pci_sleep(ar); } -static int ath10k_pci_hif_power_up(struct ath10k *ar) +static int ath10k_pci_warm_reset(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + int ret = 0; + u32 val; + + ath10k_dbg(ATH10K_DBG_BOOT, "boot performing warm chip reset\n"); + + ret = ath10k_do_pci_wake(ar); + if (ret) { + ath10k_err("failed to wake up target: %d\n", ret); + return ret; + } + + /* debug */ + val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + PCIE_INTR_CAUSE_ADDRESS); + ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val); + + val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + CPU_INTR_ADDRESS); + ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n", + val); + + /* disable pending irqs */ + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + + PCIE_INTR_ENABLE_ADDRESS, 0); + + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + + PCIE_INTR_CLR_ADDRESS, ~0); + + msleep(100); + + /* clear fw indicator */ + ath10k_pci_write32(ar, ar_pci->fw_indicator_address, 0); + + /* clear target LF timer interrupts */ + val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + + SOC_LF_TIMER_CONTROL0_ADDRESS); + ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + + SOC_LF_TIMER_CONTROL0_ADDRESS, + val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK); + + /* reset CE */ + val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + + SOC_RESET_CONTROL_ADDRESS); + ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, + val | SOC_RESET_CONTROL_CE_RST_MASK); + val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + + SOC_RESET_CONTROL_ADDRESS); + msleep(10); + + /* unreset CE */ + ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, + val & ~SOC_RESET_CONTROL_CE_RST_MASK); + val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + + SOC_RESET_CONTROL_ADDRESS); + msleep(10); + + /* debug */ + val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + PCIE_INTR_CAUSE_ADDRESS); + ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val); + + val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + CPU_INTR_ADDRESS); + ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n", + val); + + /* CPU warm reset */ + val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + + SOC_RESET_CONTROL_ADDRESS); + ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, + val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK); + + val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + + SOC_RESET_CONTROL_ADDRESS); + ath10k_dbg(ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n", val); + + msleep(100); + + ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset complete\n"); + + ath10k_do_pci_sleep(ar); + return ret; +} + +static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); const char *irq_mode; @@ -2007,7 +2095,11 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) * is in an unexpected state. We try to catch that here in order to * reset the Target and retry the probe. */ - ret = ath10k_pci_device_reset(ar); + if (cold_reset) + ret = ath10k_pci_cold_reset(ar); + else + ret = ath10k_pci_warm_reset(ar); + if (ret) { ath10k_err("failed to reset target: %d\n", ret); goto err; @@ -2077,7 +2169,7 @@ err_deinit_irq: ath10k_pci_deinit_irq(ar); err_ce: ath10k_pci_ce_deinit(ar); - ath10k_pci_device_reset(ar); + ath10k_pci_warm_reset(ar); err_ps: if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) ath10k_do_pci_sleep(ar); @@ -2085,6 +2177,34 @@ err: return ret; } +static int ath10k_pci_hif_power_up(struct ath10k *ar) +{ + int ret; + + /* + * Hardware CUS232 version 2 has some issues with cold reset and the + * preferred (and safer) way to perform a device reset is through a + * warm reset. + * + * Warm reset doesn't always work though (notably after a firmware + * crash) so fall back to cold reset if necessary. + */ + ret = __ath10k_pci_hif_power_up(ar, false); + if (ret) { + ath10k_warn("failed to power up target using warm reset (%d), trying cold reset\n", + ret); + + ret = __ath10k_pci_hif_power_up(ar, true); + if (ret) { + ath10k_err("failed to power up target using cold reset too (%d)\n", + ret); + return ret; + } + } + + return 0; +} + static void ath10k_pci_hif_power_down(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -2092,7 +2212,7 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar) ath10k_pci_free_early_irq(ar); ath10k_pci_kill_tasklet(ar); ath10k_pci_deinit_irq(ar); - ath10k_pci_device_reset(ar); + ath10k_pci_warm_reset(ar); ath10k_pci_ce_deinit(ar); if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features)) @@ -2521,7 +2641,7 @@ out: return ret; } -static int ath10k_pci_device_reset(struct ath10k *ar) +static int ath10k_pci_cold_reset(struct ath10k *ar) { int i, ret; u32 val; From 9042e17df8340247ebed9c67f4b64228f16b4c36 Mon Sep 17 00:00:00 2001 From: Marek Puzyniak Date: Mon, 10 Feb 2014 17:14:23 +0100 Subject: [PATCH 104/414] ath10k: refactor suspend/resume functions Suspend/resume callbacks are not protected by configuration mutex so adding such protection. Also in order to simplify implemetation of suspend function wait queue is replaced by completion. Signed-off-by: Marek Puzyniak Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 6 ++-- drivers/net/wireless/ath/ath10k/core.h | 3 +- drivers/net/wireless/ath/ath10k/mac.c | 39 +++++++++++++++++--------- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 56048b1bbca5..0d161cf90608 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -55,8 +55,7 @@ static void ath10k_send_suspend_complete(struct ath10k *ar) { ath10k_dbg(ATH10K_DBG_BOOT, "boot suspend complete\n"); - ar->is_target_paused = true; - wake_up(&ar->event_queue); + complete(&ar->target_suspend); } static int ath10k_init_connect_htc(struct ath10k *ar) @@ -703,6 +702,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, init_completion(&ar->scan.started); init_completion(&ar->scan.completed); init_completion(&ar->scan.on_channel); + init_completion(&ar->target_suspend); init_completion(&ar->install_key_done); init_completion(&ar->vdev_setup_done); @@ -726,8 +726,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work); skb_queue_head_init(&ar->wmi_mgmt_tx_queue); - init_waitqueue_head(&ar->event_queue); - INIT_WORK(&ar->restart_work, ath10k_core_restart); return ar; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index c0b00e1f7562..4f7ff9bd7813 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -375,8 +375,7 @@ struct ath10k { const struct ath10k_hif_ops *ops; } hif; - wait_queue_head_t event_queue; - bool is_target_paused; + struct completion target_suspend; struct ath10k_bmi bmi; struct ath10k_wmi wmi; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index e6bf2e8da770..3d905932b5a2 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3440,21 +3440,20 @@ static int ath10k_suspend(struct ieee80211_hw *hw, struct ath10k *ar = hw->priv; int ret; - ar->is_target_paused = false; + mutex_lock(&ar->conf_mutex); + + reinit_completion(&ar->target_suspend); ret = ath10k_wmi_pdev_suspend_target(ar); if (ret) { ath10k_warn("could not suspend target (%d)\n", ret); - return 1; + ret = 1; + goto exit; } - ret = wait_event_interruptible_timeout(ar->event_queue, - ar->is_target_paused == true, - 1 * HZ); - if (ret < 0) { - ath10k_warn("suspend interrupted (%d)\n", ret); - goto resume; - } else if (ret == 0) { + ret = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ); + + if (ret == 0) { ath10k_warn("suspend timed out - target pause event never came\n"); goto resume; } @@ -3465,12 +3464,17 @@ static int ath10k_suspend(struct ieee80211_hw *hw, goto resume; } - return 0; + ret = 0; + goto exit; resume: ret = ath10k_wmi_pdev_resume_target(ar); if (ret) ath10k_warn("could not resume target (%d)\n", ret); - return 1; + + ret = 1; +exit: + mutex_unlock(&ar->conf_mutex); + return ret; } static int ath10k_resume(struct ieee80211_hw *hw) @@ -3478,19 +3482,26 @@ static int ath10k_resume(struct ieee80211_hw *hw) struct ath10k *ar = hw->priv; int ret; + mutex_lock(&ar->conf_mutex); + ret = ath10k_hif_resume(ar); if (ret) { ath10k_warn("could not resume hif (%d)\n", ret); - return 1; + ret = 1; + goto exit; } ret = ath10k_wmi_pdev_resume_target(ar); if (ret) { ath10k_warn("could not resume target (%d)\n", ret); - return 1; + ret = 1; + goto exit; } - return 0; + ret = 0; +exit: + mutex_unlock(&ar->conf_mutex); + return ret; } #endif From 00f5482bcd940c11b9b81e7c399fd5f4f6667bd0 Mon Sep 17 00:00:00 2001 From: Marek Puzyniak Date: Mon, 10 Feb 2014 17:14:24 +0100 Subject: [PATCH 105/414] ath10k: suspend hardware before reset In case of warm reset target need to be suspended. Suspend function is extented to handle both cases with disabling interrupts and without disabling interrupts. Warm target reset requires suspend with all interrupts disabled. This patch depends on ath10k: fix device initialization routine Signed-off-by: Marek Puzyniak Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 24 ++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/mac.c | 14 +++----------- drivers/net/wireless/ath/ath10k/wmi.c | 4 ++-- drivers/net/wireless/ath/ath10k/wmi.h | 2 +- 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 0d161cf90608..ebc5fc2ede75 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -858,10 +858,34 @@ err: } EXPORT_SYMBOL(ath10k_core_start); +int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt) +{ + int ret; + + reinit_completion(&ar->target_suspend); + + ret = ath10k_wmi_pdev_suspend_target(ar, suspend_opt); + if (ret) { + ath10k_warn("could not suspend target (%d)\n", ret); + return ret; + } + + ret = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ); + + if (ret == 0) { + ath10k_warn("suspend timed out - target pause event never came\n"); + return -ETIMEDOUT; + } + + return 0; +} + void ath10k_core_stop(struct ath10k *ar) { lockdep_assert_held(&ar->conf_mutex); + /* try to suspend target */ + ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR); ath10k_debug_stop(ar); ath10k_htc_stop(&ar->htc); ath10k_htt_detach(&ar->htt); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 4f7ff9bd7813..fae53f909550 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -492,6 +492,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, void ath10k_core_destroy(struct ath10k *ar); int ath10k_core_start(struct ath10k *ar); +int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt); void ath10k_core_stop(struct ath10k *ar); int ath10k_core_register(struct ath10k *ar, u32 chip_id); void ath10k_core_unregister(struct ath10k *ar); diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 3d905932b5a2..b2c65904449c 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3442,22 +3442,14 @@ static int ath10k_suspend(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); - reinit_completion(&ar->target_suspend); - - ret = ath10k_wmi_pdev_suspend_target(ar); + ret = ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND); if (ret) { - ath10k_warn("could not suspend target (%d)\n", ret); + if (ret == -ETIMEDOUT) + goto resume; ret = 1; goto exit; } - ret = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ); - - if (ret == 0) { - ath10k_warn("suspend timed out - target pause event never came\n"); - goto resume; - } - ret = ath10k_hif_suspend(ar); if (ret) { ath10k_warn("could not suspend hif (%d)\n", ret); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index b3c5a1faad43..91e501b5499e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2443,7 +2443,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar, ar->wmi.cmd->pdev_set_channel_cmdid); } -int ath10k_wmi_pdev_suspend_target(struct ath10k *ar) +int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt) { struct wmi_pdev_suspend_cmd *cmd; struct sk_buff *skb; @@ -2453,7 +2453,7 @@ int ath10k_wmi_pdev_suspend_target(struct ath10k *ar) return -ENOMEM; cmd = (struct wmi_pdev_suspend_cmd *)skb->data; - cmd->suspend_opt = WMI_PDEV_SUSPEND; + cmd->suspend_opt = __cpu_to_le32(suspend_opt); return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid); } diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 083079f3fdd4..fc1093a51ab1 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4193,7 +4193,7 @@ int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar); int ath10k_wmi_connect_htc_service(struct ath10k *ar); int ath10k_wmi_pdev_set_channel(struct ath10k *ar, const struct wmi_channel_arg *); -int ath10k_wmi_pdev_suspend_target(struct ath10k *ar); +int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt); int ath10k_wmi_pdev_resume_target(struct ath10k *ar); int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, u16 rd5g, u16 ctl2g, u16 ctl5g); From fd71f807376437756bfab0ee21d5978a7b05a0f5 Mon Sep 17 00:00:00 2001 From: Bartosz Markowski Date: Mon, 10 Feb 2014 13:12:55 +0100 Subject: [PATCH 106/414] ath10k: AP: handle HT station which does not have HT RX MCS This is a workaround for HT-enabled STAs which break the spec and have no HT capabilities RX mask (no HT RX MCS map). As per spec, in section 20.3.5 Modulation and coding scheme (MCS), MCS 0 through 7 are mandatory in 20MHz with 800 ns GI at all STAs. Firmware asserts if such situation occurs. Signed-off-by: Bartosz Markowski Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b2c65904449c..1c305b10e477 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1148,8 +1148,23 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, if (ht_cap->mcs.rx_mask[i/8] & (1 << i%8)) arg->peer_ht_rates.rates[n++] = i; - arg->peer_ht_rates.num_rates = n; - arg->peer_num_spatial_streams = sta->rx_nss; + /* + * This is a workaround for HT-enabled STAs which break the spec + * and have no HT capabilities RX mask (no HT RX MCS map). + * + * As per spec, in section 20.3.5 Modulation and coding scheme (MCS), + * MCS 0 through 7 are mandatory in 20MHz with 800 ns GI at all STAs. + * + * Firmware asserts if such situation occurs. + */ + if (n == 0) { + arg->peer_ht_rates.num_rates = 8; + for (i = 0; i < arg->peer_ht_rates.num_rates; i++) + arg->peer_ht_rates.rates[i] = i; + } else { + arg->peer_ht_rates.num_rates = n; + arg->peer_num_spatial_streams = sta->rx_nss; + } ath10k_dbg(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n", arg->addr, From 716ae53c56cf51a64a56aa94d60240b9dff4a112 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Thu, 13 Feb 2014 17:50:00 +0200 Subject: [PATCH 107/414] ath10k: pass frames with invalid peer status to upper layer Pass frames with invalid peer status to upper layer. Next mac80211 will validate frames and drop if required. This is required to detect spurious frames and pass this info to user mode (detect CLASS2 CLASS3 frames from nonauthenticated/nonassociated stations). Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 820c8ba3b1ec..4767c24bf819 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -948,6 +948,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, if (status != HTT_RX_IND_MPDU_STATUS_OK && status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR && + status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER && !htt->ar->monitor_enabled) { ath10k_dbg(ATH10K_DBG_HTT, "htt rx ignoring frame w/ status %d\n", From bdcb2c9e2f9e40639e4b212d08d8cdba54932c0d Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Thu, 13 Feb 2014 17:50:01 +0200 Subject: [PATCH 108/414] ath10k: Get rid of superfluous call to pci_disable_msi() The documentation states that pci_enable_msi_block() returns the number of requests 'could have been allocated', not 'could allocate'. IOW, MSIs are *not* enabled if a positive value returned. kvalo: add commit log based on Alexander's email Signed-off-by: Alexander Gordeev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 486412b9fec2..abcb7edb6485 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2532,8 +2532,6 @@ static int ath10k_pci_init_irq(struct ath10k *ar) ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs); if (ret == 0) return 0; - if (ret > 0) - pci_disable_msi(ar_pci->pdev); /* fall-through */ } From bb8b621ac34605b8e20b63021bed7d10f3dfa544 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Thu, 13 Feb 2014 17:50:01 +0200 Subject: [PATCH 109/414] ath10k: Disable MSI in case IRQ configuration is unknown In case IRQ configuration is unknown possibly enabled MSIs are left enabled in ath10k_pci_deinit_irq(). This update fixes the described misbehaviour. Signed-off-by: Alexander Gordeev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index abcb7edb6485..4c303144c05f 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2598,6 +2598,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar) case MSI_NUM_REQUEST: pci_disable_msi(ar_pci->pdev); return 0; + default: + pci_disable_msi(ar_pci->pdev); } ath10k_warn("unknown irq configuration upon deinit\n"); From 5ad6867cb5585cdf2cf7e70165eef93bf3820875 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Thu, 13 Feb 2014 17:50:02 +0200 Subject: [PATCH 110/414] ath10k: Use pci_enable_msi_range() As result deprecation of MSI-X/MSI enablement functions pci_enable_msix() and pci_enable_msi_block() all drivers using these two interfaces need to be updated to use the new pci_enable_msi_range() and pci_enable_msix_range() interfaces. Signed-off-by: Alexander Gordeev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 4c303144c05f..34f09106f423 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2529,8 +2529,9 @@ static int ath10k_pci_init_irq(struct ath10k *ar) /* Try MSI-X */ if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) { ar_pci->num_msi_intrs = MSI_NUM_REQUEST; - ret = pci_enable_msi_block(ar_pci->pdev, ar_pci->num_msi_intrs); - if (ret == 0) + ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs, + ar_pci->num_msi_intrs); + if (ret > 0) return 0; /* fall-through */ From 2e05f01bd1839ca1a3da66be8ed7aebd36fbde77 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 13 Feb 2014 18:13:12 +0200 Subject: [PATCH 111/414] ath10k: fix alignment in ath10k_dbg() Fix a checkpatch warning: drivers/net/wireless/ath/ath10k/debug.h:95: CHECK: Alignment should match open parenthesis Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 1773c36c71a0..a5824990bd2a 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -92,7 +92,7 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar, #ifdef CONFIG_ATH10K_DEBUG __printf(2, 3) void ath10k_dbg(enum ath10k_debug_mask mask, - const char *fmt, ...); + const char *fmt, ...); void ath10k_dbg_dump(enum ath10k_debug_mask mask, const char *msg, const char *prefix, const void *buf, size_t len); From ef8c00174a8738ea334197c0164143354644cb16 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 13 Feb 2014 18:13:12 +0200 Subject: [PATCH 112/414] ath: remove camel case from struct reg_dmn_pair_mapping Fixes a checkpatch warning in ath10k: drivers/net/wireless/ath/ath10k/mac.c:1636: WARNING: Avoid CamelCase: regDmnEnum> Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath.h | 2 +- drivers/net/wireless/ath/ath10k/mac.c | 6 +++--- drivers/net/wireless/ath/ath6kl/wmi.c | 4 ++-- drivers/net/wireless/ath/regd.c | 10 +++++----- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index b59cfbe0276b..2f4f25188cd1 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -63,7 +63,7 @@ enum ath_bus_type { }; struct reg_dmn_pair_mapping { - u16 regDmnEnum; + u16 reg_domain; u16 reg_5ghz_ctl; u16 reg_2ghz_ctl; }; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 1c305b10e477..5c5860ef36bd 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1648,9 +1648,9 @@ static void ath10k_regd_update(struct ath10k *ar) /* Target allows setting up per-band regdomain but ath_common provides * a combined one only */ ret = ath10k_wmi_pdev_set_regdomain(ar, - regpair->regDmnEnum, - regpair->regDmnEnum, /* 2ghz */ - regpair->regDmnEnum, /* 5ghz */ + regpair->reg_domain, + regpair->reg_domain, /* 2ghz */ + regpair->reg_domain, /* 5ghz */ regpair->reg_2ghz_ctl, regpair->reg_5ghz_ctl); if (ret) diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 4f16d79c9eb1..8b4ce28e3ce8 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -914,7 +914,7 @@ ath6kl_get_regpair(u16 regdmn) return NULL; for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { - if (regDomainPairs[i].regDmnEnum == regdmn) + if (regDomainPairs[i].reg_domain == regdmn) return ®DomainPairs[i]; } @@ -954,7 +954,7 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len) country = ath6kl_regd_find_country_by_rd((u16) reg_code); if (regpair) ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", - regpair->regDmnEnum); + regpair->reg_domain); else ath6kl_warn("Regpair not found reg_code 0x%0x\n", reg_code); diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index e5e905910db4..415393dfb6fc 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -222,7 +222,7 @@ static const struct ieee80211_regdomain *ath_default_world_regdomain(void) static const struct ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg) { - switch (reg->regpair->regDmnEnum) { + switch (reg->regpair->reg_domain) { case 0x60: case 0x61: case 0x62: @@ -431,7 +431,7 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy, enum nl80211_reg_initiator initiator, struct ath_regulatory *reg) { - switch (reg->regpair->regDmnEnum) { + switch (reg->regpair->reg_domain) { case 0x60: case 0x63: case 0x66: @@ -560,7 +560,7 @@ static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg) printk(KERN_DEBUG "ath: EEPROM indicates we " "should expect a direct regpair map\n"); for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) - if (regDomainPairs[i].regDmnEnum == rd) + if (regDomainPairs[i].reg_domain == rd) return true; } printk(KERN_DEBUG @@ -617,7 +617,7 @@ ath_get_regpair(int regdmn) if (regdmn == NO_ENUMRD) return NULL; for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { - if (regDomainPairs[i].regDmnEnum == regdmn) + if (regDomainPairs[i].reg_domain == regdmn) return ®DomainPairs[i]; } return NULL; @@ -741,7 +741,7 @@ static int __ath_regd_init(struct ath_regulatory *reg) printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n", reg->alpha2[0], reg->alpha2[1]); printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n", - reg->regpair->regDmnEnum); + reg->regpair->reg_domain); return 0; } From 75459e3338928bdbe9618b626a6471764e2e53f0 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 13 Feb 2014 18:13:12 +0200 Subject: [PATCH 113/414] ath10k: release conf_mutex if vdev_start() fails I modified Michal's commit c930f744bdb0 ("ath10k: implement channel switching") to return when vdev_start() fails, but forgot to release conf_mutex. Found by coccinelle: >> drivers/net/wireless/ath/ath10k/mac.c:2745:5-11: preceding lock on line 2663 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 5c5860ef36bd..44b550b2fcfd 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2785,7 +2785,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, if (ret) { ath10k_warn("failed to start vdev: %d\n", ret); - return; + goto exit; } arvif->is_started = true; @@ -2866,6 +2866,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ath10k_bss_assoc(hw, vif, info); } +exit: mutex_unlock(&ar->conf_mutex); } From 9b7655eafeeec9e74e97e9056e820ede8d18093e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 14 Feb 2014 07:40:51 +0200 Subject: [PATCH 114/414] Bluetooth: Enable LE L2CAP CoC support by default Now that the LE L2CAP Connection Oriented Channel support has undergone a decent amount of testing we can make it officially supported. This patch removes the enable_lecoc module parameter which was previously needed to enable support for LE L2CAP CoC. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 - net/bluetooth/l2cap_core.c | 11 ----------- net/bluetooth/l2cap_sock.c | 29 ----------------------------- 3 files changed, 41 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index ae482f41594a..13bec91785f4 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -857,7 +857,6 @@ static inline long l2cap_chan_no_get_sndtimeo(struct l2cap_chan *chan) } extern bool disable_ertm; -extern bool enable_lecoc; int l2cap_init_sockets(void); void l2cap_cleanup_sockets(void); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 66fbac91eaed..6e6b3a9c8e6d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -5544,17 +5544,6 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, { int err = 0; - if (!enable_lecoc) { - switch (cmd->code) { - case L2CAP_LE_CONN_REQ: - case L2CAP_LE_CONN_RSP: - case L2CAP_LE_CREDITS: - case L2CAP_DISCONN_REQ: - case L2CAP_DISCONN_RSP: - return -EINVAL; - } - } - switch (cmd->code) { case L2CAP_COMMAND_REJ: l2cap_le_command_rej(conn, cmd, cmd_len, data); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 27d3d6d48b6e..b247f9d27fed 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -36,8 +36,6 @@ #include "smp.h" -bool enable_lecoc; - static struct bt_sock_list l2cap_sk_list = { .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock) }; @@ -111,8 +109,6 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) } if (bdaddr_type_is_le(la.l2_bdaddr_type)) { - if (!enable_lecoc && la.l2_psm) - return -EINVAL; /* We only allow ATT user space socket */ if (la.l2_cid && la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT)) @@ -229,8 +225,6 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, return -EINVAL; if (bdaddr_type_is_le(la.l2_bdaddr_type)) { - if (!enable_lecoc && la.l2_psm) - return -EINVAL; /* We only allow ATT user space socket */ if (la.l2_cid && la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT)) @@ -578,11 +572,6 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, break; case BT_SNDMTU: - if (!enable_lecoc) { - err = -EPROTONOSUPPORT; - break; - } - if (!bdaddr_type_is_le(chan->src_type)) { err = -EINVAL; break; @@ -598,11 +587,6 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, break; case BT_RCVMTU: - if (!enable_lecoc) { - err = -EPROTONOSUPPORT; - break; - } - if (!bdaddr_type_is_le(chan->src_type)) { err = -EINVAL; break; @@ -919,11 +903,6 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, break; case BT_SNDMTU: - if (!enable_lecoc) { - err = -EPROTONOSUPPORT; - break; - } - if (!bdaddr_type_is_le(chan->src_type)) { err = -EINVAL; break; @@ -936,11 +915,6 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, break; case BT_RCVMTU: - if (!enable_lecoc) { - err = -EPROTONOSUPPORT; - break; - } - if (!bdaddr_type_is_le(chan->src_type)) { err = -EINVAL; break; @@ -1643,6 +1617,3 @@ void l2cap_cleanup_sockets(void) bt_sock_unregister(BTPROTO_L2CAP); proto_unregister(&l2cap_proto); } - -module_param(enable_lecoc, bool, 0644); -MODULE_PARM_DESC(enable_lecoc, "Enable support for LE CoC"); From 7f717b91dd68db1fa01d396d03997ed1b748659f Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:01 -0500 Subject: [PATCH 115/414] Revert "Bluetooth: Remove rfcomm_carrier_raised()" This reverts commit f86772af6a0f643d3e13eb3f4f9213ae0c333ee4. This is the first of a 3-patch revert, together with Revert "Bluetooth: Always wait for a connection on RFCOMM open()" and Revert "Bluetooth: Move rfcomm_get_device() before rfcomm_dev_activate()". Commit 4a2fb3ecc7467c775b154813861f25a0ddc11aa0, "Bluetooth: Always wait for a connection on RFCOMM open()" open-codes blocking on tty open(), rather than using the default behavior implemented by the tty port. The reasons for reverting that patch are detailed in that changelog; this patch restores required functionality for that revert. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index f9c0980abeea..aeabadeef82b 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -160,6 +160,14 @@ static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty) return err; } +/* we block the open until the dlc->state becomes BT_CONNECTED */ +static int rfcomm_dev_carrier_raised(struct tty_port *port) +{ + struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port); + + return (dev->dlc->state == BT_CONNECTED); +} + /* device-specific cleanup: close the dlc */ static void rfcomm_dev_shutdown(struct tty_port *port) { From 136c373bf0e8c445fc028427674817333df602e3 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:02 -0500 Subject: [PATCH 116/414] Revert "Bluetooth: Always wait for a connection on RFCOMM open()" This reverts commit 4a2fb3ecc7467c775b154813861f25a0ddc11aa0. This is the second of a 3-patch revert, together with Revert "Bluetooth: Remove rfcomm_carrier_raised()" and Revert "Bluetooth: Move rfcomm_get_device() before rfcomm_dev_activate()". Before commit cad348a17e170451ea8688b532a6ca3e98c63b60, Bluetooth: Implement .activate, .shutdown and .carrier_raised methods, tty_port_block_til_ready() was open-coded in rfcomm_tty_install() as part of the RFCOMM tty open(). Unfortunately, it did not implement non-blocking open nor CLOCAL open, but rather always blocked for carrier. This is not the expected or typical behavior for ttys, and prevents several common terminal programming idioms from working (eg., opening in non-blocking mode to initialize desired termios settings then re-opening for connection). Commit cad348a17e170451ea8688b532a6ca3e98c63b60, Bluetooth: Implement .activate, .shutdown and .carrier_raised methods, added the necessary tty_port methods to use the default tty_port_open(). However, this triggered two important user-space regressions. The first regression involves the complicated mechanism for reparenting the rfcomm tty device to the ACL link device which represents an open link to a specific bluetooth host. This regression causes ModemManager to conclude the rfcomm tty device does not front a modem so it makes no attempt to initialize an attached modem. This regression is caused by the lack of a device_move() if the dlc is already open (and not specifically related to the open-coded block_til_ready()). A more appropriate solution is submitted in "Bluetooth: Fix unsafe RFCOMM device parenting" and "Bluetooth: Fix RFCOMM parent device for reused dlc" The second regression involves "rfcomm bind" and wvdial (a ppp dialer). rfcomm bind creates a device node for a /dev/rfcomm. wvdial opens that device in non-blocking mode (because it expects the connection to have already been established). In addition, subsequent writes to the rfcomm tty device fail (because the link is not yet connected; rfcomm connection begins with the actual tty open()). However, restoring the original behavior (in the patch which this reverts) was undesirable. Firstly, the original reporter notes that a trivial userspace "workaround" already exists: rfcomm connect, which creates the device node and establishes the expected connection. Secondly, the failed writes occur because the rfcomm tty driver does not buffer writes to an unconnected device; this contrasts with the dozen of other tty drivers (in fact, all of them) that do just that. The submitted patch "Bluetooth: Don't fail RFCOMM tty writes" corrects this. Thirdly, it was a long-standing bug to block on non-blocking open, which is re-fixed by revert. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 46 +++++++------------------------------- 1 file changed, 8 insertions(+), 38 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index aeabadeef82b..32ef9f91965c 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -58,7 +58,6 @@ struct rfcomm_dev { uint modem_status; struct rfcomm_dlc *dlc; - wait_queue_head_t conn_wait; struct device *tty_dev; @@ -124,40 +123,8 @@ static struct device *rfcomm_get_device(struct rfcomm_dev *dev) static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty) { struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port); - DEFINE_WAIT(wait); - int err; - err = rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel); - if (err) - return err; - - while (1) { - prepare_to_wait(&dev->conn_wait, &wait, TASK_INTERRUPTIBLE); - - if (dev->dlc->state == BT_CLOSED) { - err = -dev->err; - break; - } - - if (dev->dlc->state == BT_CONNECTED) - break; - - if (signal_pending(current)) { - err = -ERESTARTSYS; - break; - } - - tty_unlock(tty); - schedule(); - tty_lock(tty); - } - finish_wait(&dev->conn_wait, &wait); - - if (!err) - device_move(dev->tty_dev, rfcomm_get_device(dev), - DPM_ORDER_DEV_AFTER_PARENT); - - return err; + return rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel); } /* we block the open until the dlc->state becomes BT_CONNECTED */ @@ -184,6 +151,7 @@ static const struct tty_port_operations rfcomm_port_ops = { .destruct = rfcomm_dev_destruct, .activate = rfcomm_dev_activate, .shutdown = rfcomm_dev_shutdown, + .carrier_raised = rfcomm_dev_carrier_raised, }; static struct rfcomm_dev *__rfcomm_dev_get(int id) @@ -290,7 +258,6 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) tty_port_init(&dev->port); dev->port.ops = &rfcomm_port_ops; - init_waitqueue_head(&dev->conn_wait); skb_queue_head_init(&dev->pending); @@ -609,9 +576,12 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) BT_DBG("dlc %p dev %p err %d", dlc, dev, err); dev->err = err; - wake_up_interruptible(&dev->conn_wait); + if (dlc->state == BT_CONNECTED) { + device_move(dev->tty_dev, rfcomm_get_device(dev), + DPM_ORDER_DEV_AFTER_PARENT); - if (dlc->state == BT_CLOSED) + wake_up_interruptible(&dev->port.open_wait); + } else if (dlc->state == BT_CLOSED) tty_port_tty_hangup(&dev->port, false); } @@ -1133,7 +1103,7 @@ int __init rfcomm_init_ttys(void) rfcomm_tty_driver->subtype = SERIAL_TYPE_NORMAL; rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; rfcomm_tty_driver->init_termios = tty_std_termios; - rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON; tty_set_operations(rfcomm_tty_driver, &rfcomm_ops); From f87c24e74e88d767e7024c4464d0d1fb3642fb5e Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:03 -0500 Subject: [PATCH 117/414] Revert "Bluetooth: Move rfcomm_get_device() before rfcomm_dev_activate()" This reverts commit e228b63390536f5b737056059a9a04ea016b1abf. This is the third of a 3-patch revert, together with Revert "Bluetooth: Remove rfcomm_carrier_raised()" and Revert "Bluetooth: Always wait for a connection on RFCOMM open()". Commit 4a2fb3ecc7467c775b154813861f25a0ddc11aa0, "Bluetooth: Always wait for a connection on RFCOMM open()" open-codes blocking on tty open(), rather than using the default behavior implemented by the tty port. The reasons for reverting that patch are detailed in that changelog; this patch restores required functionality for that revert. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 32ef9f91965c..a535ef148ef6 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -103,22 +103,6 @@ static void rfcomm_dev_destruct(struct tty_port *port) module_put(THIS_MODULE); } -static struct device *rfcomm_get_device(struct rfcomm_dev *dev) -{ - struct hci_dev *hdev; - struct hci_conn *conn; - - hdev = hci_get_route(&dev->dst, &dev->src); - if (!hdev) - return NULL; - - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst); - - hci_dev_put(hdev); - - return conn ? &conn->dev : NULL; -} - /* device-specific initialization: open the dlc */ static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty) { @@ -185,6 +169,22 @@ static struct rfcomm_dev *rfcomm_dev_get(int id) return dev; } +static struct device *rfcomm_get_device(struct rfcomm_dev *dev) +{ + struct hci_dev *hdev; + struct hci_conn *conn; + + hdev = hci_get_route(&dev->dst, &dev->src); + if (!hdev) + return NULL; + + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst); + + hci_dev_put(hdev); + + return conn ? &conn->dev : NULL; +} + static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf) { struct rfcomm_dev *dev = dev_get_drvdata(tty_dev); From c0fdfb80382e4901473ce0e31d1e7833c1d297be Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:04 -0500 Subject: [PATCH 118/414] tty: Fix ref counting for port krefs The tty core supports two models for handling tty_port lifetimes; the tty_port can use the kref supplied by tty_port (which will automatically destruct the tty_port when the ref count drops to zero) or it can destruct the tty_port manually. For tty drivers that choose to use the port kref to manage the tty_port lifetime, it is not possible to safely acquire a port reference conditionally. If the last reference is released after evaluating the condition but before acquiring the reference, a bogus reference will be held while the tty_port destruction commences. Rather, only acquire a port reference if the ref count is non-zero and allow the caller to distinguish if a reference has successfully been acquired. Cc: Jiri Slaby Signed-off-by: Peter Hurley Acked-by: Greg Kroah-Hartman Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- include/linux/tty.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/tty.h b/include/linux/tty.h index 90b4fdc8a61f..4781d7b27dd3 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -518,9 +518,9 @@ extern void tty_port_put(struct tty_port *port); static inline struct tty_port *tty_port_get(struct tty_port *port) { - if (port) - kref_get(&port->kref); - return port; + if (port && kref_get_unless_zero(&port->kref)) + return port; + return NULL; } /* If the cts flow control is enabled, return true. */ From 082a1532fc7607727f759c069eb8dd9fa5ae3f37 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:05 -0500 Subject: [PATCH 119/414] Bluetooth: Fix racy acquire of rfcomm_dev reference rfcomm_dev_get() can return a rfcomm_dev reference for a device for which destruction may be commencing. This can happen on tty destruction, which calls rfcomm_tty_cleanup(), the last port reference may have been released but RFCOMM_TTY_RELEASED was not set. The following race is also possible: CPU 0 | CPU 1 | rfcomm_release_dev rfcomm_dev_get | . spin_lock | . dev = __rfcomm_dev_get | . if dev | . if test_bit(TTY_RELEASED) | . | !test_and_set_bit(TTY_RELEASED) | tty_port_put <<<< last reference else | tty_port_get | The reference acquire is bogus because destruction will commence with the release of the last reference. Ignore the external state change of TTY_RELEASED and instead rely on the reference acquire itself to determine if the reference is valid. Cc: Jiri Slaby Cc: Greg Kroah-Hartman Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index a535ef148ef6..7cf193f0eea7 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -157,12 +157,8 @@ static struct rfcomm_dev *rfcomm_dev_get(int id) dev = __rfcomm_dev_get(id); - if (dev) { - if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) - dev = NULL; - else - tty_port_get(&dev->port); - } + if (dev && !tty_port_get(&dev->port)) + dev = NULL; spin_unlock(&rfcomm_dev_lock); From 960603a54aa0d5f4f1c4f1037bcaee571d03cb1e Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:06 -0500 Subject: [PATCH 120/414] Bluetooth: Exclude released devices from RFCOMMGETDEVLIST ioctl When enumerating RFCOMM devices in the rfcomm_dev_list, holding the rfcomm_dev_lock only guarantees the existence of the enumerated rfcomm_dev in memory, and not safe access to its state. Testing the device state (such as RFCOMM_TTY_RELEASED) does not guarantee the device will remain in that state for the subsequent access to the rfcomm_dev's fields, nor guarantee that teardown has not commenced. Obtain an rfcomm_dev reference for the duration of rfcomm_dev access. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 7cf193f0eea7..b385d9985656 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -468,7 +468,7 @@ static int rfcomm_get_dev_list(void __user *arg) spin_lock(&rfcomm_dev_lock); list_for_each_entry(dev, &rfcomm_dev_list, list) { - if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) + if (!tty_port_get(&dev->port)) continue; (di + n)->id = dev->id; (di + n)->flags = dev->flags; @@ -476,6 +476,7 @@ static int rfcomm_get_dev_list(void __user *arg) (di + n)->channel = dev->channel; bacpy(&(di + n)->src, &dev->src); bacpy(&(di + n)->dst, &dev->dst); + tty_port_put(&dev->port); if (++n >= dev_num) break; } From 1c64834e0624c61735308138e67cc3b527f41621 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:07 -0500 Subject: [PATCH 121/414] Bluetooth: Release rfcomm_dev only once No logic prevents an rfcomm_dev from being released multiple times. For example, if the rfcomm_dev ref count is large due to pending tx, then multiple RFCOMMRELEASEDEV ioctls may mistakenly release the rfcomm_dev too many times. Note that concurrent ioctls are not required to create this condition. Introduce RFCOMM_DEV_RELEASED status bit which guarantees the rfcomm_dev can only be released once. NB: Since the flags are exported to userspace, introduce the status field to track state for which userspace should not be aware. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- include/net/bluetooth/rfcomm.h | 6 +++++- net/bluetooth/rfcomm/tty.c | 11 +++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index c312cfc4e922..b9759eb17cdd 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -324,11 +324,15 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, #define RFCOMMGETDEVINFO _IOR('R', 211, int) #define RFCOMMSTEALDLC _IOW('R', 220, int) +/* rfcomm_dev.flags bit definitions */ #define RFCOMM_REUSE_DLC 0 #define RFCOMM_RELEASE_ONHUP 1 #define RFCOMM_HANGUP_NOW 2 #define RFCOMM_TTY_ATTACHED 3 -#define RFCOMM_TTY_RELEASED 4 +#define RFCOMM_DEFUNCT_BIT4 4 /* don't reuse this bit - userspace visible */ + +/* rfcomm_dev.status bit definitions */ +#define RFCOMM_DEV_RELEASED 0 struct rfcomm_dev_req { s16 dev_id; diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index b385d9985656..d9d4bc89e638 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -51,6 +51,8 @@ struct rfcomm_dev { unsigned long flags; int err; + unsigned long status; /* don't export to userspace */ + bdaddr_t src; bdaddr_t dst; u8 channel; @@ -423,6 +425,12 @@ static int rfcomm_release_dev(void __user *arg) return -EPERM; } + /* only release once */ + if (test_and_set_bit(RFCOMM_DEV_RELEASED, &dev->status)) { + tty_port_put(&dev->port); + return -EALREADY; + } + if (req.flags & (1 << RFCOMM_HANGUP_NOW)) rfcomm_dlc_close(dev->dlc, 0); @@ -433,8 +441,7 @@ static int rfcomm_release_dev(void __user *arg) tty_kref_put(tty); } - if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) && - !test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags)) + if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) tty_port_put(&dev->port); tty_port_put(&dev->port); From 80ea73378af46b0023eb2f400d26c2a60248ffaa Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:08 -0500 Subject: [PATCH 122/414] Bluetooth: Fix unreleased rfcomm_dev reference When RFCOMM_RELEASE_ONHUP is set, the rfcomm tty driver 'takes over' the initial rfcomm_dev reference created by the RFCOMMCREATEDEV ioctl. The assumption is that the rfcomm tty driver will release the rfcomm_dev reference when the tty is freed (in rfcomm_tty_cleanup()). However, if the tty is never opened, the 'take over' never occurs, so when RFCOMMRELEASEDEV ioctl is called, the reference is not released. Track the state of the reference 'take over' so that the release is guaranteed by either the RFCOMMRELEASEDEV ioctl or the rfcomm tty driver. Note that the synchronous hangup in rfcomm_release_dev() ensures that rfcomm_tty_install() cannot race with the RFCOMMRELEASEDEV ioctl. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- include/net/bluetooth/rfcomm.h | 1 + net/bluetooth/rfcomm/tty.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index b9759eb17cdd..0d69936831fa 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -333,6 +333,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, /* rfcomm_dev.status bit definitions */ #define RFCOMM_DEV_RELEASED 0 +#define RFCOMM_TTY_OWNED 1 struct rfcomm_dev_req { s16 dev_id; diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index d9d4bc89e638..bb570d95adca 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -441,7 +441,7 @@ static int rfcomm_release_dev(void __user *arg) tty_kref_put(tty); } - if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) + if (!test_bit(RFCOMM_TTY_OWNED, &dev->status)) tty_port_put(&dev->port); tty_port_put(&dev->port); @@ -685,8 +685,10 @@ static int rfcomm_tty_install(struct tty_driver *driver, struct tty_struct *tty) * when the last process closes the tty. The behaviour is expected by * userspace. */ - if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) + if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) { + set_bit(RFCOMM_TTY_OWNED, &dev->status); tty_port_put(&dev->port); + } return 0; } From c949c224cfd7d5445ef947e8b93c0657323d5be5 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:09 -0500 Subject: [PATCH 123/414] Bluetooth: Fix RFCOMM tty teardown race RFCOMM tty device teardown can race with new tty device registration for the same device id: CPU 0 | CPU 1 rfcomm_dev_add | rfcomm_dev_destruct | spin_lock | list_del <== dev_id no longer used | spin_unlock spin_lock | . [search rfcomm_dev_list] | . [dev_id not in use] | . [initialize new rfcomm_dev] | . spin_unlock | . | . tty_port_register_device | tty_unregister_device Don't remove rfcomm_dev from the device list until after tty device unregistration has completed. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index bb570d95adca..6ea08b05b53a 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -84,10 +84,6 @@ static void rfcomm_dev_destruct(struct tty_port *port) BT_DBG("dev %p dlc %p", dev, dlc); - spin_lock(&rfcomm_dev_lock); - list_del(&dev->list); - spin_unlock(&rfcomm_dev_lock); - rfcomm_dlc_lock(dlc); /* Detach DLC if it's owned by this dev */ if (dlc->owner == dev) @@ -98,6 +94,10 @@ static void rfcomm_dev_destruct(struct tty_port *port) tty_unregister_device(rfcomm_tty_driver, dev->id); + spin_lock(&rfcomm_dev_lock); + list_del(&dev->list); + spin_unlock(&rfcomm_dev_lock); + kfree(dev); /* It's safe to call module_put() here because socket still From c10a848cea89a8f0418fa0efec33c4e8507aab4b Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:10 -0500 Subject: [PATCH 124/414] Bluetooth: Verify dlci not in use before rfcomm_dev create Only one session/channel combination may be in use at any one time. However, the failure does not occur until the tty is opened (in rfcomm_dlc_open()). Because these settings are actually bound at rfcomm device creation (via RFCOMMCREATEDEV ioctl), validate and fail before creating the rfcomm tty device. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- include/net/bluetooth/rfcomm.h | 1 + net/bluetooth/rfcomm/core.c | 26 +++++++++++++++++++++++++- net/bluetooth/rfcomm/tty.c | 8 ++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index 0d69936831fa..f8262a2783ec 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -241,6 +241,7 @@ int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb); int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig); int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig); void rfcomm_dlc_accept(struct rfcomm_dlc *d); +struct rfcomm_dlc *rfcomm_dlc_exists(bdaddr_t *src, bdaddr_t *dst, u8 channel); #define rfcomm_dlc_lock(d) spin_lock(&d->lock) #define rfcomm_dlc_unlock(d) spin_unlock(&d->lock) diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index ba115d472f7b..b378bbb6f8a7 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -360,6 +360,11 @@ static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci) return NULL; } +static int rfcomm_check_channel(u8 channel) +{ + return channel < 1 || channel > 30; +} + static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel) { struct rfcomm_session *s; @@ -369,7 +374,7 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, BT_DBG("dlc %p state %ld %pMR -> %pMR channel %d", d, d->state, src, dst, channel); - if (channel < 1 || channel > 30) + if (rfcomm_check_channel(channel)) return -EINVAL; if (d->state != BT_OPEN && d->state != BT_CLOSED) @@ -514,6 +519,25 @@ no_session: return r; } +struct rfcomm_dlc *rfcomm_dlc_exists(bdaddr_t *src, bdaddr_t *dst, u8 channel) +{ + struct rfcomm_session *s; + struct rfcomm_dlc *dlc = NULL; + u8 dlci; + + if (rfcomm_check_channel(channel)) + return ERR_PTR(-EINVAL); + + rfcomm_lock(); + s = rfcomm_session_get(src, dst); + if (s) { + dlci = __dlci(!s->initiator, channel); + dlc = rfcomm_dlc_get(s, dlci); + } + rfcomm_unlock(); + return dlc; +} + int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb) { int len = skb->len; diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 6ea08b05b53a..a58d693e1e61 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -385,6 +385,14 @@ static int rfcomm_create_dev(struct sock *sk, void __user *arg) dlc = rfcomm_pi(sk)->dlc; rfcomm_dlc_hold(dlc); } else { + /* Validate the channel is unused */ + dlc = rfcomm_dlc_exists(&req.src, &req.dst, req.channel); + if (IS_ERR(dlc)) + return PTR_ERR(dlc); + else if (dlc) { + rfcomm_dlc_put(dlc); + return -EBUSY; + } dlc = rfcomm_dlc_alloc(GFP_KERNEL); if (!dlc) return -ENOMEM; From 4339c25afb0d49878fba5a989618ffe807aa46cd Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:11 -0500 Subject: [PATCH 125/414] Bluetooth: Simplify RFCOMM session state eval Merge conditional test for BT_LISTEN session state into following switch statement (which is functionally equivalent). Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index b378bbb6f8a7..e8898624cbaf 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -1968,12 +1968,11 @@ static void rfcomm_process_sessions(void) continue; } - if (s->state == BT_LISTEN) { + switch (s->state) { + case BT_LISTEN: rfcomm_accept_connection(s); continue; - } - switch (s->state) { case BT_BOUND: s = rfcomm_check_connection(s); break; From 5998e04063563ff2ffc779510f072ff0ff94163b Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:12 -0500 Subject: [PATCH 126/414] Bluetooth: Refactor deferred setup test in rfcomm_dlc_close() Prepare for directly closing dlc if the RFCOMM session has not yet been started; refactor the deferred setup test for only those dlc states to which the test applies. Retains functional equivalence. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/core.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index e8898624cbaf..3ce5ae493d1d 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -443,11 +443,18 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) switch (d->state) { case BT_CONNECT: case BT_CONFIG: + case BT_OPEN: + case BT_CONNECT2: if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) { set_bit(RFCOMM_AUTH_REJECT, &d->flags); rfcomm_schedule(); - break; + return 0; } + } + + switch (d->state) { + case BT_CONNECT: + case BT_CONFIG: /* Fall through */ case BT_CONNECTED: @@ -461,15 +468,6 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) } break; - case BT_OPEN: - case BT_CONNECT2: - if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) { - set_bit(RFCOMM_AUTH_REJECT, &d->flags); - rfcomm_schedule(); - break; - } - /* Fall through */ - default: rfcomm_dlc_clear_timer(d); From f622357a5e83e3a812ca985a78e86d750c98228b Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:13 -0500 Subject: [PATCH 127/414] Bluetooth: Refactor dlc disconnect logic in rfcomm_dlc_close() Prepare for directly closing dlc if the RFCOMM session has not yet been started; refactor the dlc disconnect logic into a separate local function, __rfcomm_dlc_disconn(). Retains functional equivalence. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/core.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 3ce5ae493d1d..5acc82fa0200 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -431,6 +431,20 @@ int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 chann return r; } +static void __rfcomm_dlc_disconn(struct rfcomm_dlc *d) +{ + struct rfcomm_session *s = d->session; + + d->state = BT_DISCONN; + if (skb_queue_empty(&d->tx_queue)) { + rfcomm_send_disc(s, d->dlci); + rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT); + } else { + rfcomm_queue_disc(d); + rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2); + } +} + static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) { struct rfcomm_session *s = d->session; @@ -458,14 +472,7 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) /* Fall through */ case BT_CONNECTED: - d->state = BT_DISCONN; - if (skb_queue_empty(&d->tx_queue)) { - rfcomm_send_disc(s, d->dlci); - rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT); - } else { - rfcomm_queue_disc(d); - rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2); - } + __rfcomm_dlc_disconn(d); break; default: From c4fd318d6ebc16bd64ca7b9c06f21b7f33bb462e Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:14 -0500 Subject: [PATCH 128/414] Bluetooth: Directly close dlc for not yet started RFCOMM session If the RFCOMM session has not yet been started (ie., session is still in BT_BOUND state) when a dlc is closed, directly close and unlink the dlc rather than sending a DISC frame that is never sent. This allows the dlci to be immediately reused rather than waiting for a 20 second timeout. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/core.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 5acc82fa0200..b727cd97c5a2 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -468,13 +468,19 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) switch (d->state) { case BT_CONNECT: - case BT_CONFIG: - /* Fall through */ - case BT_CONNECTED: __rfcomm_dlc_disconn(d); break; + case BT_CONFIG: + if (s->state != BT_BOUND) { + __rfcomm_dlc_disconn(d); + break; + } + /* if closing a dlc in a session that hasn't been started, + * just close and unlink the dlc + */ + default: rfcomm_dlc_clear_timer(d); From b92483d54abb4ff288accc36bf1daef44dea9fbe Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:15 -0500 Subject: [PATCH 129/414] Bluetooth: Fix unsafe RFCOMM device parenting Accessing the results of hci_conn_hash_lookup_ba() is unsafe without holding the hci_dev_lock() during the lookup. For example: CPU 0 | CPU 1 hci_conn_hash_lookup_ba | hci_conn_del rcu_read_lock | hci_conn_hash_del list_for_each_entry_rcu | list_del_rcu if (.....) | synchronize_rcu rcu_read_unlock | | hci_conn_del_sysfs | hci_dev_put | hci_conn_put | put_device (last reference) | bt_link_release | kfree(conn) return p << just freed | Even if a hci_conn reference were taken (via hci_conn_get), would not guarantee the lifetime of the sysfs device, but only safe access to the in-memory structure. Ensure the hci_conn device stays valid while the rfcomm device is reparented; rename rfcomm_get_device() to rfcomm_reparent_device() and perform the reparenting within the function while holding the hci_dev_lock. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index a58d693e1e61..2975bc4b9188 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -167,20 +167,29 @@ static struct rfcomm_dev *rfcomm_dev_get(int id) return dev; } -static struct device *rfcomm_get_device(struct rfcomm_dev *dev) +static void rfcomm_reparent_device(struct rfcomm_dev *dev) { struct hci_dev *hdev; struct hci_conn *conn; hdev = hci_get_route(&dev->dst, &dev->src); if (!hdev) - return NULL; + return; + /* The lookup results are unsafe to access without the + * hci device lock (FIXME: why is this not documented?) + */ + hci_dev_lock(hdev); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst); - hci_dev_put(hdev); + /* Just because the acl link is in the hash table is no + * guarantee the sysfs device has been added ... + */ + if (conn && device_is_registered(&conn->dev)) + device_move(dev->tty_dev, &conn->dev, DPM_ORDER_DEV_AFTER_PARENT); - return conn ? &conn->dev : NULL; + hci_dev_unlock(hdev); + hci_dev_put(hdev); } static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf) @@ -589,8 +598,7 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) dev->err = err; if (dlc->state == BT_CONNECTED) { - device_move(dev->tty_dev, rfcomm_get_device(dev), - DPM_ORDER_DEV_AFTER_PARENT); + rfcomm_reparent_device(dev); wake_up_interruptible(&dev->port.open_wait); } else if (dlc->state == BT_CLOSED) From b4d21f193985218c6c75969376249f69e49eb6ee Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:16 -0500 Subject: [PATCH 130/414] Bluetooth: Fix RFCOMM parent device for reused dlc The RFCOMM tty device is parented to the acl link device when the dlc state_change(BT_CONNECTED) notification is received. However, if the dlc from the RFCOMM socket is being reused (RFCOMM_REUSE_DLC is set), then the dlc may already be connected, and no notification will occur. Instead, always parent the RFCOMM tty device to the acl link device at registration time. If the acl link device is not available (eg, because the dlc is not connected) then the tty will remain unparented until the BT_CONNECTED notification is received. Fixes regression with ModemManager when the rfcomm device is created with the flag RFCOMM_REUSE_DLC. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 2975bc4b9188..fa1226f17e86 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -316,6 +316,7 @@ out: goto free; } + rfcomm_reparent_device(dev); dev_set_drvdata(dev->tty_dev, dev); if (device_create_file(dev->tty_dev, &dev_attr_address) < 0) From 7611fcedd6caae0586397508a2414788d87a231c Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:17 -0500 Subject: [PATCH 131/414] Bluetooth: Rename __rfcomm_dev_get() to __rfcomm_dev_lookup() Functions which search lists for matching id's are more commonly named *_lookup, which is the convention in the bluetooth core as well. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index fa1226f17e86..4a38b5454ab0 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -140,7 +140,7 @@ static const struct tty_port_operations rfcomm_port_ops = { .carrier_raised = rfcomm_dev_carrier_raised, }; -static struct rfcomm_dev *__rfcomm_dev_get(int id) +static struct rfcomm_dev *__rfcomm_dev_lookup(int id) { struct rfcomm_dev *dev; @@ -157,7 +157,7 @@ static struct rfcomm_dev *rfcomm_dev_get(int id) spin_lock(&rfcomm_dev_lock); - dev = __rfcomm_dev_get(id); + dev = __rfcomm_dev_lookup(id); if (dev && !tty_port_get(&dev->port)) dev = NULL; From 033ace99c444daa4141b84419f670513ce637b77 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:18 -0500 Subject: [PATCH 132/414] Bluetooth: Serialize RFCOMMCREATEDEV and RFCOMMRELEASEDEV ioctls At least two different race conditions exist with multiple concurrent RFCOMMCREATEDEV and RFCOMMRELEASEDEV ioctls: * Multiple concurrent RFCOMMCREATEDEVs with RFCOMM_REUSE_DLC can mistakenly share the same DLC. * RFCOMMRELEASEDEV can destruct the rfcomm_dev still being constructed by RFCOMMCREATEDEV. Introduce rfcomm_ioctl_mutex to serialize these add/remove operations. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 4a38b5454ab0..ef2769553dab 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -40,6 +40,7 @@ #define RFCOMM_TTY_MAJOR 216 /* device node major id of the usb/bluetooth.c driver */ #define RFCOMM_TTY_MINOR 0 +static DEFINE_MUTEX(rfcomm_ioctl_mutex); static struct tty_driver *rfcomm_tty_driver; struct rfcomm_dev { @@ -373,7 +374,7 @@ static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size #define NOCAP_FLAGS ((1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP)) -static int rfcomm_create_dev(struct sock *sk, void __user *arg) +static int __rfcomm_create_dev(struct sock *sk, void __user *arg) { struct rfcomm_dev_req req; struct rfcomm_dlc *dlc; @@ -423,7 +424,7 @@ static int rfcomm_create_dev(struct sock *sk, void __user *arg) return id; } -static int rfcomm_release_dev(void __user *arg) +static int __rfcomm_release_dev(void __user *arg) { struct rfcomm_dev_req req; struct rfcomm_dev *dev; @@ -466,6 +467,28 @@ static int rfcomm_release_dev(void __user *arg) return 0; } +static int rfcomm_create_dev(struct sock *sk, void __user *arg) +{ + int ret; + + mutex_lock(&rfcomm_ioctl_mutex); + ret = __rfcomm_create_dev(sk, arg); + mutex_unlock(&rfcomm_ioctl_mutex); + + return ret; +} + +static int rfcomm_release_dev(void __user *arg) +{ + int ret; + + mutex_lock(&rfcomm_ioctl_mutex); + ret = __rfcomm_release_dev(arg); + mutex_unlock(&rfcomm_ioctl_mutex); + + return ret; +} + static int rfcomm_get_dev_list(void __user *arg) { struct rfcomm_dev *dev; From f355095756c2a0b77a5b0aa0384c0c09d9735252 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:19 -0500 Subject: [PATCH 133/414] Bluetooth: Refactor rfcomm_dev_add() Move rfcomm_dev allocation and initialization into new function, __rfcomm_dev_add(), to simplify resource release in error handling. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index ef2769553dab..0537a0501595 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -208,17 +208,16 @@ static ssize_t show_channel(struct device *tty_dev, struct device_attribute *att static DEVICE_ATTR(address, S_IRUGO, show_address, NULL); static DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL); -static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) +static struct rfcomm_dev *__rfcomm_dev_add(struct rfcomm_dev_req *req, + struct rfcomm_dlc *dlc) { struct rfcomm_dev *dev, *entry; struct list_head *head = &rfcomm_dev_list; int err = 0; - BT_DBG("id %d channel %d", req->dev_id, req->channel); - dev = kzalloc(sizeof(struct rfcomm_dev), GFP_KERNEL); if (!dev) - return -ENOMEM; + return ERR_PTR(-ENOMEM); spin_lock(&rfcomm_dev_lock); @@ -301,22 +300,37 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) holds reference to this module. */ __module_get(THIS_MODULE); + spin_unlock(&rfcomm_dev_lock); + return dev; + out: spin_unlock(&rfcomm_dev_lock); + kfree(dev); + return ERR_PTR(err); +} - if (err < 0) - goto free; +static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) +{ + struct rfcomm_dev *dev; + struct device *tty; - dev->tty_dev = tty_port_register_device(&dev->port, rfcomm_tty_driver, + BT_DBG("id %d channel %d", req->dev_id, req->channel); + + dev = __rfcomm_dev_add(req, dlc); + if (IS_ERR(dev)) + return PTR_ERR(dev); + + tty = tty_port_register_device(&dev->port, rfcomm_tty_driver, dev->id, NULL); - if (IS_ERR(dev->tty_dev)) { - err = PTR_ERR(dev->tty_dev); + if (IS_ERR(tty)) { spin_lock(&rfcomm_dev_lock); list_del(&dev->list); spin_unlock(&rfcomm_dev_lock); - goto free; + kfree(dev); + return PTR_ERR(tty); } + dev->tty_dev = tty; rfcomm_reparent_device(dev); dev_set_drvdata(dev->tty_dev, dev); @@ -327,10 +341,6 @@ out: BT_ERR("Failed to create channel attribute"); return dev->id; - -free: - kfree(dev); - return err; } /* ---- Send buffer ---- */ From fb856e50900a84dd9f8d50d3882eb4a26ba6ea54 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:20 -0500 Subject: [PATCH 134/414] Bluetooth: Cleanup RFCOMM device registration error handling If RFCOMM tty device registration fails, cleanup by releasing the tty_port reference to trigger rfcomm_dev destruction (rather than open-coding it). The dlc reference release is moved into rfcomm_dev_add(), which ensures cleanup in both error paths -- ie., if __rfcomm_dev_add() fails or if tty_port_register_device() fails. Fixes releasing the module reference if device registration fails. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 0537a0501595..375b60dae04d 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -93,7 +93,8 @@ static void rfcomm_dev_destruct(struct tty_port *port) rfcomm_dlc_put(dlc); - tty_unregister_device(rfcomm_tty_driver, dev->id); + if (dev->tty_dev) + tty_unregister_device(rfcomm_tty_driver, dev->id); spin_lock(&rfcomm_dev_lock); list_del(&dev->list); @@ -317,16 +318,15 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) BT_DBG("id %d channel %d", req->dev_id, req->channel); dev = __rfcomm_dev_add(req, dlc); - if (IS_ERR(dev)) + if (IS_ERR(dev)) { + rfcomm_dlc_put(dlc); return PTR_ERR(dev); + } tty = tty_port_register_device(&dev->port, rfcomm_tty_driver, dev->id, NULL); if (IS_ERR(tty)) { - spin_lock(&rfcomm_dev_lock); - list_del(&dev->list); - spin_unlock(&rfcomm_dev_lock); - kfree(dev); + tty_port_put(&dev->port); return PTR_ERR(tty); } @@ -420,10 +420,8 @@ static int __rfcomm_create_dev(struct sock *sk, void __user *arg) } id = rfcomm_dev_add(&req, dlc); - if (id < 0) { - rfcomm_dlc_put(dlc); + if (id < 0) return id; - } if (req.flags & (1 << RFCOMM_REUSE_DLC)) { /* DLC is now used by device. From 5326a4ee982703ddba14a9821fe5cb10d122e1b0 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:21 -0500 Subject: [PATCH 135/414] Bluetooth: Force -EIO from tty read/write if .activate() fails If rfcomm_dlc_open() fails, set tty into error state which returns -EIO from reads and writes. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 375b60dae04d..f6b9f0c4c29e 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -111,8 +111,12 @@ static void rfcomm_dev_destruct(struct tty_port *port) static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty) { struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port); + int err; - return rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel); + err = rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel); + if (err) + set_bit(TTY_IO_ERROR, &tty->flags); + return err; } /* we block the open until the dlc->state becomes BT_CONNECTED */ From 72e5108c6d637ea2f4c0e64b09621a79f363b664 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:22 -0500 Subject: [PATCH 136/414] Bluetooth: Don't fail RFCOMM tty writes The tty driver api design prefers no-fail writes if the driver write_room() method has previously indicated space is available to accept writes. Since this is trivially possible for the RFCOMM tty driver, do so. Introduce rfcomm_dlc_send_noerror(), which queues but does not schedule the krfcomm thread if the dlc is not yet connected (and thus does not error based on the connection state). The mtu size test is also unnecessary since the caller already chunks the written data into mtu size. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- include/net/bluetooth/rfcomm.h | 1 + net/bluetooth/rfcomm/core.c | 14 ++++++++++++++ net/bluetooth/rfcomm/tty.c | 23 +++++++---------------- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index f8262a2783ec..2611cc389d7d 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -238,6 +238,7 @@ int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel); int rfcomm_dlc_close(struct rfcomm_dlc *d, int reason); int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb); +void rfcomm_dlc_send_noerror(struct rfcomm_dlc *d, struct sk_buff *skb); int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig); int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig); void rfcomm_dlc_accept(struct rfcomm_dlc *d); diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index b727cd97c5a2..21e15318937c 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -569,6 +569,20 @@ int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb) return len; } +void rfcomm_dlc_send_noerror(struct rfcomm_dlc *d, struct sk_buff *skb) +{ + int len = skb->len; + + BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len); + + rfcomm_make_uih(skb, d->addr); + skb_queue_tail(&d->tx_queue, skb); + + if (d->state == BT_CONNECTED && + !test_bit(RFCOMM_TX_THROTTLED, &d->flags)) + rfcomm_schedule(); +} + void __rfcomm_dlc_throttle(struct rfcomm_dlc *d) { BT_DBG("dlc %p state %ld", d, d->state); diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index f6b9f0c4c29e..af775f35c019 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -374,14 +374,10 @@ static void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev) static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, gfp_t priority) { - if (atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) { - struct sk_buff *skb = alloc_skb(size, priority); - if (skb) { - rfcomm_set_owner_w(skb, dev); - return skb; - } - } - return NULL; + struct sk_buff *skb = alloc_skb(size, priority); + if (skb) + rfcomm_set_owner_w(skb, dev); + return skb; } /* ---- Device IOCTLs ---- */ @@ -786,7 +782,7 @@ static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, in struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; struct rfcomm_dlc *dlc = dev->dlc; struct sk_buff *skb; - int err = 0, sent = 0, size; + int sent = 0, size; BT_DBG("tty %p count %d", tty, count); @@ -794,7 +790,6 @@ static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, in size = min_t(uint, count, dlc->mtu); skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, GFP_ATOMIC); - if (!skb) break; @@ -802,17 +797,13 @@ static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, in memcpy(skb_put(skb, size), buf + sent, size); - err = rfcomm_dlc_send(dlc, skb); - if (err < 0) { - kfree_skb(skb); - break; - } + rfcomm_dlc_send_noerror(dlc, skb); sent += size; count -= size; } - return sent ? sent : err; + return sent; } static int rfcomm_tty_write_room(struct tty_struct *tty) From b16b4351313fb89ccb4c227d432d16aa32ffec72 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:23 -0500 Subject: [PATCH 137/414] Bluetooth: Refactor write_room() calculation Compute the amount of space available for a single write() within rfcomm_room(); clamp to 0 for negative values. Note this patch does not change the result of the computation. Report the amount of room returned in the debug printk. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index af775f35c019..3f44195c04ad 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -348,11 +348,18 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) } /* ---- Send buffer ---- */ -static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc) +static inline unsigned int rfcomm_room(struct rfcomm_dev *dev) { - /* We can't let it be zero, because we don't get a callback - when tx_credits becomes nonzero, hence we'd never wake up */ - return dlc->mtu * (dlc->tx_credits?:1); + struct rfcomm_dlc *dlc = dev->dlc; + + /* The limit is bogus; the number of packets which can + * currently be sent by the krfcommd thread has no relevance + * to the number of packets which can be queued on the dlc's + * tx queue. + */ + int limit = dlc->mtu * (dlc->tx_credits?:1); + + return max(0, limit - atomic_read(&dev->wmem_alloc)); } static void rfcomm_wfree(struct sk_buff *skb) @@ -809,16 +816,12 @@ static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, in static int rfcomm_tty_write_room(struct tty_struct *tty) { struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; - int room; + int room = 0; - BT_DBG("tty %p", tty); + if (dev && dev->dlc) + room = rfcomm_room(dev); - if (!dev || !dev->dlc) - return 0; - - room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc); - if (room < 0) - room = 0; + BT_DBG("tty %p room %d", tty, room); return room; } From 8981be9b2fe5553af35a43865d9ab4271c3aa2e2 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:24 -0500 Subject: [PATCH 138/414] Bluetooth: Fix write_room() calculation The skb truesize of a 12-byte payload with a 10-byte head/tail reserve is 768 bytes. Consequently, even with 40 tx_credits, at most 6 packets could be queued at any one time: 40 tx_credits * 127-byte mtu < 768-byte truesize * 7 This error could also cause the tx queue to apparently stall if credit flow control is disabled (where tx_credits is fixed at 5), or if the receiver only granted a limited number of tx credits (eg., less than 7). Instead, track the outstanding number of queued packets not yet sent in wmem_alloc and allow for a maximum of 40 queued packets. Report the space avail for a single write() as the mtu * number of packets left before reaching the maximum. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 3f44195c04ad..403ec09f480a 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -352,20 +352,16 @@ static inline unsigned int rfcomm_room(struct rfcomm_dev *dev) { struct rfcomm_dlc *dlc = dev->dlc; - /* The limit is bogus; the number of packets which can - * currently be sent by the krfcommd thread has no relevance - * to the number of packets which can be queued on the dlc's - * tx queue. - */ - int limit = dlc->mtu * (dlc->tx_credits?:1); + /* Limit the outstanding number of packets not yet sent to 40 */ + int pending = 40 - atomic_read(&dev->wmem_alloc); - return max(0, limit - atomic_read(&dev->wmem_alloc)); + return max(0, pending) * dlc->mtu; } static void rfcomm_wfree(struct sk_buff *skb) { struct rfcomm_dev *dev = (void *) skb->sk; - atomic_sub(skb->truesize, &dev->wmem_alloc); + atomic_dec(&dev->wmem_alloc); if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags)) tty_port_tty_wakeup(&dev->port); tty_port_put(&dev->port); @@ -374,7 +370,7 @@ static void rfcomm_wfree(struct sk_buff *skb) static void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev) { tty_port_get(&dev->port); - atomic_add(skb->truesize, &dev->wmem_alloc); + atomic_inc(&dev->wmem_alloc); skb->sk = (void *) dev; skb->destructor = rfcomm_wfree; } From 90046f509dca8e754b75aacb6ef7afa68b102c63 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 14 Feb 2014 14:45:51 +0100 Subject: [PATCH 139/414] ath10k: fix SMPS support Firmware ignores SMPS flags in peer assoc command. For SMPS to work it is necessary to set peer parameter after peer assoc command so that tx chainmask is setup properly. This should fix packet loss and improve throughput with stations that have SMPS enabled upon association. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 56 +++++++++++++++++++++------ 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 44b550b2fcfd..c2aaecb4c25b 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1082,7 +1082,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, struct wmi_peer_assoc_complete_arg *arg) { const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; - int smps; int i, n; lockdep_assert_held(&ar->conf_mutex); @@ -1128,17 +1127,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, arg->peer_flags |= WMI_PEER_STBC; } - smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; - smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; - - if (smps == WLAN_HT_CAP_SM_PS_STATIC) { - arg->peer_flags |= WMI_PEER_SPATIAL_MUX; - arg->peer_flags |= WMI_PEER_STATIC_MIMOPS; - } else if (smps == WLAN_HT_CAP_SM_PS_DYNAMIC) { - arg->peer_flags |= WMI_PEER_SPATIAL_MUX; - arg->peer_flags |= WMI_PEER_DYN_MIMOPS; - } - if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2]) arg->peer_rate_caps |= WMI_RC_TS_FLAG; else if (ht_cap->mcs.rx_mask[1]) @@ -1378,6 +1366,33 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar, return 0; } +static const u32 ath10k_smps_map[] = { + [WLAN_HT_CAP_SM_PS_STATIC] = WMI_PEER_SMPS_STATIC, + [WLAN_HT_CAP_SM_PS_DYNAMIC] = WMI_PEER_SMPS_DYNAMIC, + [WLAN_HT_CAP_SM_PS_INVALID] = WMI_PEER_SMPS_PS_NONE, + [WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE, +}; + +static int ath10k_setup_peer_smps(struct ath10k *ar, struct ath10k_vif *arvif, + const u8 *addr, + const struct ieee80211_sta_ht_cap *ht_cap) +{ + int smps; + + if (!ht_cap->ht_supported) + return 0; + + smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; + smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; + + if (smps >= ARRAY_SIZE(ath10k_smps_map)) + return -EINVAL; + + return ath10k_wmi_peer_set_param(ar, arvif->vdev_id, addr, + WMI_PEER_SMPS_STATE, + ath10k_smps_map[smps]); +} + /* can be called only in mac80211 callbacks due to `key_count` usage */ static void ath10k_bss_assoc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -1385,6 +1400,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, { struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); + struct ieee80211_sta_ht_cap ht_cap; struct wmi_peer_assoc_complete_arg peer_arg; struct ieee80211_sta *ap_sta; int ret; @@ -1401,6 +1417,10 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, return; } + /* ap_sta must be accessed only within rcu section which must be left + * before calling ath10k_setup_peer_smps() which might sleep. */ + ht_cap = ap_sta->ht_cap; + ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta, bss_conf, &peer_arg); if (ret) { @@ -1419,6 +1439,12 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, return; } + ret = ath10k_setup_peer_smps(ar, arvif, bss_conf->bssid, &ht_cap); + if (ret) { + ath10k_warn("failed to setup peer SMPS: %d\n", ret); + return; + } + ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up (associated) bssid %pM aid %d\n", arvif->vdev_id, bss_conf->bssid, bss_conf->aid); @@ -1500,6 +1526,12 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, return ret; } + ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap); + if (ret) { + ath10k_warn("failed to setup peer SMPS: %d\n", ret); + return ret; + } + ret = ath10k_install_peer_wep_keys(arvif, sta->addr); if (ret) { ath10k_warn("could not install peer wep keys (%d)\n", ret); From 9797febc4cc112869b19a110f70e0dedb1bb63d6 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 14 Feb 2014 14:49:48 +0100 Subject: [PATCH 140/414] ath10k: implement sta_rc_update() This allows dynamic changes of bandwidth/nss/smps, e.g. via ht/vht operation mode change notification. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 12 ++ drivers/net/wireless/ath/ath10k/mac.c | 157 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 6 + 3 files changed, 175 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index fae53f909550..1fc26fe057e8 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -228,6 +228,18 @@ struct ath10k_peer { struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1]; }; +struct ath10k_sta { + struct ath10k_vif *arvif; + + /* the following are protected by ar->data_lock */ + u32 changed; /* IEEE80211_RC_* */ + u32 bw; + u32 nss; + u32 smps; + + struct work_struct update_wk; +}; + #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ) struct ath10k_vif { diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c2aaecb4c25b..e17f5d732b5a 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3104,6 +3104,69 @@ exit: return ret; } +static void ath10k_sta_rc_update_wk(struct work_struct *wk) +{ + struct ath10k *ar; + struct ath10k_vif *arvif; + struct ath10k_sta *arsta; + struct ieee80211_sta *sta; + u32 changed, bw, nss, smps; + int err; + + arsta = container_of(wk, struct ath10k_sta, update_wk); + sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv); + arvif = arsta->arvif; + ar = arvif->ar; + + spin_lock_bh(&ar->data_lock); + + changed = arsta->changed; + arsta->changed = 0; + + bw = arsta->bw; + nss = arsta->nss; + smps = arsta->smps; + + spin_unlock_bh(&ar->data_lock); + + mutex_lock(&ar->conf_mutex); + + if (changed & IEEE80211_RC_BW_CHANGED) { + ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n", + sta->addr, bw); + + err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, + WMI_PEER_CHAN_WIDTH, bw); + if (err) + ath10k_warn("failed to update STA %pM peer bw %d: %d\n", + sta->addr, bw, err); + } + + if (changed & IEEE80211_RC_NSS_CHANGED) { + ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM nss %d\n", + sta->addr, nss); + + err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, + WMI_PEER_NSS, nss); + if (err) + ath10k_warn("failed to update STA %pM nss %d: %d\n", + sta->addr, nss, err); + } + + if (changed & IEEE80211_RC_SMPS_CHANGED) { + ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM smps %d\n", + sta->addr, smps); + + err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, + WMI_PEER_SMPS_STATE, smps); + if (err) + ath10k_warn("failed to update STA %pM smps %d: %d\n", + sta->addr, smps, err); + } + + mutex_unlock(&ar->conf_mutex); +} + static int ath10k_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -3112,9 +3175,15 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, { struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; int max_num_peers; int ret = 0; + /* cancel must be done outside the mutex to avoid deadlock */ + if ((old_state == IEEE80211_STA_NONE && + new_state == IEEE80211_STA_NOTEXIST)) + cancel_work_sync(&arsta->update_wk); + mutex_lock(&ar->conf_mutex); if (old_state == IEEE80211_STA_NOTEXIST && @@ -3139,6 +3208,10 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, "mac vdev %d peer create %pM (new sta) num_peers %d\n", arvif->vdev_id, sta->addr, ar->num_peers); + memset(arsta, 0, sizeof(*arsta)); + arsta->arvif = arvif; + INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk); + ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr); if (ret) ath10k_warn("Failed to add peer %pM for vdev %d when adding a new sta: %i\n", @@ -3905,6 +3978,88 @@ static void ath10k_channel_switch_beacon(struct ieee80211_hw *hw, return; } +static void ath10k_sta_rc_update(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + u32 changed) +{ + struct ath10k *ar = hw->priv; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + u32 bw, smps; + + spin_lock_bh(&ar->data_lock); + + ath10k_dbg(ATH10K_DBG_MAC, + "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n", + sta->addr, changed, sta->bandwidth, sta->rx_nss, + sta->smps_mode); + + if (changed & IEEE80211_RC_BW_CHANGED) { + bw = WMI_PEER_CHWIDTH_20MHZ; + + switch (sta->bandwidth) { + case IEEE80211_STA_RX_BW_20: + bw = WMI_PEER_CHWIDTH_20MHZ; + break; + case IEEE80211_STA_RX_BW_40: + bw = WMI_PEER_CHWIDTH_40MHZ; + break; + case IEEE80211_STA_RX_BW_80: + bw = WMI_PEER_CHWIDTH_80MHZ; + break; + case IEEE80211_STA_RX_BW_160: + ath10k_warn("mac sta rc update for %pM: invalid bw %d\n", + sta->addr, sta->bandwidth); + bw = WMI_PEER_CHWIDTH_20MHZ; + break; + } + + arsta->bw = bw; + } + + if (changed & IEEE80211_RC_NSS_CHANGED) + arsta->nss = sta->rx_nss; + + if (changed & IEEE80211_RC_SMPS_CHANGED) { + smps = WMI_PEER_SMPS_PS_NONE; + + switch (sta->smps_mode) { + case IEEE80211_SMPS_AUTOMATIC: + case IEEE80211_SMPS_OFF: + smps = WMI_PEER_SMPS_PS_NONE; + break; + case IEEE80211_SMPS_STATIC: + smps = WMI_PEER_SMPS_STATIC; + break; + case IEEE80211_SMPS_DYNAMIC: + smps = WMI_PEER_SMPS_DYNAMIC; + break; + case IEEE80211_SMPS_NUM_MODES: + ath10k_warn("mac sta rc update for %pM: invalid smps: %d\n", + sta->addr, sta->smps_mode); + smps = WMI_PEER_SMPS_PS_NONE; + break; + } + + arsta->smps = smps; + } + + if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { + /* FIXME: Not implemented. Probably the only way to do it would + * be to re-assoc the peer. */ + changed &= ~IEEE80211_RC_SUPP_RATES_CHANGED; + ath10k_dbg(ATH10K_DBG_MAC, + "mac sta rc update for %pM: changing supported rates not implemented\n", + sta->addr); + } + + arsta->changed |= changed; + + spin_unlock_bh(&ar->data_lock); + + ieee80211_queue_work(hw, &arsta->update_wk); +} + static const struct ieee80211_ops ath10k_ops = { .tx = ath10k_tx, .start = ath10k_start, @@ -3929,6 +4084,7 @@ static const struct ieee80211_ops ath10k_ops = { .get_survey = ath10k_get_survey, .set_bitrate_mask = ath10k_set_bitrate_mask, .channel_switch_beacon = ath10k_channel_switch_beacon, + .sta_rc_update = ath10k_sta_rc_update, #ifdef CONFIG_PM .suspend = ath10k_suspend, .resume = ath10k_resume, @@ -4304,6 +4460,7 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN; ar->hw->vif_data_size = sizeof(struct ath10k_vif); + ar->hw->sta_data_size = sizeof(struct ath10k_sta); ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index fc1093a51ab1..4fcc96aa9513 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3876,6 +3876,12 @@ enum wmi_peer_smps_state { WMI_PEER_SMPS_DYNAMIC = 0x2 }; +enum wmi_peer_chwidth { + WMI_PEER_CHWIDTH_20MHZ = 0, + WMI_PEER_CHWIDTH_40MHZ = 1, + WMI_PEER_CHWIDTH_80MHZ = 2, +}; + enum wmi_peer_param { WMI_PEER_SMPS_STATE = 0x1, /* see %wmi_peer_smps_state */ WMI_PEER_AMPDU = 0x2, From 9113bfd82dc8ece9cbb898df8794f58a78a36e97 Mon Sep 17 00:00:00 2001 From: Jurgen Kramer Date: Sat, 15 Feb 2014 12:01:09 +0100 Subject: [PATCH 141/414] Bluetooth: btusb: Add IMC Networks (Broadcom based) Add support for IMC Networks (Broadcom based) to btusb driver. Below the output of /sys/kernel/debug/usb/devices for this device: T: Bus=01 Lev=02 Prnt=02 Port=04 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=13d3 ProdID=3404 Rev= 1.12 S: Manufacturer=Broadcom Corp S: Product=BCM20702A0 S: SerialNumber=240A649F8246 C:* #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr= 0mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) E: Ad=84(I) Atr=02(Bulk) MxPS= 32 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS= 32 Ivl=0ms I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none) Signed-off-by: Jurgen Kramer Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 5926a9db44b4..e5680fa173c2 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -116,6 +116,9 @@ static const struct usb_device_id btusb_table[] = { /* Belkin F8065bf - Broadcom based */ { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) }, + /* IMC Networks - Broadcom based */ + { USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01) }, + { } /* Terminating entry */ }; From 490cb0b318a0619ae545e63d6773f01caf29d4a0 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 16 Feb 2014 12:59:05 -0800 Subject: [PATCH 142/414] Bluetooth: Restrict long term keys to public and static addresses The long term keys should be associated with an identity address. Valid identity addresses are public addresses or static addresses. So only allow these two as valid address information for long term keys. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ce7ef339b1c4..70bef3d5db57 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4162,9 +4162,19 @@ static bool ltk_is_valid(struct mgmt_ltk_info *key) { if (key->master != 0x00 && key->master != 0x01) return false; - if (!bdaddr_type_is_le(key->addr.type)) - return false; - return true; + + switch (key->addr.type) { + case BDADDR_LE_PUBLIC: + return true; + + case BDADDR_LE_RANDOM: + /* Two most significant bits shall be set */ + if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0) + return false; + return true; + } + + return false; } static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, From 0fe442ff854b7bf93e57c7f3964b05a6438de3db Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 16 Feb 2014 12:59:06 -0800 Subject: [PATCH 143/414] Bluetooth: Fix sending wrong store hint for new long term keys The long term keys should only be stored when they belong to an indentity address. The identity address can either be a public address or a random static address. For all other addresses (unresovable or resolvable) tell userspace that the long term key is not persistent. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e7746690d620..58d2f9bf241f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2685,6 +2685,7 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, { struct smp_ltk *key, *old_key; bool master = ltk_type_master(type); + u8 persistent; old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type, master); if (old_key) @@ -2708,8 +2709,13 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, if (!new_key) return 0; + if (addr_type == ADDR_LE_DEV_RANDOM && (bdaddr->b[5] & 0xc0) != 0xc0) + persistent = 0; + else + persistent = 1; + if (type == HCI_SMP_LTK || type == HCI_SMP_LTK_SLAVE) - mgmt_new_ltk(hdev, key, 1); + mgmt_new_ltk(hdev, key, persistent); return 0; } From c6521401d668538784e27d5746e7035fcf1107a8 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 17 Feb 2014 09:21:18 -0800 Subject: [PATCH 144/414] Bluetooth: Add missing index added event on user channel failure When the setup of user channel fails, the index added event is not sent and will cause issues with user interaction. This problem can be easily triggered with a LE only controller without a public address. In that case hci_dev_open() fails and that error case is not sending an event saying that the controller is available for normal use again. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 7552f9e3089c..68e51a84e72d 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -716,6 +716,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, err = hci_dev_open(hdev->id); if (err) { clear_bit(HCI_USER_CHANNEL, &hdev->dev_flags); + mgmt_index_added(hdev); hci_dev_put(hdev); goto done; } From c6beca0e0dc70c439894337e82609ec3b79ed900 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 17 Feb 2014 09:21:19 -0800 Subject: [PATCH 145/414] Bluetooth: Allow HCI User Channel usage for controllers without address Trying to setup HCI User Channel usage for LE only controllers without a public address or configured static address will fail with an error saying that no address is available. In case of HCI User Channel the requirement for a valid address is not needed. So allow skipping this extra validation step. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 58d2f9bf241f..b40d52446f8f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1937,10 +1937,15 @@ static int hci_dev_do_open(struct hci_dev *hdev) * be able to determine if there is a public address * or not. * + * In case of user channel usage, it is not important + * if a public address or static random address is + * available. + * * This check is only valid for BR/EDR controllers * since AMP controllers do not have an address. */ - if (hdev->dev_type == HCI_BREDR && + if (!test_bit(HCI_USER_CHANNEL, &hdev->dev_flags) && + hdev->dev_type == HCI_BREDR && !bacmp(&hdev->bdaddr, BDADDR_ANY) && !bacmp(&hdev->static_addr, BDADDR_ANY)) { ret = -EADDRNOTAVAIL; From c46b98bea5691c0ed99da85cf0cb87bc146468e9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 10:19:29 +0200 Subject: [PATCH 146/414] Bluetooth: Fix missing PDU length checks for SMP For each received SMP PDU we need to check that we have enough data to fit the specified size of the PDU. This patch adds the necessary checks for each SMP PDU handler and ensures that buffer overflows do not occur if to little data has been received. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index efe51ccdc615..1730bb2b6259 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -565,6 +565,9 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); + if (skb->len < sizeof(*req)) + return SMP_UNSPECIFIED; + if (conn->hcon->link_mode & HCI_LM_MASTER) return SMP_CMD_NOTSUPP; @@ -617,6 +620,9 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); + if (skb->len < sizeof(*rsp)) + return SMP_UNSPECIFIED; + if (!(conn->hcon->link_mode & HCI_LM_MASTER)) return SMP_CMD_NOTSUPP; @@ -661,6 +667,9 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); + if (skb->len < sizeof(smp->pcnf)) + return SMP_UNSPECIFIED; + memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf)); skb_pull(skb, sizeof(smp->pcnf)); @@ -686,6 +695,9 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); + if (skb->len < sizeof(smp->rrnd)) + return SMP_UNSPECIFIED; + swap128(skb->data, smp->rrnd); skb_pull(skb, sizeof(smp->rrnd)); @@ -725,6 +737,9 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); + if (skb->len < sizeof(*rp)) + return SMP_UNSPECIFIED; + if (!(conn->hcon->link_mode & HCI_LM_MASTER)) return SMP_CMD_NOTSUPP; @@ -814,6 +829,11 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb) struct smp_cmd_encrypt_info *rp = (void *) skb->data; struct smp_chan *smp = conn->smp_chan; + BT_DBG("conn %p", conn); + + if (skb->len < sizeof(*rp)) + return SMP_UNSPECIFIED; + skb_pull(skb, sizeof(*rp)); memcpy(smp->tk, rp->ltk, sizeof(smp->tk)); @@ -829,6 +849,11 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) struct hci_conn *hcon = conn->hcon; u8 authenticated; + BT_DBG("conn %p", conn); + + if (skb->len < sizeof(*rp)) + return SMP_UNSPECIFIED; + skb_pull(skb, sizeof(*rp)); hci_dev_lock(hdev); From 6bfdfe3cd68d5a797e0ebfb57068fe7f9c20c93a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 10:19:30 +0200 Subject: [PATCH 147/414] Bluetooth: Fix minor whitespace issues in SMP code This patch fixes a couple of unnecessary empty lines in the SMP code. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 1 - net/bluetooth/smp.h | 1 - 2 files changed, 2 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 1730bb2b6259..ae487e17380e 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -990,7 +990,6 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) *keydist &= req->resp_key_dist; } - BT_DBG("keydist 0x%x", *keydist); if (*keydist & SMP_DIST_ENC_KEY) { diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index a700bcb490d7..777ee93a6c9b 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -132,7 +132,6 @@ struct smp_chan { struct crypto_blkcipher *tfm; struct work_struct confirm; struct work_struct random; - }; /* SMP Commands */ From 60478054a6af7aa8cceb8218d29d27f165f1c9d3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 10:19:31 +0200 Subject: [PATCH 148/414] Bluetooth: Add smp_irk_matches helper function This patch adds a helper function to check whether a given IRK matches a given Resolvable Private Address (RPA). The function will be needed for implementing the rest of address resolving support. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 46 +++++++++++++++++++++++++++++++++++++++++++++ net/bluetooth/smp.h | 3 +++ 2 files changed, 49 insertions(+) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index ae487e17380e..5f500b479f45 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -78,6 +78,52 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) return err; } +static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3]) +{ + u8 _res[16], k[16]; + int err; + + /* r' = padding || r */ + memset(_res, 0, 13); + _res[13] = r[2]; + _res[14] = r[1]; + _res[15] = r[0]; + + swap128(irk, k); + err = smp_e(tfm, k, _res); + if (err) { + BT_ERR("Encrypt error"); + return err; + } + + /* The output of the random address function ah is: + * ah(h, r) = e(k, r') mod 2^24 + * The output of the security function e is then truncated to 24 bits + * by taking the least significant 24 bits of the output of e as the + * result of ah. + */ + res[0] = _res[15]; + res[1] = _res[14]; + res[2] = _res[13]; + + return 0; +} + +bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16], + bdaddr_t *bdaddr) +{ + u8 hash[3]; + int err; + + BT_DBG("RPA %pMR IRK %*phN", bdaddr, 16, irk); + + err = smp_ah(tfm, irk, &bdaddr->b[3], hash); + if (err) + return false; + + return !memcmp(bdaddr->b, hash, 3); +} + static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16], u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia, u8 _rat, bdaddr_t *ra, u8 res[16]) diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 777ee93a6c9b..950d039c2ea2 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -143,4 +143,7 @@ int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey); void smp_chan_destroy(struct l2cap_conn *conn); +bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16], + bdaddr_t *bdaddr); + #endif /* __SMP_H */ From 99780a7b639e73d8f8f291fa1a981db883aec47f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 10:40:07 +0200 Subject: [PATCH 149/414] Bluetooth: Add AES crypto context for each HCI device Previously the crypto context has only been available for LE SMP sessions, but now that we'll need to perform operations also during discovery it makes sense to have this context part of the hci_dev struct. Later, the context can be removed from the SMP context. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 92fa75fce29d..b344890b18f5 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -259,6 +259,7 @@ struct hci_dev { __u32 req_status; __u32 req_result; + struct crypto_blkcipher *tfm_aes; struct discovery_state discovery; struct hci_conn_hash conn_hash; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b40d52446f8f..df25af5502ef 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -3205,9 +3206,18 @@ int hci_register_dev(struct hci_dev *hdev) dev_set_name(&hdev->dev, "%s", hdev->name); + hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(hdev->tfm_aes)) { + BT_ERR("Unable to create crypto context"); + error = PTR_ERR(hdev->tfm_aes); + hdev->tfm_aes = NULL; + goto err_wqueue; + } + error = device_add(&hdev->dev); if (error < 0) - goto err_wqueue; + goto err_tfm; hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev, RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, @@ -3243,6 +3253,8 @@ int hci_register_dev(struct hci_dev *hdev) return id; +err_tfm: + crypto_free_blkcipher(hdev->tfm_aes); err_wqueue: destroy_workqueue(hdev->workqueue); destroy_workqueue(hdev->req_workqueue); @@ -3293,6 +3305,9 @@ void hci_unregister_dev(struct hci_dev *hdev) rfkill_destroy(hdev->rfkill); } + if (hdev->tfm_aes) + crypto_free_blkcipher(hdev->tfm_aes); + device_del(&hdev->dev); debugfs_remove_recursive(hdev->debugfs); From 970c4e46037ab8ece3940afc9fcf916d3ed7e003 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 10:19:33 +0200 Subject: [PATCH 150/414] Bluetooth: Add basic IRK management support This patch adds the initial IRK storage and management functions to the HCI core. This includes storing a list of IRKs per HCI device and the ability to add, remove and lookup entries in that list. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 16 ++++++++ net/bluetooth/hci_core.c | 70 ++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b344890b18f5..eac422337582 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -103,6 +103,14 @@ struct smp_ltk { u8 val[16]; }; +struct smp_irk { + struct list_head list; + bdaddr_t rpa; + bdaddr_t bdaddr; + u8 addr_type; + u8 val[16]; +}; + struct link_key { struct list_head list; bdaddr_t bdaddr; @@ -269,6 +277,7 @@ struct hci_dev { struct list_head uuids; struct list_head link_keys; struct list_head long_term_keys; + struct list_head identity_resolving_keys; struct list_head remote_oob_data; struct list_head le_conn_params; @@ -787,6 +796,13 @@ int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_smp_ltks_clear(struct hci_dev *hdev); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); +struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa); +struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 addr_type); +int hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, + u8 val[16], bdaddr_t *rpa); +void hci_smp_irks_clear(struct hci_dev *hdev); + int hci_remote_oob_data_clear(struct hci_dev *hdev); struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index df25af5502ef..59a76b2566eb 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -35,6 +35,8 @@ #include #include +#include "smp.h" + static void hci_rx_work(struct work_struct *work); static void hci_cmd_work(struct work_struct *work); static void hci_tx_work(struct work_struct *work); @@ -2544,6 +2546,16 @@ int hci_smp_ltks_clear(struct hci_dev *hdev) return 0; } +void hci_smp_irks_clear(struct hci_dev *hdev) +{ + struct smp_irk *k, *tmp; + + list_for_each_entry_safe(k, tmp, &hdev->identity_resolving_keys, list) { + list_del(&k->list); + kfree(k); + } +} + struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) { struct link_key *k; @@ -2632,6 +2644,39 @@ struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, return NULL; } +struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa) +{ + struct smp_irk *irk; + + list_for_each_entry(irk, &hdev->identity_resolving_keys, list) { + if (!bacmp(&irk->rpa, rpa)) + return irk; + } + + list_for_each_entry(irk, &hdev->identity_resolving_keys, list) { + if (smp_irk_matches(hdev->tfm_aes, irk->val, rpa)) { + bacpy(&irk->rpa, rpa); + return irk; + } + } + + return NULL; +} + +struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 addr_type) +{ + struct smp_irk *irk; + + list_for_each_entry(irk, &hdev->identity_resolving_keys, list) { + if (addr_type == irk->addr_type && + bacmp(bdaddr, &irk->bdaddr) == 0) + return irk; + } + + return NULL; +} + int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) { @@ -2726,6 +2771,29 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, return 0; } +int hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, + u8 val[16], bdaddr_t *rpa) +{ + struct smp_irk *irk; + + irk = hci_find_irk_by_addr(hdev, bdaddr, addr_type); + if (!irk) { + irk = kzalloc(sizeof(*irk), GFP_KERNEL); + if (!irk) + return -ENOMEM; + + bacpy(&irk->bdaddr, bdaddr); + irk->addr_type = addr_type; + + list_add(&irk->list, &hdev->identity_resolving_keys); + } + + memcpy(irk->val, val, 16); + bacpy(&irk->rpa, rpa); + + return 0; +} + int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) { struct link_key *key; @@ -3120,6 +3188,7 @@ struct hci_dev *hci_alloc_dev(void) INIT_LIST_HEAD(&hdev->uuids); INIT_LIST_HEAD(&hdev->link_keys); INIT_LIST_HEAD(&hdev->long_term_keys); + INIT_LIST_HEAD(&hdev->identity_resolving_keys); INIT_LIST_HEAD(&hdev->remote_oob_data); INIT_LIST_HEAD(&hdev->le_conn_params); INIT_LIST_HEAD(&hdev->conn_hash.list); @@ -3320,6 +3389,7 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_uuids_clear(hdev); hci_link_keys_clear(hdev); hci_smp_ltks_clear(hdev); + hci_smp_irks_clear(hdev); hci_remote_oob_data_clear(hdev); hci_conn_params_clear(hdev); hci_dev_unlock(hdev); From 301cb2d85eb89140eaff8c22066a4bfd774960a3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 10:19:34 +0200 Subject: [PATCH 151/414] Bluetooth: Add hci_bdaddr_is_rpa convenience function When implementing support for Resolvable Private Addresses (RPAs) we'll need to in several places be able to identify such addresses. This patch adds a simple convenience function to do the identification of the address type. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index eac422337582..86ea4bab9e77 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1071,6 +1071,17 @@ static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type) return false; } +static inline bool hci_bdaddr_is_rpa(bdaddr_t *bdaddr, u8 addr_type) +{ + if (addr_type != 0x01) + return false; + + if ((bdaddr->b[5] & 0xc0) == 0x40) + return true; + + return false; +} + int hci_register_cb(struct hci_cb *hcb); int hci_unregister_cb(struct hci_cb *hcb); From 41edf1601af3b25461d91e73834dc89510bca8e5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 10:19:35 +0200 Subject: [PATCH 152/414] Bluetooth: Implement mgmt_load_irks command This patch implements the Load IRKs command for the management interface. The command is used to load the kernel with the initial set of IRKs. It also sets a HCI_RPA_RESOLVING flag to indicate that we can start requesting devices to distribute their IRK to us. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/mgmt.h | 12 ++++++ net/bluetooth/mgmt.c | 79 ++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 352d3d7d06bb..d3a8fff50f69 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -125,6 +125,7 @@ enum { HCI_SSP_ENABLED, HCI_SC_ENABLED, HCI_SC_ONLY, + HCI_RPA_RESOLVING, HCI_HS_ENABLED, HCI_LE_ENABLED, HCI_ADVERTISING, diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 4303fa90b7c1..e4fa13e559e2 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -389,6 +389,18 @@ struct mgmt_cp_set_scan_params { #define MGMT_OP_SET_DEBUG_KEYS 0x002E +struct mgmt_irk_info { + struct mgmt_addr_info addr; + __u8 val[16]; +} __packed; + +#define MGMT_OP_LOAD_IRKS 0x0030 +struct mgmt_cp_load_irks { + __le16 irk_count; + struct mgmt_irk_info irks[0]; +} __packed; +#define MGMT_LOAD_IRKS_SIZE 2 + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 70bef3d5db57..782e2bb10881 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -81,6 +81,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_SET_SCAN_PARAMS, MGMT_OP_SET_SECURE_CONN, MGMT_OP_SET_DEBUG_KEYS, + MGMT_OP_LOAD_IRKS, }; static const u16 mgmt_events[] = { @@ -4158,6 +4159,82 @@ unlock: return err; } +static bool irk_is_valid(struct mgmt_irk_info *irk) +{ + switch (irk->addr.type) { + case BDADDR_LE_PUBLIC: + return true; + + case BDADDR_LE_RANDOM: + /* Two most significant bits shall be set */ + if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0) + return false; + return true; + } + + return false; +} + +static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data, + u16 len) +{ + struct mgmt_cp_load_irks *cp = cp_data; + u16 irk_count, expected_len; + int i, err; + + BT_DBG("request for %s", hdev->name); + + if (!lmp_le_capable(hdev)) + return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS, + MGMT_STATUS_NOT_SUPPORTED); + + irk_count = __le16_to_cpu(cp->irk_count); + + expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info); + if (expected_len != len) { + BT_ERR("load_irks: expected %u bytes, got %u bytes", + len, expected_len); + return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS, + MGMT_STATUS_INVALID_PARAMS); + } + + BT_DBG("%s irk_count %u", hdev->name, irk_count); + + for (i = 0; i < irk_count; i++) { + struct mgmt_irk_info *key = &cp->irks[i]; + + if (!irk_is_valid(key)) + return cmd_status(sk, hdev->id, + MGMT_OP_LOAD_IRKS, + MGMT_STATUS_INVALID_PARAMS); + } + + hci_dev_lock(hdev); + + hci_smp_irks_clear(hdev); + + for (i = 0; i < irk_count; i++) { + struct mgmt_irk_info *irk = &cp->irks[i]; + u8 addr_type; + + if (irk->addr.type == BDADDR_LE_PUBLIC) + addr_type = ADDR_LE_DEV_PUBLIC; + else + addr_type = ADDR_LE_DEV_RANDOM; + + hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val, + BDADDR_ANY); + } + + set_bit(HCI_RPA_RESOLVING, &hdev->dev_flags); + + err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0); + + hci_dev_unlock(hdev); + + return err; +} + static bool ltk_is_valid(struct mgmt_ltk_info *key) { if (key->master != 0x00 && key->master != 0x01) @@ -4296,6 +4373,8 @@ static const struct mgmt_handler { { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE }, { set_secure_conn, false, MGMT_SETTING_SIZE }, { set_debug_keys, false, MGMT_SETTING_SIZE }, + { }, + { load_irks, true, MGMT_LOAD_IRKS_SIZE }, }; From fd349c020c5b6f7a6e17cb8b4e821ff9b6f71ba6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 10:19:36 +0200 Subject: [PATCH 153/414] Bluetooth: Enable support for remote IRK distribution This patch does the necessary changes to request the remote device to distribute its IRK to us during the SMP pairing procedure. This includes setting the right key distribution values in the pairing request/response and handling of the two related SMP PDUs, i.e. Identity Information and Identity Address Information. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 80 +++++++++++++++++++++++++++++++++++++++++---- net/bluetooth/smp.h | 4 +++ 2 files changed, 77 insertions(+), 7 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 5f500b479f45..024baa789eb9 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -249,31 +249,42 @@ static void build_pairing_cmd(struct l2cap_conn *conn, struct smp_cmd_pairing *req, struct smp_cmd_pairing *rsp, __u8 authreq) { - u8 dist_keys = 0; + struct smp_chan *smp = conn->smp_chan; + struct hci_conn *hcon = conn->hcon; + struct hci_dev *hdev = hcon->hdev; + u8 local_dist = 0, remote_dist = 0; if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->dev_flags)) { - dist_keys = SMP_DIST_ENC_KEY; + local_dist = SMP_DIST_ENC_KEY; + remote_dist = SMP_DIST_ENC_KEY; authreq |= SMP_AUTH_BONDING; } else { authreq &= ~SMP_AUTH_BONDING; } + if (test_bit(HCI_RPA_RESOLVING, &hdev->dev_flags)) + remote_dist |= SMP_DIST_ID_KEY; + if (rsp == NULL) { req->io_capability = conn->hcon->io_capability; req->oob_flag = SMP_OOB_NOT_PRESENT; req->max_key_size = SMP_MAX_ENC_KEY_SIZE; - req->init_key_dist = dist_keys; - req->resp_key_dist = dist_keys; + req->init_key_dist = local_dist; + req->resp_key_dist = remote_dist; req->auth_req = (authreq & AUTH_REQ_MASK); + + smp->remote_key_dist = remote_dist; return; } rsp->io_capability = conn->hcon->io_capability; rsp->oob_flag = SMP_OOB_NOT_PRESENT; rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE; - rsp->init_key_dist = req->init_key_dist & dist_keys; - rsp->resp_key_dist = req->resp_key_dist & dist_keys; + rsp->init_key_dist = req->init_key_dist & remote_dist; + rsp->resp_key_dist = req->resp_key_dist & local_dist; rsp->auth_req = (authreq & AUTH_REQ_MASK); + + smp->remote_key_dist = rsp->init_key_dist; } static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) @@ -907,12 +918,61 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK, 1, authenticated, smp->tk, smp->enc_key_size, rp->ediv, rp->rand); - smp_distribute_keys(conn, 1); + if (!(smp->remote_key_dist & SMP_DIST_ID_KEY)) + smp_distribute_keys(conn, 1); hci_dev_unlock(hdev); return 0; } +static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb) +{ + struct smp_cmd_ident_info *info = (void *) skb->data; + struct smp_chan *smp = conn->smp_chan; + + BT_DBG(""); + + if (skb->len < sizeof(*info)) + return SMP_UNSPECIFIED; + + skb_pull(skb, sizeof(*info)); + + memcpy(smp->irk, info->irk, 16); + + return 0; +} + +static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, + struct sk_buff *skb) +{ + struct smp_cmd_ident_addr_info *info = (void *) skb->data; + struct smp_chan *smp = conn->smp_chan; + struct hci_conn *hcon = conn->hcon; + bdaddr_t rpa; + + BT_DBG(""); + + if (skb->len < sizeof(*info)) + return SMP_UNSPECIFIED; + + skb_pull(skb, sizeof(*info)); + + bacpy(&smp->id_addr, &info->bdaddr); + smp->id_addr_type = info->addr_type; + + if (hci_bdaddr_is_rpa(&hcon->dst, hcon->dst_type)) + bacpy(&rpa, &hcon->dst); + else + bacpy(&rpa, BDADDR_ANY); + + hci_add_irk(conn->hcon->hdev, &smp->id_addr, smp->id_addr_type, + smp->irk, &rpa); + + smp_distribute_keys(conn, 1); + + return 0; +} + int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) { struct hci_conn *hcon = conn->hcon; @@ -987,7 +1047,13 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) break; case SMP_CMD_IDENT_INFO: + reason = smp_cmd_ident_info(conn, skb); + break; + case SMP_CMD_IDENT_ADDR_INFO: + reason = smp_cmd_ident_addr_info(conn, skb); + break; + case SMP_CMD_SIGN_INFO: /* Just ignored */ reason = 0; diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 950d039c2ea2..4f373bc56ad7 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -128,6 +128,10 @@ struct smp_chan { u8 pcnf[16]; /* SMP Pairing Confirm */ u8 tk[16]; /* SMP Temporary Key */ u8 enc_key_size; + u8 remote_key_dist; + bdaddr_t id_addr; + u8 id_addr_type; + u8 irk[16]; unsigned long smp_flags; struct crypto_blkcipher *tfm; struct work_struct confirm; From 6131ddc8eb9bad8c4ff37e097b2537c819b76cc0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 10:19:37 +0200 Subject: [PATCH 154/414] Bluetooth: Fix properly ignoring unexpected SMP PDUs If we didn't request certain pieces of information during the key distribution negotiation we should properly ignore those PDUs if the peer incorrectly sends them. This includes the Encryption Information and Master Identification PDUs if the EncKey bit was not set, and the Identity Information and Identity Address Information PDUs if the IdKey bit was not set. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 024baa789eb9..5867c1c3f436 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -891,6 +891,10 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*rp)) return SMP_UNSPECIFIED; + /* Ignore this PDU if it wasn't requested */ + if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY)) + return 0; + skb_pull(skb, sizeof(*rp)); memcpy(smp->tk, rp->ltk, sizeof(smp->tk)); @@ -911,6 +915,10 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*rp)) return SMP_UNSPECIFIED; + /* Ignore this PDU if it wasn't requested */ + if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY)) + return 0; + skb_pull(skb, sizeof(*rp)); hci_dev_lock(hdev); @@ -935,6 +943,10 @@ static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*info)) return SMP_UNSPECIFIED; + /* Ignore this PDU if it wasn't requested */ + if (!(smp->remote_key_dist & SMP_DIST_ID_KEY)) + return 0; + skb_pull(skb, sizeof(*info)); memcpy(smp->irk, info->irk, 16); @@ -955,6 +967,10 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, if (skb->len < sizeof(*info)) return SMP_UNSPECIFIED; + /* Ignore this PDU if it wasn't requested */ + if (!(smp->remote_key_dist & SMP_DIST_ID_KEY)) + return 0; + skb_pull(skb, sizeof(*info)); bacpy(&smp->id_addr, &info->bdaddr); From e0b2b27e622da0ba8a3d253b985d3d8f174b4313 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 17:14:31 +0200 Subject: [PATCH 155/414] Bluetooth: Fix missing address type check for removing LTKs When removing Long Term Keys we should also be checking that the given address type (public vs random) matches. This patch updates the hci_remove_ltk function to take an extra parameter and uses it for address type matching. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 4 ++-- net/bluetooth/mgmt.c | 14 +++++++++++--- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 86ea4bab9e77..ab94abdeb3c1 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -792,7 +792,7 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, __le16 ediv, u8 rand[8]); struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, bool master); -int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr); +int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type); int hci_smp_ltks_clear(struct hci_dev *hdev); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 59a76b2566eb..957c8f4cc4c7 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2810,12 +2810,12 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) return 0; } -int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr) +int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type) { struct smp_ltk *k, *tmp; list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) { - if (bacmp(bdaddr, &k->bdaddr)) + if (bacmp(bdaddr, &k->bdaddr) || k->bdaddr_type != bdaddr_type) continue; BT_DBG("%s removing %pMR", hdev->name, bdaddr); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 782e2bb10881..473f8687b28b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2318,10 +2318,18 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, goto unlock; } - if (cp->addr.type == BDADDR_BREDR) + if (cp->addr.type == BDADDR_BREDR) { err = hci_remove_link_key(hdev, &cp->addr.bdaddr); - else - err = hci_remove_ltk(hdev, &cp->addr.bdaddr); + } else { + u8 addr_type; + + if (cp->addr.type == BDADDR_LE_PUBLIC) + addr_type = ADDR_LE_DEV_PUBLIC; + else + addr_type = ADDR_LE_DEV_RANDOM; + + err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type); + } if (err < 0) { err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, From 35f7498a87794ca531335f7c782e5b9495fec6d6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 17:14:32 +0200 Subject: [PATCH 156/414] Bluetooth: Remove return values from functions that don't need them There are many functions that never fail but still declare an integer return value for no reason. This patch converts these functions to use a void return value to avoid any confusion of whether they can fail or not. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 10 +++++----- net/bluetooth/hci_core.c | 26 +++++++++----------------- net/bluetooth/mgmt.c | 2 +- 3 files changed, 15 insertions(+), 23 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ab94abdeb3c1..964a7888ad0c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -768,7 +768,7 @@ int hci_inquiry(void __user *arg); struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); -int hci_blacklist_clear(struct hci_dev *hdev); +void hci_blacklist_clear(struct hci_dev *hdev); int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); @@ -779,9 +779,9 @@ void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); void hci_conn_params_clear(struct hci_dev *hdev); -int hci_uuids_clear(struct hci_dev *hdev); +void hci_uuids_clear(struct hci_dev *hdev); -int hci_link_keys_clear(struct hci_dev *hdev); +void hci_link_keys_clear(struct hci_dev *hdev); struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); @@ -793,7 +793,7 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, bool master); int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type); -int hci_smp_ltks_clear(struct hci_dev *hdev); +void hci_smp_ltks_clear(struct hci_dev *hdev); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa); @@ -803,7 +803,7 @@ int hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 val[16], bdaddr_t *rpa); void hci_smp_irks_clear(struct hci_dev *hdev); -int hci_remote_oob_data_clear(struct hci_dev *hdev); +void hci_remote_oob_data_clear(struct hci_dev *hdev); struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 957c8f4cc4c7..fd5bb4086613 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2506,7 +2506,7 @@ static void hci_discov_off(struct work_struct *work) mgmt_discoverable_timeout(hdev); } -int hci_uuids_clear(struct hci_dev *hdev) +void hci_uuids_clear(struct hci_dev *hdev) { struct bt_uuid *uuid, *tmp; @@ -2514,11 +2514,9 @@ int hci_uuids_clear(struct hci_dev *hdev) list_del(&uuid->list); kfree(uuid); } - - return 0; } -int hci_link_keys_clear(struct hci_dev *hdev) +void hci_link_keys_clear(struct hci_dev *hdev) { struct list_head *p, *n; @@ -2530,11 +2528,9 @@ int hci_link_keys_clear(struct hci_dev *hdev) list_del(p); kfree(key); } - - return 0; } -int hci_smp_ltks_clear(struct hci_dev *hdev) +void hci_smp_ltks_clear(struct hci_dev *hdev) { struct smp_ltk *k, *tmp; @@ -2542,8 +2538,6 @@ int hci_smp_ltks_clear(struct hci_dev *hdev) list_del(&k->list); kfree(k); } - - return 0; } void hci_smp_irks_clear(struct hci_dev *hdev) @@ -2873,7 +2867,7 @@ int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr) return 0; } -int hci_remote_oob_data_clear(struct hci_dev *hdev) +void hci_remote_oob_data_clear(struct hci_dev *hdev) { struct oob_data *data, *n; @@ -2881,8 +2875,6 @@ int hci_remote_oob_data_clear(struct hci_dev *hdev) list_del(&data->list); kfree(data); } - - return 0; } int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, @@ -2951,7 +2943,7 @@ struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, return NULL; } -int hci_blacklist_clear(struct hci_dev *hdev) +void hci_blacklist_clear(struct hci_dev *hdev) { struct list_head *p, *n; @@ -2961,8 +2953,6 @@ int hci_blacklist_clear(struct hci_dev *hdev) list_del(p); kfree(b); } - - return 0; } int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) @@ -2991,8 +2981,10 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) { struct bdaddr_list *entry; - if (!bacmp(bdaddr, BDADDR_ANY)) - return hci_blacklist_clear(hdev); + if (!bacmp(bdaddr, BDADDR_ANY)) { + hci_blacklist_clear(hdev); + return 0; + } entry = hci_blacklist_lookup(hdev, bdaddr, type); if (!entry) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 473f8687b28b..fbb76a0de580 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2073,7 +2073,7 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, } if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { - err = hci_uuids_clear(hdev); + hci_uuids_clear(hdev); if (enable_service_cache(hdev)) { err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, From c51ffa0b2fb23ec19b2d01597506d8c953ed1218 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 17:14:33 +0200 Subject: [PATCH 157/414] Bluetooth: Fix hci_remove_ltk failure when no match is found There is code (in mgmt.c) that depends on the hci_remove_ltk function to fail if no match is found. This patch adds tracking of removed LTKs (there can be up to two: one for master and another for slave) in the hci_remove_ltk function and returns -ENOENT of no matches were found. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index fd5bb4086613..69b7145bfce2 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2807,6 +2807,7 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type) { struct smp_ltk *k, *tmp; + int removed = 0; list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) { if (bacmp(bdaddr, &k->bdaddr) || k->bdaddr_type != bdaddr_type) @@ -2816,9 +2817,10 @@ int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type) list_del(&k->list); kfree(k); + removed++; } - return 0; + return removed ? 0 : -ENOENT; } /* HCI command timer function */ From b7d448d74a09af412d778918415fe2ea4d5c2de4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 17:14:34 +0200 Subject: [PATCH 158/414] Bluetooth: Fix completing SMP as peripheral when no keys are expected When we're the acceptors (peripheral/slave) of an SMP procedure and we've completed distributing our keys we should only stick around waiting for keys from the remote side if any of the initiator distribution bits were actually set. This patch fixes the smp_distribute_keys function to clear the SMP context when this situation occurs. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 5867c1c3f436..0c0dd1b52b66 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1175,7 +1175,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) *keydist &= ~SMP_DIST_SIGN; } - if (conn->hcon->out || force) { + if (conn->hcon->out || force || !(rsp->init_key_dist & 0x07)) { clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); cancel_delayed_work_sync(&conn->security_timer); smp_chan_destroy(conn); From a7ec73386ce2a8ab351ee8ab6a1e5475f72617dc Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 17:14:35 +0200 Subject: [PATCH 159/414] Bluetooth: Fix removing any IRKs when unpairing devices When mgmt_unpair_device is called we should also remove any associated IRKs. This patch adds a hci_remove_irk convenience function and ensures that it's called when mgmt_unpair_device is called. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 15 +++++++++++++++ net/bluetooth/mgmt.c | 2 ++ 3 files changed, 18 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 964a7888ad0c..ac468de11cb7 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -801,6 +801,7 @@ struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type); int hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 val[16], bdaddr_t *rpa); +void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type); void hci_smp_irks_clear(struct hci_dev *hdev); void hci_remote_oob_data_clear(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 69b7145bfce2..cdba4709f012 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2823,6 +2823,21 @@ int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type) return removed ? 0 : -ENOENT; } +void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type) +{ + struct smp_irk *k, *tmp; + + list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) { + if (bacmp(bdaddr, &k->bdaddr) || k->addr_type != addr_type) + continue; + + BT_DBG("%s removing %pMR", hdev->name, bdaddr); + + list_del(&k->list); + kfree(k); + } +} + /* HCI command timer function */ static void hci_cmd_timeout(unsigned long arg) { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index fbb76a0de580..90aac905a98b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2328,6 +2328,8 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, else addr_type = ADDR_LE_DEV_RANDOM; + hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type); + err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type); } From 2426f3a5945ce1dfdb04aaf26748a987be49ff7c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 17:14:36 +0200 Subject: [PATCH 160/414] Bluetooth: Add convenience function for fetching IRKs There are many situations where we need to check if an LE address is an RPA and if so try to look up the IRK for it. To simplify such cases this patch adds a convenience function for the job. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ac468de11cb7..4461c0051228 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1083,6 +1083,15 @@ static inline bool hci_bdaddr_is_rpa(bdaddr_t *bdaddr, u8 addr_type) return false; } +static inline struct smp_irk *hci_get_irk(struct hci_dev *hdev, + bdaddr_t *bdaddr, u8 addr_type) +{ + if (!hci_bdaddr_is_rpa(bdaddr, addr_type)) + return NULL; + + return hci_find_irk_by_rpa(hdev, bdaddr); +} + int hci_register_cb(struct hci_cb *hcb); int hci_unregister_cb(struct hci_cb *hcb); From b075dd40c95d11c2c8690f6c4d6232fc0d9e7f56 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Tue, 18 Feb 2014 02:19:26 -0300 Subject: [PATCH 161/414] Bluetooth: allocate static minor for vhci Commit bfacbb9 (Bluetooth: Use devname:vhci module alias for virtual HCI driver) added the module alias to hci_vhci module so it's possible to create the /dev/vhci node. However creating an alias without specifying the minor doesn't allow us to create the node ahead, triggerring module auto-load when it's first accessed. Starting with depmod from kmod 16 we started to warn if there's a devname alias without specifying the major and minor. Let's do the same done for uhid, kvm, fuse and others, specifying a fixed minor. In systems with systemd as the init the following will happen: on early boot systemd will call "kmod static-nodes" to read /lib/modules/$(uname -r)/modules.devname and then create the nodes. When first accessed these "dead" nodes will trigger the module loading. Signed-off-by: Lucas De Marchi Acked-by: Greg Kroah-Hartman Signed-off-by: Marcel Holtmann --- Documentation/devices.txt | 1 + drivers/bluetooth/hci_vhci.c | 3 ++- include/linux/miscdevice.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devices.txt b/Documentation/devices.txt index 10378cc48374..04356f5bc3af 100644 --- a/Documentation/devices.txt +++ b/Documentation/devices.txt @@ -353,6 +353,7 @@ Your cooperation is appreciated. 133 = /dev/exttrp External device trap 134 = /dev/apm_bios Advanced Power Management BIOS 135 = /dev/rtc Real Time Clock + 137 = /dev/vhci Bluetooth virtual HCI driver 139 = /dev/openprom SPARC OpenBoot PROM 140 = /dev/relay8 Berkshire Products Octal relay card 141 = /dev/relay16 Berkshire Products ISO-16 relay card diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 1ef6990a5c7e..add1c6a72063 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -359,7 +359,7 @@ static const struct file_operations vhci_fops = { static struct miscdevice vhci_miscdev= { .name = "vhci", .fops = &vhci_fops, - .minor = MISC_DYNAMIC_MINOR, + .minor = VHCI_MINOR, }; static int __init vhci_init(void) @@ -385,3 +385,4 @@ MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL"); MODULE_ALIAS("devname:vhci"); +MODULE_ALIAS_MISCDEV(VHCI_MINOR); diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index 3737f7218f51..7bb6148d990f 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -23,6 +23,7 @@ #define TEMP_MINOR 131 /* Temperature Sensor */ #define RTC_MINOR 135 #define EFI_RTC_MINOR 136 /* EFI Time services */ +#define VHCI_MINOR 137 #define SUN_OPENPROM_MINOR 139 #define DMAPI_MINOR 140 /* DMAPI */ #define NVRAM_MINOR 144 From 0b8800623d3f12dd40a039aa191d52bfa4eef5b4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 18 Feb 2014 18:26:19 +0200 Subject: [PATCH 162/414] Bluetooth: sort the list of IDs in the source code This will help to manage table of supported IDs. There is no functional change. Signed-off-by: Andy Shevchenko Signed-off-by: Marcel Holtmann --- drivers/bluetooth/ath3k.c | 80 +++++++++++++++++++-------------------- drivers/bluetooth/btusb.c | 52 ++++++++++++------------- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 41ec6f9a8252..fc93ade5fcac 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -62,52 +62,52 @@ static const struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x0CF3, 0x3000) }, /* Atheros AR3011 with sflash firmware*/ + { USB_DEVICE(0x0489, 0xE027) }, + { USB_DEVICE(0x0489, 0xE03D) }, + { USB_DEVICE(0x0930, 0x0215) }, { USB_DEVICE(0x0CF3, 0x3002) }, { USB_DEVICE(0x0CF3, 0xE019) }, { USB_DEVICE(0x13d3, 0x3304) }, - { USB_DEVICE(0x0930, 0x0215) }, - { USB_DEVICE(0x0489, 0xE03D) }, - { USB_DEVICE(0x0489, 0xE027) }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03F0, 0x311D) }, /* Atheros AR3012 with sflash firmware*/ + { USB_DEVICE(0x0489, 0xe04d) }, + { USB_DEVICE(0x0489, 0xe04e) }, + { USB_DEVICE(0x0489, 0xe057) }, + { USB_DEVICE(0x0489, 0xe056) }, + { USB_DEVICE(0x0489, 0xe05f) }, + { USB_DEVICE(0x04c5, 0x1330) }, + { USB_DEVICE(0x04CA, 0x3004) }, + { USB_DEVICE(0x04CA, 0x3005) }, + { USB_DEVICE(0x04CA, 0x3006) }, + { USB_DEVICE(0x04CA, 0x3008) }, + { USB_DEVICE(0x04CA, 0x300b) }, + { USB_DEVICE(0x0930, 0x0219) }, + { USB_DEVICE(0x0930, 0x0220) }, { USB_DEVICE(0x0CF3, 0x0036) }, { USB_DEVICE(0x0CF3, 0x3004) }, { USB_DEVICE(0x0CF3, 0x3008) }, { USB_DEVICE(0x0CF3, 0x311D) }, { USB_DEVICE(0x0CF3, 0x311E) }, { USB_DEVICE(0x0CF3, 0x311F) }, + { USB_DEVICE(0x0cf3, 0x3121) }, { USB_DEVICE(0x0CF3, 0x817a) }, - { USB_DEVICE(0x13d3, 0x3375) }, - { USB_DEVICE(0x04CA, 0x3004) }, - { USB_DEVICE(0x04CA, 0x3005) }, - { USB_DEVICE(0x04CA, 0x3006) }, - { USB_DEVICE(0x04CA, 0x3008) }, - { USB_DEVICE(0x04CA, 0x300b) }, - { USB_DEVICE(0x13d3, 0x3362) }, + { USB_DEVICE(0x0cf3, 0xe003) }, { USB_DEVICE(0x0CF3, 0xE004) }, { USB_DEVICE(0x0CF3, 0xE005) }, - { USB_DEVICE(0x0930, 0x0219) }, - { USB_DEVICE(0x0930, 0x0220) }, - { USB_DEVICE(0x0489, 0xe057) }, + { USB_DEVICE(0x13d3, 0x3362) }, + { USB_DEVICE(0x13d3, 0x3375) }, { USB_DEVICE(0x13d3, 0x3393) }, - { USB_DEVICE(0x0489, 0xe04e) }, - { USB_DEVICE(0x0489, 0xe056) }, - { USB_DEVICE(0x0489, 0xe04d) }, - { USB_DEVICE(0x04c5, 0x1330) }, { USB_DEVICE(0x13d3, 0x3402) }, - { USB_DEVICE(0x0cf3, 0x3121) }, - { USB_DEVICE(0x0cf3, 0xe003) }, - { USB_DEVICE(0x0489, 0xe05f) }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xE02C) }, /* Atheros AR5BBU22 with sflash firmware */ - { USB_DEVICE(0x0489, 0xE03C) }, { USB_DEVICE(0x0489, 0xE036) }, + { USB_DEVICE(0x0489, 0xE03C) }, { } /* Terminating entry */ }; @@ -120,38 +120,38 @@ MODULE_DEVICE_TABLE(usb, ath3k_table); static const struct usb_device_id ath3k_blist_tbl[] = { /* Atheros AR3012 with sflash firmware*/ + { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311E), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311F), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU22 with sflash firmware */ - { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 }, { } /* Terminating entry */ }; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index e5680fa173c2..46640e98fa03 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -101,16 +101,16 @@ static const struct usb_device_id btusb_table[] = { { USB_DEVICE(0x0c10, 0x0000) }, /* Broadcom BCM20702A0 */ + { USB_DEVICE(0x0489, 0xe042) }, + { USB_DEVICE(0x04ca, 0x2003) }, { USB_DEVICE(0x0b05, 0x17b5) }, { USB_DEVICE(0x0b05, 0x17cb) }, - { USB_DEVICE(0x04ca, 0x2003) }, - { USB_DEVICE(0x0489, 0xe042) }, { USB_DEVICE(0x413c, 0x8197) }, /* Foxconn - Hon Hai */ { USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) }, - /*Broadcom devices with vendor specific id */ + /* Broadcom devices with vendor specific id */ { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) }, /* Belkin F8065bf - Broadcom based */ @@ -132,57 +132,57 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE }, /* Atheros 3011 with sflash firmware */ + { USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE }, + { USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE }, + { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0cf3, 0xe019), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE }, - { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE }, - { USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE }, - { USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE }, /* Atheros 3012 with sflash firmware */ + { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311f), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, /* Atheros AR5BBU12 with sflash firmware */ - { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 }, /* Broadcom BCM2035 */ - { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU }, - { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 }, + { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU }, /* Broadcom BCM2045 */ { USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_WRONG_SCO_MTU }, From a735f9e22432899cee188d167966782c29246390 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 18 Feb 2014 18:26:20 +0200 Subject: [PATCH 163/414] Bluetooth: append new supported device to the list [0b05:17d0] The device found on Asus Z87 Expert motherboard requires firmware to work correctly. T: Bus=03 Lev=01 Prnt=01 Port=03 Cnt=02 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0b05 ProdID=17d0 Rev=00.02 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb Signed-off-by: Andy Shevchenko Signed-off-by: Marcel Holtmann --- drivers/bluetooth/ath3k.c | 2 ++ drivers/bluetooth/btusb.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index fc93ade5fcac..4f78a9d39dc8 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -86,6 +86,7 @@ static const struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x04CA, 0x300b) }, { USB_DEVICE(0x0930, 0x0219) }, { USB_DEVICE(0x0930, 0x0220) }, + { USB_DEVICE(0x0b05, 0x17d0) }, { USB_DEVICE(0x0CF3, 0x0036) }, { USB_DEVICE(0x0CF3, 0x3004) }, { USB_DEVICE(0x0CF3, 0x3008) }, @@ -133,6 +134,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 46640e98fa03..199b9d42489c 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -156,6 +156,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, From 893ce8b1b3d92cbddcf34bb92c7d24720efc7fed Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 21:41:31 +0200 Subject: [PATCH 164/414] Bluetooth: Remove SMP data specific crypto context Now that each HCI device has its own AES crypto context we don't need the one stored in the SMP data any more. This patch removes the variable from struct smp_chan and updates the SMP code to use the per-hdev crypto context. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 27 +++++++++++++++------------ net/bluetooth/smp.h | 1 - 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 0c0dd1b52b66..8517d1f0984d 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -413,20 +413,16 @@ static void confirm_work(struct work_struct *work) { struct smp_chan *smp = container_of(work, struct smp_chan, confirm); struct l2cap_conn *conn = smp->conn; - struct crypto_blkcipher *tfm; + struct hci_dev *hdev = conn->hcon->hdev; + struct crypto_blkcipher *tfm = hdev->tfm_aes; struct smp_cmd_pairing_confirm cp; int ret; u8 res[16], reason; BT_DBG("conn %p", conn); - tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(tfm)) { - reason = SMP_UNSPECIFIED; - goto error; - } - - smp->tfm = tfm; + /* Prevent mutual access to hdev->tfm_aes */ + hci_dev_lock(hdev); if (conn->hcon->out) ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, @@ -436,6 +432,9 @@ static void confirm_work(struct work_struct *work) ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, conn->hcon->dst_type, &conn->hcon->dst, conn->hcon->src_type, &conn->hcon->src, res); + + hci_dev_unlock(hdev); + if (ret) { reason = SMP_UNSPECIFIED; goto error; @@ -457,7 +456,8 @@ static void random_work(struct work_struct *work) struct smp_chan *smp = container_of(work, struct smp_chan, random); struct l2cap_conn *conn = smp->conn; struct hci_conn *hcon = conn->hcon; - struct crypto_blkcipher *tfm = smp->tfm; + struct hci_dev *hdev = hcon->hdev; + struct crypto_blkcipher *tfm = hdev->tfm_aes; u8 reason, confirm[16], res[16], key[16]; int ret; @@ -468,6 +468,9 @@ static void random_work(struct work_struct *work) BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); + /* Prevent mutual access to hdev->tfm_aes */ + hci_dev_lock(hdev); + if (hcon->out) ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, hcon->src_type, &hcon->src, @@ -476,6 +479,9 @@ static void random_work(struct work_struct *work) ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, hcon->dst_type, &hcon->dst, hcon->src_type, &hcon->src, res); + + hci_dev_unlock(hdev); + if (ret) { reason = SMP_UNSPECIFIED; goto error; @@ -562,9 +568,6 @@ void smp_chan_destroy(struct l2cap_conn *conn) BUG_ON(!smp); - if (smp->tfm) - crypto_free_blkcipher(smp->tfm); - kfree(smp); conn->smp_chan = NULL; conn->hcon->smp_conn = NULL; diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 4f373bc56ad7..8f54c9b152de 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -133,7 +133,6 @@ struct smp_chan { u8 id_addr_type; u8 irk[16]; unsigned long smp_flags; - struct crypto_blkcipher *tfm; struct work_struct confirm; struct work_struct random; }; From 68d6f6ded5bdaa89f9da0144359a7c5565991f8d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 21:41:32 +0200 Subject: [PATCH 165/414] Bluetooth: Track the LE Identity Address in struct hci_conn Since we want user space to see and use the LE Identity Address whenever interfacing with the kernel it makes sense to track that instead of the real address (the two will only be different in the case of an RPA). This patch adds the necessary updates to when an LE connection gets established and when receiving the Identity Address from a remote device. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 8 ++++++++ net/bluetooth/smp.c | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d2c6878a9d6a..49a2d4d841df 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3568,6 +3568,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_le_conn_complete *ev = (void *) skb->data; struct hci_conn *conn; + struct smp_irk *irk; BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); @@ -3600,6 +3601,13 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) } } + /* Track the connection based on the Identity Address from now on */ + irk = hci_get_irk(hdev, &ev->bdaddr, ev->bdaddr_type); + if (irk) { + bacpy(&conn->dst, &irk->bdaddr); + conn->dst_type = irk->addr_type; + } + if (ev->status) { mgmt_connect_failed(hdev, &conn->dst, conn->type, conn->dst_type, ev->status); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 8517d1f0984d..af29afed0cca 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -987,6 +987,10 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, hci_add_irk(conn->hcon->hdev, &smp->id_addr, smp->id_addr_type, smp->irk, &rpa); + /* Track the connection based on the Identity Address from now on */ + bacpy(&hcon->dst, &smp->id_addr); + hcon->dst_type = smp->id_addr_type; + smp_distribute_keys(conn, 1); return 0; From 387a33e304caeeabf0c2439607fa6e726666bdf0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 21:41:33 +0200 Subject: [PATCH 166/414] Bluetooth: Fix updating Identity Address in L2CAP channels When we receive a remote identity address during SMP key distribution we should ensure that any associated L2CAP channel instances get their address information correspondingly updated (so that e.g. doing getpeername on associated sockets returns the correct address). This patch adds a new L2CAP core function l2cap_conn_update_id_addr() which is used to iterate through all L2CAP channels associated with a connection and update their address information. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_core.c | 17 +++++++++++++++++ net/bluetooth/smp.c | 2 ++ 3 files changed, 20 insertions(+) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 13bec91785f4..4abdcb220e3a 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -881,6 +881,7 @@ int l2cap_ertm_init(struct l2cap_chan *chan); void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); void l2cap_chan_del(struct l2cap_chan *chan, int err); +void l2cap_conn_update_id_addr(struct hci_conn *hcon); void l2cap_send_conn_req(struct l2cap_chan *chan); void l2cap_move_start(struct l2cap_chan *chan); void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan, diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 6e6b3a9c8e6d..c3bda6445f3d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -609,6 +609,23 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) return; } +void l2cap_conn_update_id_addr(struct hci_conn *hcon) +{ + struct l2cap_conn *conn = hcon->l2cap_data; + struct l2cap_chan *chan; + + mutex_lock(&conn->chan_lock); + + list_for_each_entry(chan, &conn->chan_l, list) { + l2cap_chan_lock(chan); + bacpy(&chan->dst, &hcon->dst); + chan->dst_type = bdaddr_type(hcon, hcon->dst_type); + l2cap_chan_unlock(chan); + } + + mutex_unlock(&conn->chan_lock); +} + static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan) { struct l2cap_conn *conn = chan->conn; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index af29afed0cca..b6a2a8942b2d 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -991,6 +991,8 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, bacpy(&hcon->dst, &smp->id_addr); hcon->dst_type = smp->id_addr_type; + l2cap_conn_update_id_addr(hcon); + smp_distribute_keys(conn, 1); return 0; From f4a407bef20c0e63fcd910a9404418522abff4ab Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 21:41:34 +0200 Subject: [PATCH 167/414] Bluetooth: Wait for SMP key distribution completion when pairing When we initiate pairing through mgmt_pair_device the code has so far been waiting for a successful HCI Encrypt Change event in order to respond to the mgmt command. However, putting privacy into the play we actually want the key distribution to be complete before replying so that we can include the Identity Address in the mgmt response. This patch updates the various hci_conn callbacks for LE in mgmt.c to only respond in the case of failure, and adds a new mgmt_smp_complete function that the SMP code will call once key distribution has been completed. Since the smp_chan_destroy function that's used to indicate completion and clean up the SMP context can be called from various places, including outside of smp.c, the easiest way to track failure vs success is a new flag that we set once key distribution has been successfully completed. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/mgmt.c | 25 +++++++++++++++++++------ net/bluetooth/smp.c | 5 +++++ net/bluetooth/smp.h | 1 + 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4461c0051228..64c4e3f0a515 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1212,6 +1212,7 @@ int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent); void mgmt_reenable_advertising(struct hci_dev *hdev); +void mgmt_smp_complete(struct hci_conn *conn, bool complete); /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 90aac905a98b..24a85fe76cd8 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2655,6 +2655,16 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status) mgmt_pending_remove(cmd); } +void mgmt_smp_complete(struct hci_conn *conn, bool complete) +{ + u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED; + struct pending_cmd *cmd; + + cmd = find_pairing(conn); + if (cmd) + pairing_complete(cmd, status); +} + static void pairing_complete_cb(struct hci_conn *conn, u8 status) { struct pending_cmd *cmd; @@ -2668,7 +2678,7 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status) pairing_complete(cmd, mgmt_status(status)); } -static void le_connect_complete_cb(struct hci_conn *conn, u8 status) +static void le_pairing_complete_cb(struct hci_conn *conn, u8 status) { struct pending_cmd *cmd; @@ -2755,13 +2765,16 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, } /* For LE, just connecting isn't a proof that the pairing finished */ - if (cp->addr.type == BDADDR_BREDR) + if (cp->addr.type == BDADDR_BREDR) { conn->connect_cfm_cb = pairing_complete_cb; - else - conn->connect_cfm_cb = le_connect_complete_cb; + conn->security_cfm_cb = pairing_complete_cb; + conn->disconn_cfm_cb = pairing_complete_cb; + } else { + conn->connect_cfm_cb = le_pairing_complete_cb; + conn->security_cfm_cb = le_pairing_complete_cb; + conn->disconn_cfm_cb = le_pairing_complete_cb; + } - conn->security_cfm_cb = pairing_complete_cb; - conn->disconn_cfm_cb = pairing_complete_cb; conn->io_capability = cp->io_cap; cmd->user_data = conn; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index b6a2a8942b2d..27eebca260fa 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -565,9 +565,13 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) void smp_chan_destroy(struct l2cap_conn *conn) { struct smp_chan *smp = conn->smp_chan; + bool complete; BUG_ON(!smp); + complete = test_bit(SMP_FLAG_COMPLETE, &smp->smp_flags); + mgmt_smp_complete(conn->hcon, complete); + kfree(smp); conn->smp_chan = NULL; conn->hcon->smp_conn = NULL; @@ -1187,6 +1191,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) if (conn->hcon->out || force || !(rsp->init_key_dist & 0x07)) { clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); cancel_delayed_work_sync(&conn->security_timer); + set_bit(SMP_FLAG_COMPLETE, &smp->smp_flags); smp_chan_destroy(conn); } diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 8f54c9b152de..675fd3b21d2c 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -118,6 +118,7 @@ struct smp_cmd_security_req { #define SMP_FLAG_TK_VALID 1 #define SMP_FLAG_CFM_PENDING 2 #define SMP_FLAG_MITM_AUTH 3 +#define SMP_FLAG_COMPLETE 4 struct smp_chan { struct l2cap_conn *conn; From 6cfc9988bd3e5d2931365da76db9b5a7334494b6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 21:41:35 +0200 Subject: [PATCH 168/414] Bluetooth: Don't try to look up private addresses as Identity Address Identity Addresses are either public or static random. When looking up addresses based on the Identity Address it doesn't make sense to go through the IRK list if we're given a private random address. This patch fixes (or rather improves) the hci_find_irk_by_addr function to bail out early if given a private random address. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index cdba4709f012..e4c5b9d6083c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2662,6 +2662,10 @@ struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, { struct smp_irk *irk; + /* Identity Address must be public or static random */ + if (addr_type == ADDR_LE_DEV_RANDOM && (bdaddr->b[5] & 0xc0) != 0xc0) + return NULL; + list_for_each_entry(irk, &hdev->identity_resolving_keys, list) { if (addr_type == irk->addr_type && bacmp(bdaddr, &irk->bdaddr) == 0) From 1ebfcc1f5884509925522ab76c17db9befe0aac9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 21:41:36 +0200 Subject: [PATCH 169/414] Bluetooth: Look up RPA for connection requests with Identity Address We need to check whether there's a matching IRK and RPA when we're requested to connect to a remote LE device based on its Identity Address. This patch updates the hci_connect_le function to do an extra call to hci_find_irk_by_addr and uses the RPA if it's cached. This is particularly important once we start exposing the Identity Address to user space instead of the RPA in events such as Device Connected and Device Found. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 67972928a623..40ec37355d6f 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -588,6 +588,7 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, { struct hci_conn_params *params; struct hci_conn *conn; + struct smp_irk *irk; int err; if (test_bit(HCI_ADVERTISING, &hdev->flags)) @@ -616,15 +617,23 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, if (conn) return ERR_PTR(-EBUSY); + /* Convert from L2CAP channel address type to HCI address type */ + if (dst_type == BDADDR_LE_PUBLIC) + dst_type = ADDR_LE_DEV_PUBLIC; + else + dst_type = ADDR_LE_DEV_RANDOM; + + irk = hci_find_irk_by_addr(hdev, dst, dst_type); + if (irk && bacmp(&irk->rpa, BDADDR_ANY)) { + dst = &irk->rpa; + dst_type = ADDR_LE_DEV_RANDOM; + } + conn = hci_conn_add(hdev, LE_LINK, dst); if (!conn) return ERR_PTR(-ENOMEM); - if (dst_type == BDADDR_LE_PUBLIC) - conn->dst_type = ADDR_LE_DEV_PUBLIC; - else - conn->dst_type = ADDR_LE_DEV_RANDOM; - + conn->dst_type = dst_type; conn->src_type = hdev->own_addr_type; conn->state = BT_CONNECT; From 5cedbb8d7aee79a8bbfc8e5b91bc1353ffb0f7b0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 21:41:37 +0200 Subject: [PATCH 170/414] Bluetooth: Use Identity Address in Device Found event Whenever a device uses an RPA we want to have user space identify it by its Identity Address if we've got an IRK available for it. This patch updates the Device Found mgmt event to contain the Identity Address if an IRK is available for the device in question. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 24a85fe76cd8..747cb9bbc331 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5325,6 +5325,7 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, { char buf[512]; struct mgmt_ev_device_found *ev = (void *) buf; + struct smp_irk *irk; size_t ev_size; if (!hci_discovery_active(hdev)) @@ -5336,8 +5337,15 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, memset(buf, 0, sizeof(buf)); - bacpy(&ev->addr.bdaddr, bdaddr); - ev->addr.type = link_to_bdaddr(link_type, addr_type); + irk = hci_get_irk(hdev, bdaddr, addr_type); + if (irk) { + bacpy(&ev->addr.bdaddr, &irk->bdaddr); + ev->addr.type = link_to_bdaddr(link_type, irk->addr_type); + } else { + bacpy(&ev->addr.bdaddr, bdaddr); + ev->addr.type = link_to_bdaddr(link_type, addr_type); + } + ev->rssi = rssi; if (cfm_name) ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME); From 2c96e03def3b1ba47a5d0ec0c8ef7935a9bfb3a0 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 18 Feb 2014 20:48:34 +0100 Subject: [PATCH 171/414] Bluetooth: Print error when dropping L2CAP data Silently dropping L2CAP data (i.e. due to remote device not obeying negotiated MTU) is confusing and makes debugging harder. Signed-off-by: Szymon Janc Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c3bda6445f3d..6ace116f3b39 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -6776,8 +6776,10 @@ static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid, * But we don't have any other choice. L2CAP doesn't * provide flow control mechanism. */ - if (chan->imtu < skb->len) + if (chan->imtu < skb->len) { + BT_ERR("Dropping L2CAP data: receive buffer overflow"); goto drop; + } if (!chan->ops->recv(chan, skb)) goto done; From 01fdb0fc6e937eeff7b20d0e217408cee9ec05af Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 18 Feb 2014 14:22:19 -0800 Subject: [PATCH 172/414] Bluetooth: Report identity address when remote device connects When the remote device has been successfully connected, report the identity address (public address or static random address). Currently the address from the HCI_LE_Connection_Complete event is used. This was no problem so far, but since now known resolvable random addresses are converted into identities, it is important to use the identity of the connection and not the address report by HCI event. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 49a2d4d841df..d7c709519e31 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3618,7 +3618,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) } if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) - mgmt_device_connected(hdev, &ev->bdaddr, conn->type, + mgmt_device_connected(hdev, &conn->dst, conn->type, conn->dst_type, 0, NULL, 0, NULL); conn->sec_level = BT_SECURITY_LOW; From 64c7b77c124c71166d1dd49fc7e8d6fee7d9b01b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 18 Feb 2014 14:22:20 -0800 Subject: [PATCH 173/414] Bluetooth: Use connection address for reporting connection failures When reporting connect failed events to userspace, use the address of the connection and not the address from the HCI event. This change is strictly speaking not needed since BR/EDR does not have the concept of resolvable random addresses. It is more for making the code consistent. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d7c709519e31..22bfc5c17e7f 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1704,7 +1704,7 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) } else { conn->state = BT_CLOSED; if (conn->type == ACL_LINK) - mgmt_connect_failed(hdev, &ev->bdaddr, conn->type, + mgmt_connect_failed(hdev, &conn->dst, conn->type, conn->dst_type, ev->status); } From edb4b46651c87f1579154298c41f9c1a753565a3 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 18 Feb 2014 15:13:43 -0800 Subject: [PATCH 174/414] Bluetooth: Fix wrong identity address during connection failures When the connection attempt fails, the address information are not provided in the HCI_LE_Connection_Complete event. So use the original information from the connection to reconstruct the identity address. This is important when a connection attempt has been made using the identity address, but the cached resolvable random address has changed in the meantime. The failure event needs to use the identity address and not the resolvable random address. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 13 +++++++++++++ net/bluetooth/hci_event.c | 12 ++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 40ec37355d6f..a027951d0da5 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -623,6 +623,19 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, else dst_type = ADDR_LE_DEV_RANDOM; + /* When given an identity address with existing identity + * resolving key, the connection needs to be established + * to a resolvable random address. + * + * This uses the cached random resolvable address from + * a previous scan. When no cached address is available, + * try connecting to the identity address instead. + * + * Storing the resolvable random address is required here + * to handle connection failures. The address will later + * be resolved back into the original identity address + * from the connect request. + */ irk = hci_find_irk_by_addr(hdev, dst, dst_type); if (irk && bacmp(&irk->rpa, BDADDR_ANY)) { dst = &irk->rpa; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 22bfc5c17e7f..7228fa100b1f 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3601,8 +3601,16 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) } } - /* Track the connection based on the Identity Address from now on */ - irk = hci_get_irk(hdev, &ev->bdaddr, ev->bdaddr_type); + /* Lookup the identity address from the stored connection + * address and address type. + * + * When establishing connections to an identity address, the + * connection procedure will store the resolvable random + * address first. Now if it can be converted back into the + * identity address, start using the identity address from + * now on. + */ + irk = hci_get_irk(hdev, &conn->dst, conn->dst_type); if (irk) { bacpy(&conn->dst, &irk->bdaddr); conn->dst_type = irk->addr_type; From 3698d70469d165d01fefcad9a56172742157ff95 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 18 Feb 2014 21:54:49 -0800 Subject: [PATCH 175/414] Bluetooth: Expose current list of identity resolving keys via debugfs For debugging purposes expose the current list of identity resolving keys via debugfs. This file is read-only and limited to root access. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e4c5b9d6083c..e8f61b3fe87c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -599,6 +599,36 @@ static int own_address_type_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(own_address_type_fops, own_address_type_get, own_address_type_set, "%llu\n"); +static int identity_resolving_keys_show(struct seq_file *f, void *ptr) +{ + struct hci_dev *hdev = f->private; + struct list_head *p, *n; + + hci_dev_lock(hdev); + list_for_each_safe(p, n, &hdev->identity_resolving_keys) { + struct smp_irk *irk = list_entry(p, struct smp_irk, list); + seq_printf(f, "%pMR (type %u) %*phN %pMR\n", + &irk->bdaddr, irk->addr_type, + 16, irk->val, &irk->rpa); + } + hci_dev_unlock(hdev); + + return 0; +} + +static int identity_resolving_keys_open(struct inode *inode, struct file *file) +{ + return single_open(file, identity_resolving_keys_show, + inode->i_private); +} + +static const struct file_operations identity_resolving_keys_fops = { + .open = identity_resolving_keys_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int long_term_keys_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; @@ -1512,6 +1542,9 @@ static int __hci_init(struct hci_dev *hdev) hdev, &static_address_fops); debugfs_create_file("own_address_type", 0644, hdev->debugfs, hdev, &own_address_type_fops); + debugfs_create_file("identity_resolving_keys", 0400, + hdev->debugfs, hdev, + &identity_resolving_keys_fops); debugfs_create_file("long_term_keys", 0400, hdev->debugfs, hdev, &long_term_keys_fops); debugfs_create_file("conn_min_interval", 0644, hdev->debugfs, From d66c295031aec712e179d21de66602d631390f34 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 18 Feb 2014 22:27:14 -0800 Subject: [PATCH 176/414] Bluetooth: Use same LE min/max connection event length during update During LE connection establishment the value 0x0000 is used for min/max connection event length. So use the same value when the peripheral is requesting an update of the the connection paramters. For some reason the value 0x0001 got used in the connection update and 0x0000 in the connection creation. Using the same value for both just makes sense. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index a027951d0da5..bd66c52eff95 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -225,8 +225,8 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, cp.conn_interval_max = cpu_to_le16(max); cp.conn_latency = cpu_to_le16(latency); cp.supervision_timeout = cpu_to_le16(to_multiplier); - cp.min_ce_len = __constant_cpu_to_le16(0x0001); - cp.max_ce_len = __constant_cpu_to_le16(0x0001); + cp.min_ce_len = __constant_cpu_to_le16(0x0000); + cp.max_ce_len = __constant_cpu_to_le16(0x0000); hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp); } From 0a14ab416d7754be0bb0d4306c996f72f52fa5bf Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 19 Feb 2014 14:57:43 +0200 Subject: [PATCH 177/414] Bluetooth: Avoid using GFP_ATOMIC where not necessary The various pieces of data cached in the hci_dev structure do not need to be allocated using GFP_ATOMIC since they are never added from interrupt context. This patch updates these allocations to use GFP_KERNEL instead. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e8f61b3fe87c..7e679e085506 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2721,7 +2721,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, key = old_key; } else { old_key_type = conn ? conn->key_type : 0xff; - key = kzalloc(sizeof(*key), GFP_ATOMIC); + key = kzalloc(sizeof(*key), GFP_KERNEL); if (!key) return -ENOMEM; list_add(&key->list, &hdev->link_keys); @@ -2773,7 +2773,7 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, if (old_key) key = old_key; else { - key = kzalloc(sizeof(*key), GFP_ATOMIC); + key = kzalloc(sizeof(*key), GFP_KERNEL); if (!key) return -ENOMEM; list_add(&key->list, &hdev->long_term_keys); @@ -2938,7 +2938,7 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, data = hci_find_remote_oob_data(hdev, bdaddr); if (!data) { - data = kmalloc(sizeof(*data), GFP_ATOMIC); + data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -2965,7 +2965,7 @@ int hci_add_remote_oob_ext_data(struct hci_dev *hdev, bdaddr_t *bdaddr, data = hci_find_remote_oob_data(hdev, bdaddr); if (!data) { - data = kmalloc(sizeof(*data), GFP_ATOMIC); + data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; From ca9142b8825c159897cc4a246ea27585c82add4b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 19 Feb 2014 14:57:44 +0200 Subject: [PATCH 178/414] Bluetooth: Return added key when adding LTKs and IRKs The SMP code will need to postpone the mgmt event emission for the IRK and LTKs. To avoid extra lookups at the end of the key distribution simply return the added value from the add_ltk and add_irk functions. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 11 ++++++----- net/bluetooth/hci_core.c | 21 +++++++++++---------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 64c4e3f0a515..5366dc9e25eb 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -787,9 +787,10 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8], bool master); -int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, - int new_key, u8 authenticated, u8 tk[16], u8 enc_size, - __le16 ediv, u8 rand[8]); +struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 addr_type, u8 type, int new_key, + u8 authenticated, u8 tk[16], u8 enc_size, + __le16 ediv, u8 rand[8]); struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, bool master); int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type); @@ -799,8 +800,8 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa); struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type); -int hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, - u8 val[16], bdaddr_t *rpa); +struct smp_irk *hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 addr_type, u8 val[16], bdaddr_t *rpa); void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type); void hci_smp_irks_clear(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 7e679e085506..e23c718d668b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2761,9 +2761,10 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, return 0; } -int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, - int new_key, u8 authenticated, u8 tk[16], u8 enc_size, __le16 - ediv, u8 rand[8]) +struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 addr_type, u8 type, int new_key, + u8 authenticated, u8 tk[16], u8 enc_size, + __le16 ediv, u8 rand[8]) { struct smp_ltk *key, *old_key; bool master = ltk_type_master(type); @@ -2775,7 +2776,7 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, else { key = kzalloc(sizeof(*key), GFP_KERNEL); if (!key) - return -ENOMEM; + return NULL; list_add(&key->list, &hdev->long_term_keys); } @@ -2789,7 +2790,7 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, memcpy(key->rand, rand, sizeof(key->rand)); if (!new_key) - return 0; + return key; if (addr_type == ADDR_LE_DEV_RANDOM && (bdaddr->b[5] & 0xc0) != 0xc0) persistent = 0; @@ -2799,11 +2800,11 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, if (type == HCI_SMP_LTK || type == HCI_SMP_LTK_SLAVE) mgmt_new_ltk(hdev, key, persistent); - return 0; + return key; } -int hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, - u8 val[16], bdaddr_t *rpa) +struct smp_irk *hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 addr_type, u8 val[16], bdaddr_t *rpa) { struct smp_irk *irk; @@ -2811,7 +2812,7 @@ int hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, if (!irk) { irk = kzalloc(sizeof(*irk), GFP_KERNEL); if (!irk) - return -ENOMEM; + return NULL; bacpy(&irk->bdaddr, bdaddr); irk->addr_type = addr_type; @@ -2822,7 +2823,7 @@ int hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, memcpy(irk->val, val, 16); bacpy(&irk->rpa, rpa); - return 0; + return irk; } int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) From ba74b666b5e581ef3d4912af73774fab48c03198 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 19 Feb 2014 14:57:45 +0200 Subject: [PATCH 179/414] Bluetooth: Move New LTK store hint evaluation into mgmt_new_ltk It's simpler (one less if-statement) to just evaluate the appropriate value for store_hint in the mgmt_new_ltk function than to pass a boolean parameter to the function. Furthermore, this simplifies moving the mgmt event emission out from hci_add_ltk in subsequent patches. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 8 +------- net/bluetooth/mgmt.c | 9 +++++++-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 5366dc9e25eb..8ca95e5e3765 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1211,7 +1211,7 @@ void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, void mgmt_discovering(struct hci_dev *hdev, u8 discovering); int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); -void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent); +void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key); void mgmt_reenable_advertising(struct hci_dev *hdev); void mgmt_smp_complete(struct hci_conn *conn, bool complete); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e23c718d668b..60c875267c19 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2768,7 +2768,6 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, { struct smp_ltk *key, *old_key; bool master = ltk_type_master(type); - u8 persistent; old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type, master); if (old_key) @@ -2792,13 +2791,8 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, if (!new_key) return key; - if (addr_type == ADDR_LE_DEV_RANDOM && (bdaddr->b[5] & 0xc0) != 0xc0) - persistent = 0; - else - persistent = 1; - if (type == HCI_SMP_LTK || type == HCI_SMP_LTK_SLAVE) - mgmt_new_ltk(hdev, key, persistent); + mgmt_new_ltk(hdev, key); return key; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 747cb9bbc331..ad51da1b6dc2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4765,13 +4765,18 @@ void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL); } -void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent) +void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key) { struct mgmt_ev_new_long_term_key ev; memset(&ev, 0, sizeof(ev)); - ev.store_hint = persistent; + if (key->bdaddr_type == ADDR_LE_DEV_RANDOM && + (key->bdaddr.b[5] & 0xc0) != 0xc0) + ev.store_hint = 0x00; + else + ev.store_hint = 0x01; + bacpy(&ev.key.addr.bdaddr, &key->bdaddr); ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type); ev.key.type = key->authenticated; From 23d0e128e38049734c7ecc0987de02486d1ded3e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 19 Feb 2014 14:57:46 +0200 Subject: [PATCH 180/414] Bluetooth: Track SMP keys in the SMP context As preparation to do mgmt notification in a single place at the end of the key distribution, store the keys that need to be notified within the SMP context. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 21 +++++++++++++-------- net/bluetooth/smp.h | 3 +++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 27eebca260fa..eaac54be91b1 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -915,6 +915,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) struct smp_chan *smp = conn->smp_chan; struct hci_dev *hdev = conn->hcon->hdev; struct hci_conn *hcon = conn->hcon; + struct smp_ltk *ltk; u8 authenticated; BT_DBG("conn %p", conn); @@ -930,9 +931,10 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) hci_dev_lock(hdev); authenticated = (hcon->sec_level == BT_SECURITY_HIGH); - hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK, 1, - authenticated, smp->tk, smp->enc_key_size, - rp->ediv, rp->rand); + ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK, 1, + authenticated, smp->tk, smp->enc_key_size, + rp->ediv, rp->rand); + smp->ltk = ltk; if (!(smp->remote_key_dist & SMP_DIST_ID_KEY)) smp_distribute_keys(conn, 1); hci_dev_unlock(hdev); @@ -988,8 +990,8 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, else bacpy(&rpa, BDADDR_ANY); - hci_add_irk(conn->hcon->hdev, &smp->id_addr, smp->id_addr_type, - smp->irk, &rpa); + smp->remote_irk = hci_add_irk(conn->hcon->hdev, &smp->id_addr, + smp->id_addr_type, smp->irk, &rpa); /* Track the connection based on the Identity Address from now on */ bacpy(&hcon->dst, &smp->id_addr); @@ -1137,6 +1139,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) struct smp_cmd_encrypt_info enc; struct smp_cmd_master_ident ident; struct hci_conn *hcon = conn->hcon; + struct smp_ltk *ltk; u8 authenticated; __le16 ediv; @@ -1147,9 +1150,11 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc); authenticated = hcon->sec_level == BT_SECURITY_HIGH; - hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, - HCI_SMP_LTK_SLAVE, 1, authenticated, - enc.ltk, smp->enc_key_size, ediv, ident.rand); + ltk = hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, + HCI_SMP_LTK_SLAVE, 1, authenticated, + enc.ltk, smp->enc_key_size, ediv, + ident.rand); + smp->slave_ltk = ltk; ident.ediv = ediv; diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 675fd3b21d2c..d8cc543f523c 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -133,6 +133,9 @@ struct smp_chan { bdaddr_t id_addr; u8 id_addr_type; u8 irk[16]; + struct smp_ltk *ltk; + struct smp_ltk *slave_ltk; + struct smp_irk *remote_irk; unsigned long smp_flags; struct work_struct confirm; struct work_struct random; From 35d702719d6464a9de2bf98d536c6e054f0a8f7e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 19 Feb 2014 14:57:47 +0200 Subject: [PATCH 181/414] Bluetooth: Move SMP LTK notification after key distribution This patch moves the SMP Long Term Key notification over mgmt from the hci_add_ltk function to smp.c when both sides have completed their key distribution. This way we are also able to update the identity address into the mgmt_new_ltk event. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 5 ++--- net/bluetooth/hci_core.c | 11 ++--------- net/bluetooth/mgmt.c | 6 +++--- net/bluetooth/smp.c | 29 ++++++++++++++++++++++++----- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 8ca95e5e3765..59ae04c2684f 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -788,9 +788,8 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8], bool master); struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 addr_type, u8 type, int new_key, - u8 authenticated, u8 tk[16], u8 enc_size, - __le16 ediv, u8 rand[8]); + u8 addr_type, u8 type, u8 authenticated, + u8 tk[16], u8 enc_size, __le16 ediv, u8 rand[8]); struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, bool master); int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 60c875267c19..3711c7626cb2 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2762,9 +2762,8 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, } struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 addr_type, u8 type, int new_key, - u8 authenticated, u8 tk[16], u8 enc_size, - __le16 ediv, u8 rand[8]) + u8 addr_type, u8 type, u8 authenticated, + u8 tk[16], u8 enc_size, __le16 ediv, u8 rand[8]) { struct smp_ltk *key, *old_key; bool master = ltk_type_master(type); @@ -2788,12 +2787,6 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, key->type = type; memcpy(key->rand, rand, sizeof(key->rand)); - if (!new_key) - return key; - - if (type == HCI_SMP_LTK || type == HCI_SMP_LTK_SLAVE) - mgmt_new_ltk(hdev, key); - return key; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ad51da1b6dc2..bcfc6da67a5c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4330,9 +4330,9 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, else type = HCI_SMP_LTK_SLAVE; - hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, - type, 0, key->type, key->val, - key->enc_size, key->ediv, key->rand); + hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type, + key->type, key->val, key->enc_size, key->ediv, + key->rand); } err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0, diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index eaac54be91b1..f05c1b71d99a 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -532,7 +532,7 @@ static void random_work(struct work_struct *work) SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, - HCI_SMP_STK_SLAVE, 0, 0, stk, smp->enc_key_size, + HCI_SMP_STK_SLAVE, 0, stk, smp->enc_key_size, ediv, rand); } @@ -931,7 +931,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) hci_dev_lock(hdev); authenticated = (hcon->sec_level == BT_SECURITY_HIGH); - ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK, 1, + ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK, authenticated, smp->tk, smp->enc_key_size, rp->ediv, rp->rand); smp->ltk = ltk; @@ -1106,6 +1106,25 @@ done: return err; } +static void smp_notify_keys(struct l2cap_conn *conn) +{ + struct smp_chan *smp = conn->smp_chan; + struct hci_conn *hcon = conn->hcon; + struct hci_dev *hdev = hcon->hdev; + + if (smp->ltk) { + smp->ltk->bdaddr_type = hcon->dst_type; + bacpy(&smp->ltk->bdaddr, &hcon->dst); + mgmt_new_ltk(hdev, smp->ltk); + } + + if (smp->slave_ltk) { + smp->slave_ltk->bdaddr_type = hcon->dst_type; + bacpy(&smp->slave_ltk->bdaddr, &hcon->dst); + mgmt_new_ltk(hdev, smp->slave_ltk); + } +} + int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) { struct smp_cmd_pairing *req, *rsp; @@ -1151,9 +1170,8 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) authenticated = hcon->sec_level == BT_SECURITY_HIGH; ltk = hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, - HCI_SMP_LTK_SLAVE, 1, authenticated, - enc.ltk, smp->enc_key_size, ediv, - ident.rand); + HCI_SMP_LTK_SLAVE, authenticated, enc.ltk, + smp->enc_key_size, ediv, ident.rand); smp->slave_ltk = ltk; ident.ediv = ediv; @@ -1197,6 +1215,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); cancel_delayed_work_sync(&conn->security_timer); set_bit(SMP_FLAG_COMPLETE, &smp->smp_flags); + smp_notify_keys(conn); smp_chan_destroy(conn); } From 95fbac8a8e459262c580ee4172e4713cdc60929b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 19 Feb 2014 15:18:31 +0200 Subject: [PATCH 182/414] Bluetooth: Add support for sending New IRK event This patch adds the necessary helper function to send the New IRK mgmt event and makes sure that the function is called at when SMP key distribution has completed. The event is sent before the New LTK event so user space knows which remote device to associate with the keys. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/mgmt.h | 7 +++++++ net/bluetooth/mgmt.c | 15 +++++++++++++++ net/bluetooth/smp.c | 3 +++ 4 files changed, 26 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 59ae04c2684f..3be2905010cd 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1211,6 +1211,7 @@ void mgmt_discovering(struct hci_dev *hdev, u8 discovering); int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key); +void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk); void mgmt_reenable_advertising(struct hci_dev *hdev); void mgmt_smp_complete(struct hci_conn *conn, bool complete); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index e4fa13e559e2..2e46251e8aec 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -536,3 +536,10 @@ struct mgmt_ev_passkey_notify { __le32 passkey; __u8 entered; } __packed; + +#define MGMT_EV_NEW_IRK 0x0018 +struct mgmt_ev_new_irk { + __u8 store_hint; + bdaddr_t rpa; + struct mgmt_irk_info irk; +} __packed; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bcfc6da67a5c..1daa837da091 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4792,6 +4792,21 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key) mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL); } +void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk) +{ + struct mgmt_ev_new_irk ev; + + memset(&ev, 0, sizeof(ev)); + + ev.store_hint = 0x01; + bacpy(&ev.rpa, &irk->rpa); + bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr); + ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type); + memcpy(ev.irk.val, irk->val, sizeof(irk->val)); + + mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL); +} + static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, u8 data_len) { diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index f05c1b71d99a..f06068072bdd 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1112,6 +1112,9 @@ static void smp_notify_keys(struct l2cap_conn *conn) struct hci_conn *hcon = conn->hcon; struct hci_dev *hdev = hcon->hdev; + if (smp->remote_irk) + mgmt_new_irk(hdev, smp->remote_irk); + if (smp->ltk) { smp->ltk->bdaddr_type = hcon->dst_type; bacpy(&smp->ltk->bdaddr, &hcon->dst); From bab6d1e594ef4dd76ee5a369da96d572c43c7489 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 19 Feb 2014 11:51:54 -0800 Subject: [PATCH 183/414] Bluetooth: Don't send store hint for devices using identity addresses The identity resolving keys should only be stored for devices using resolvable random addresses. If the device is already using an identity address, inform it about the new identity resolving key, but tell userspace that this key is not persistent. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1daa837da091..e8b9d2f261ee 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4798,7 +4798,22 @@ void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk) memset(&ev, 0, sizeof(ev)); - ev.store_hint = 0x01; + /* For identity resolving keys from devices that are already + * using a public address or static random address, do not + * ask for storing this key. The identity resolving key really + * is only mandatory for devices using resovlable random + * addresses. + * + * Storing all identity resolving keys has the downside that + * they will be also loaded on next boot of they system. More + * identity resolving keys, means more time during scanning is + * needed to actually resolve these addresses. + */ + if (bacmp(&irk->rpa, BDADDR_ANY)) + ev.store_hint = 0x01; + else + ev.store_hint = 0x00; + bacpy(&ev.rpa, &irk->rpa); bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr); ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type); From 5192d30114771ac5956d750ec506dc574411cc70 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 19 Feb 2014 17:11:58 -0800 Subject: [PATCH 184/414] Bluetooth: Add comment explainging store hint for long term keys The code itself is not descriptive on what store hint is used for long term keys and why. So add some extensive comment here. Similar to what has already been done for identity resolving key store hint. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e8b9d2f261ee..5f5e388716ec 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4771,6 +4771,17 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key) memset(&ev, 0, sizeof(ev)); + /* Devices using resolvable or non-resolvable random addresses + * without providing an indentity resolving key don't require + * to store long term keys. Their addresses will change the + * next time around. + * + * Only when a remote device provides an identity address + * make sure the long term key is stored. If the remote + * identity is known, the long term keys are internally + * mapped to the identity address. So allow static random + * and public addresses here. + */ if (key->bdaddr_type == ADDR_LE_DEV_RANDOM && (key->bdaddr.b[5] & 0xc0) != 0xc0) ev.store_hint = 0x00; From b32bba6ced5696593a6bae5fdc69dc79c0a97ef5 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 19 Feb 2014 19:31:26 -0800 Subject: [PATCH 185/414] Bluetooth: Replace own_address_type with force_static_address debugfs The own_address_type debugfs option does not providing enough flexibity for interacting with the upcoming LE privacy support. What really is needed is an option to force using the static address compared to the public address. The new force_static_address debugfs option does exactly that. In addition it is also only available when the controller does actually have a public address. For single mode LE only controllers this option will not be available. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_core.c | 99 ++++++++++++++++++++++++------------- 2 files changed, 65 insertions(+), 35 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index d3a8fff50f69..fe4b06bfc150 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -118,6 +118,7 @@ enum { HCI_DEBUG_KEYS, HCI_DUT_MODE, HCI_FORCE_SC, + HCI_FORCE_STATIC_ADDR, HCI_UNREGISTER, HCI_USER_CHANNEL, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3711c7626cb2..b25a36c3064b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -571,33 +571,52 @@ static const struct file_operations static_address_fops = { .release = single_release, }; -static int own_address_type_set(void *data, u64 val) +static ssize_t force_static_address_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { - struct hci_dev *hdev = data; + struct hci_dev *hdev = file->private_data; + char buf[3]; - if (val != 0 && val != 1) + buf[0] = test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags) ? 'Y': 'N'; + buf[1] = '\n'; + buf[2] = '\0'; + return simple_read_from_buffer(user_buf, count, ppos, buf, 2); +} + +static ssize_t force_static_address_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct hci_dev *hdev = file->private_data; + char buf[32]; + size_t buf_size = min(count, (sizeof(buf)-1)); + bool enable; + + if (test_bit(HCI_UP, &hdev->flags)) + return -EBUSY; + + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + buf[buf_size] = '\0'; + if (strtobool(buf, &enable)) return -EINVAL; - hci_dev_lock(hdev); - hdev->own_addr_type = val; - hci_dev_unlock(hdev); + if (enable == test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags)) + return -EALREADY; - return 0; + change_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags); + + return count; } -static int own_address_type_get(void *data, u64 *val) -{ - struct hci_dev *hdev = data; - - hci_dev_lock(hdev); - *val = hdev->own_addr_type; - hci_dev_unlock(hdev); - - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(own_address_type_fops, own_address_type_get, - own_address_type_set, "%llu\n"); +static const struct file_operations force_static_address_fops = { + .open = simple_open, + .read = force_static_address_read, + .write = force_static_address_write, + .llseek = default_llseek, +}; static int identity_resolving_keys_show(struct seq_file *f, void *ptr) { @@ -1406,17 +1425,19 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) hci_setup_link_policy(req); if (lmp_le_capable(hdev)) { - if (test_bit(HCI_SETUP, &hdev->dev_flags)) { - /* If the controller has a public BD_ADDR, then - * by default use that one. If this is a LE only - * controller without a public address, default - * to the random address. - */ - if (bacmp(&hdev->bdaddr, BDADDR_ANY)) - hdev->own_addr_type = ADDR_LE_DEV_PUBLIC; - else - hdev->own_addr_type = ADDR_LE_DEV_RANDOM; - } + /* If the controller has a public BD_ADDR, then by default + * use that one. If this is a LE only controller without + * a public address, default to the random address. + * + * For debugging purposes it is possible to force + * controllers with a public address to use the + * random address instead. + */ + if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags) || + !bacmp(&hdev->bdaddr, BDADDR_ANY)) + hdev->own_addr_type = ADDR_LE_DEV_RANDOM; + else + hdev->own_addr_type = ADDR_LE_DEV_PUBLIC; hci_set_le_support(req); } @@ -1536,12 +1557,20 @@ static int __hci_init(struct hci_dev *hdev) } if (lmp_le_capable(hdev)) { + debugfs_create_file("static_address", 0444, hdev->debugfs, + hdev, &static_address_fops); + + /* For controllers with a public address, provide a debug + * option to force the usage of the configured static + * address. By default the public address is used. + */ + if (bacmp(&hdev->bdaddr, BDADDR_ANY)) + debugfs_create_file("force_static_address", 0644, + hdev->debugfs, hdev, + &force_static_address_fops); + debugfs_create_u8("white_list_size", 0444, hdev->debugfs, &hdev->le_white_list_size); - debugfs_create_file("static_address", 0444, hdev->debugfs, - hdev, &static_address_fops); - debugfs_create_file("own_address_type", 0644, hdev->debugfs, - hdev, &own_address_type_fops); debugfs_create_file("identity_resolving_keys", 0400, hdev->debugfs, hdev, &identity_resolving_keys_fops); From 7a4cd51dec96b42d899ed7b2207c9ef810534451 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 19 Feb 2014 19:52:13 -0800 Subject: [PATCH 186/414] Bluetooth: Track the current configured random address For Bluetooth controllers with LE support, track the value of the currently configured random address. It is important to know what the current random address is to avoid unneeded attempts to set a new address. This will become important when introducing the LE privacy support in the future. In addition expose the current configured random address via debugfs for debugging purposes. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 26 ++++++++++++++++++++++++++ net/bluetooth/hci_event.c | 24 ++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3be2905010cd..3a8e22e9b25d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -151,6 +151,7 @@ struct hci_dev { __u8 bus; __u8 dev_type; bdaddr_t bdaddr; + bdaddr_t random_addr; bdaddr_t static_addr; __u8 own_addr_type; __u8 dev_name[HCI_MAX_NAME_LENGTH]; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b25a36c3064b..877330b4876f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -548,6 +548,29 @@ static int sniff_max_interval_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(sniff_max_interval_fops, sniff_max_interval_get, sniff_max_interval_set, "%llu\n"); +static int random_address_show(struct seq_file *f, void *p) +{ + struct hci_dev *hdev = f->private; + + hci_dev_lock(hdev); + seq_printf(f, "%pMR\n", &hdev->random_addr); + hci_dev_unlock(hdev); + + return 0; +} + +static int random_address_open(struct inode *inode, struct file *file) +{ + return single_open(file, random_address_show, inode->i_private); +} + +static const struct file_operations random_address_fops = { + .open = random_address_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int static_address_show(struct seq_file *f, void *p) { struct hci_dev *hdev = f->private; @@ -1557,6 +1580,8 @@ static int __hci_init(struct hci_dev *hdev) } if (lmp_le_capable(hdev)) { + debugfs_create_file("random_address", 0444, hdev->debugfs, + hdev, &random_address_fops); debugfs_create_file("static_address", 0444, hdev->debugfs, hdev, &static_address_fops); @@ -2205,6 +2230,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) memset(hdev->eir, 0, sizeof(hdev->eir)); memset(hdev->dev_class, 0, sizeof(hdev->dev_class)); + bacpy(&hdev->random_addr, BDADDR_ANY); hci_req_unlock(hdev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 7228fa100b1f..4327b129d38e 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -959,6 +959,26 @@ static void hci_cc_read_local_oob_ext_data(struct hci_dev *hdev, hci_dev_unlock(hdev); } + +static void hci_cc_le_set_random_addr(struct hci_dev *hdev, struct sk_buff *skb) +{ + __u8 status = *((__u8 *) skb->data); + bdaddr_t *sent; + + BT_DBG("%s status 0x%2.2x", hdev->name, status); + + sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_RANDOM_ADDR); + if (!sent) + return; + + hci_dev_lock(hdev); + + if (!status) + bacpy(&hdev->random_addr, sent); + + hci_dev_unlock(hdev); +} + static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) { __u8 *sent, status = *((__u8 *) skb->data); @@ -2308,6 +2328,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_cc_user_passkey_neg_reply(hdev, skb); break; + case HCI_OP_LE_SET_RANDOM_ADDR: + hci_cc_le_set_random_addr(hdev, skb); + break; + case HCI_OP_LE_SET_ADV_ENABLE: hci_cc_le_set_adv_enable(hdev, skb); break; From df942e7ba70cd0a7aa9e0432b8a6a328de2c5574 Mon Sep 17 00:00:00 2001 From: Sunil Dutt Undekari Date: Thu, 20 Feb 2014 16:22:09 +0530 Subject: [PATCH 187/414] cfg80211: Pass TDLS peer capability information in tdls_mgmt While framing the TDLS Setup Confirmation frame, the driver needs to know if the TDLS peer is VHT/HT/WMM capable and thus shall construct the VHT/HT operation / WMM parameter elements accordingly. Supplicant determines if the TDLS peer is VHT/HT/WMM capable based on the presence of the respective IEs in the received TDLS Setup Response frame. The host driver should not need to parse the received TDLS Response frame and thus, should be able to rely on the supplicant to indicate the capability of the peer through additional flags while transmitting the TDLS Setup Confirmation frame through tdls_mgmt operations. Signed-off-by: Sunil Dutt Undekari Signed-off-by: Johannes Berg --- drivers/net/wireless/mwifiex/cfg80211.c | 4 ++-- include/net/cfg80211.h | 3 ++- include/uapi/linux/nl80211.h | 21 +++++++++++++++++++++ net/mac80211/cfg.c | 4 ++-- net/wireless/nl80211.c | 7 ++++++- net/wireless/rdev-ops.h | 9 ++++++--- net/wireless/trace.h | 12 ++++++++---- 7 files changed, 47 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 436ba437a4ba..6948a97af839 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2600,8 +2600,8 @@ static int mwifiex_cfg80211_set_coalesce(struct wiphy *wiphy, static int mwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, u8 *peer, u8 action_code, u8 dialog_token, - u16 status_code, const u8 *extra_ies, - size_t extra_ies_len) + u16 status_code, u32 peer_capability, + const u8 *extra_ies, size_t extra_ies_len) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int ret; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 9f90554e88c4..c89a5b5bd103 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2465,7 +2465,8 @@ struct cfg80211_ops { int (*tdls_mgmt)(struct wiphy *wiphy, struct net_device *dev, u8 *peer, u8 action_code, u8 dialog_token, - u16 status_code, const u8 *buf, size_t len); + u16 status_code, u32 peer_capability, + const u8 *buf, size_t len); int (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev, u8 *peer, enum nl80211_tdls_operation oper); diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index ba1f7625625c..47d7087513e0 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1575,6 +1575,9 @@ enum nl80211_commands { * advertise values that cannot always be met. In such cases, an attempt * to add a new station entry with @NL80211_CMD_NEW_STATION may fail. * + * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32. + * As specified in the &enum nl80211_tdls_peer_capability. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1908,6 +1911,8 @@ enum nl80211_attrs { NL80211_ATTR_MAX_AP_ASSOC_STA, + NL80211_ATTR_TDLS_PEER_CAPABILITY, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -4074,4 +4079,20 @@ struct nl80211_vendor_cmd_info { __u32 subcmd; }; +/** + * enum nl80211_tdls_peer_capability - TDLS peer flags. + * + * Used by tdls_mgmt() to determine which conditional elements need + * to be added to TDLS Setup frames. + * + * @NL80211_TDLS_PEER_HT: TDLS peer is HT capable. + * @NL80211_TDLS_PEER_VHT: TDLS peer is VHT capable. + * @NL80211_TDLS_PEER_WMM: TDLS peer is WMM capable. + */ +enum nl80211_tdls_peer_capability { + NL80211_TDLS_PEER_HT = 1<<0, + NL80211_TDLS_PEER_VHT = 1<<1, + NL80211_TDLS_PEER_WMM = 1<<2, +}; + #endif /* __LINUX_NL80211_H */ diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 3849fd07a321..1acb29109b45 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3644,8 +3644,8 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, u8 *peer, u8 action_code, u8 dialog_token, - u16 status_code, const u8 *extra_ies, - size_t extra_ies_len) + u16 status_code, u32 peer_capability, + const u8 *extra_ies, size_t extra_ies_len) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 058aa0e1a462..be836098d342 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -384,6 +384,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { .len = IEEE80211_QOS_MAP_LEN_MAX }, [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN }, [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 }, + [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 }, }; /* policy for the key attributes */ @@ -7269,6 +7270,7 @@ static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; u8 action_code, dialog_token; + u32 peer_capability = 0; u16 status_code; u8 *peer; @@ -7287,9 +7289,12 @@ static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info) action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]); status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]); dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]); + if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]) + peer_capability = + nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]); return rdev_tdls_mgmt(rdev, dev, peer, action_code, - dialog_token, status_code, + dialog_token, status_code, peer_capability, nla_data(info->attrs[NL80211_ATTR_IE]), nla_len(info->attrs[NL80211_ATTR_IE])); } diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index c8e225947adb..74d97d33c938 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -769,13 +769,16 @@ static inline int rdev_set_rekey_data(struct cfg80211_registered_device *rdev, static inline int rdev_tdls_mgmt(struct cfg80211_registered_device *rdev, struct net_device *dev, u8 *peer, u8 action_code, u8 dialog_token, - u16 status_code, const u8 *buf, size_t len) + u16 status_code, u32 peer_capability, + const u8 *buf, size_t len) { int ret; trace_rdev_tdls_mgmt(&rdev->wiphy, dev, peer, action_code, - dialog_token, status_code, buf, len); + dialog_token, status_code, peer_capability, + buf, len); ret = rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code, - dialog_token, status_code, buf, len); + dialog_token, status_code, peer_capability, + buf, len); trace_rdev_return_int(&rdev->wiphy, ret); return ret; } diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 5eaeed59db07..aabccf13e07b 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -1468,9 +1468,10 @@ TRACE_EVENT(rdev_sched_scan_start, TRACE_EVENT(rdev_tdls_mgmt, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 *peer, u8 action_code, u8 dialog_token, - u16 status_code, const u8 *buf, size_t len), + u16 status_code, u32 peer_capability, + const u8 *buf, size_t len), TP_ARGS(wiphy, netdev, peer, action_code, dialog_token, status_code, - buf, len), + peer_capability, buf, len), TP_STRUCT__entry( WIPHY_ENTRY NETDEV_ENTRY @@ -1478,6 +1479,7 @@ TRACE_EVENT(rdev_tdls_mgmt, __field(u8, action_code) __field(u8, dialog_token) __field(u16, status_code) + __field(u32, peer_capability) __dynamic_array(u8, buf, len) ), TP_fast_assign( @@ -1487,13 +1489,15 @@ TRACE_EVENT(rdev_tdls_mgmt, __entry->action_code = action_code; __entry->dialog_token = dialog_token; __entry->status_code = status_code; + __entry->peer_capability = peer_capability; memcpy(__get_dynamic_array(buf), buf, len); ), TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", action_code: %u, " - "dialog_token: %u, status_code: %u, buf: %#.2x ", + "dialog_token: %u, status_code: %u, peer_capability: %u buf: %#.2x ", WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->action_code, __entry->dialog_token, - __entry->status_code, ((u8 *)__get_dynamic_array(buf))[0]) + __entry->status_code, __entry->peer_capability, + ((u8 *)__get_dynamic_array(buf))[0]) ); TRACE_EVENT(rdev_dump_survey, From d9b8396a52b4e857263eeb9e1eba474ea11c19bf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 13 Feb 2014 17:16:10 +0100 Subject: [PATCH 188/414] cfg80211: document sched_scan_stop synchronous behaviour Due to userspace assumptions, the sched_scan_stop operation must be synchronous, i.e. once it returns a new scheduled scan must be able to start immediately. Document this in the API. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 7 ++++++- include/uapi/linux/nl80211.h | 5 +++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index c89a5b5bd103..7c9fe4b05927 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2206,7 +2206,12 @@ struct cfg80211_qos_map { * @set_cqm_txe_config: Configure connection quality monitor TX error * thresholds. * @sched_scan_start: Tell the driver to start a scheduled scan. - * @sched_scan_stop: Tell the driver to stop an ongoing scheduled scan. + * @sched_scan_stop: Tell the driver to stop an ongoing scheduled scan. This + * call must stop the scheduled scan and be ready for starting a new one + * before it returns, i.e. @sched_scan_start may be called immediately + * after that again and should not fail in that case. The driver should + * not call cfg80211_sched_scan_stopped() for a requested stop (when this + * method returns 0.) * * @mgmt_frame_register: Notify driver that a management frame type was * registered. Note that this callback may not sleep, and cannot run diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 47d7087513e0..81481cff1dc1 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -303,8 +303,9 @@ * passed, all channels allowed for the current regulatory domain * are used. Extra IEs can also be passed from the userspace by * using the %NL80211_ATTR_IE attribute. - * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT - * if scheduled scan is not running. + * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT if + * scheduled scan is not running. The caller may assume that as soon + * as the call returns, it is safe to start a new scheduled scan again. * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan * results available. * @NL80211_CMD_SCHED_SCAN_STOPPED: indicates that the scheduled scan has From 37e3308cb2b6933019d9d9c2045877d6d68d9c5a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Feb 2014 10:48:17 +0100 Subject: [PATCH 189/414] mac80211: allow driver to return error from sched_scan_stop In order to solve races with sched_scan_stop, it is necessary for the driver to be able to return an error to propagate that to cfg80211 so it doesn't send an event. Reviewed-by: Alexander Bondar Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 6 ++++-- drivers/net/wireless/ti/wlcore/main.c | 6 ++++-- include/net/mac80211.h | 3 ++- net/mac80211/driver-ops.h | 12 ++++++++---- net/mac80211/scan.c | 2 +- 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index beaf8140abbf..7492fc0f2766 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1746,14 +1746,16 @@ out: return ret; } -static void iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); mutex_lock(&mvm->mutex); iwl_mvm_sched_scan_stop(mvm); mutex_unlock(&mvm->mutex); + + return 0; } static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 7aae5b3a0c2c..4175a57ac9f5 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -3668,8 +3668,8 @@ out: return ret; } -static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static int wl1271_op_sched_scan_stop(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct wl1271 *wl = hw->priv; struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); @@ -3691,6 +3691,8 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw, wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); + + return 0; } static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a6bcc39e146e..86faa413b37d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2460,6 +2460,7 @@ enum ieee80211_roc_type { * This process will continue until sched_scan_stop is called. * * @sched_scan_stop: Tell the hardware to stop an ongoing scheduled scan. + * In this case, ieee80211_sched_scan_stopped() must not be called. * * @sw_scan_start: Notifier function that is called just before a software scan * is started. Can be NULL, if the driver doesn't need this notification. @@ -2807,7 +2808,7 @@ struct ieee80211_ops { struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, struct ieee80211_sched_scan_ies *ies); - void (*sched_scan_stop)(struct ieee80211_hw *hw, + int (*sched_scan_stop)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void (*sw_scan_start)(struct ieee80211_hw *hw); void (*sw_scan_complete)(struct ieee80211_hw *hw); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index ef8b385eff04..fc689f5d971e 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -354,16 +354,20 @@ drv_sched_scan_start(struct ieee80211_local *local, return ret; } -static inline void drv_sched_scan_stop(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata) +static inline int drv_sched_scan_stop(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) { + int ret; + might_sleep(); check_sdata_in_driver(sdata); trace_drv_sched_scan_stop(local, sdata); - local->ops->sched_scan_stop(&local->hw, &sdata->vif); - trace_drv_return_void(local); + ret = local->ops->sched_scan_stop(&local->hw, &sdata->vif); + trace_drv_return_int(local, ret); + + return ret; } static inline void drv_sw_scan_start(struct ieee80211_local *local) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index b211e412511f..836f500dfbf3 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -1056,7 +1056,7 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) local->sched_scan_req = NULL; if (rcu_access_pointer(local->sched_scan_sdata)) - drv_sched_scan_stop(local, sdata); + ret = drv_sched_scan_stop(local, sdata); out: mutex_unlock(&local->mtx); From 1270c416e1ba726b4a1d15167babfe5f2c0b59e6 Mon Sep 17 00:00:00 2001 From: Eytan Lifshitz Date: Tue, 18 Feb 2014 15:02:29 +0200 Subject: [PATCH 190/414] iwlwifi: mvm: fix possible memory leak iwl_parse_nvm_data() doesn't free allocated memory if it is fed with invalid parameter. Fix this. Signed-off-by: Eytan Lifshitz Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index df3ea60c87d9..80c40967cd35 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -516,6 +516,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, if (!nvm_calib) { IWL_ERR_DEV(dev, "Can't parse empty Calib NVM sections\n"); + kfree(data); return NULL; } /* in family 8000 Xtal calibration values moved to OTP */ From cfadc3ffccd5b75b4cd6babbfcd2271d37a82e90 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 12 Feb 2014 08:51:54 +0200 Subject: [PATCH 191/414] iwlwifi: pcie: stop the firmware when we restart it In case the firmware didn't assert but we want to restart it, e.g. we didn't get the reply for a host command, or the Tx queues are stuck, we should stop the firmware by provoking an interrupt. This allows to better debug the firmware in these bad scenarios. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/tx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index e476d9eda61a..3b0c72c10054 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -207,7 +207,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data) IWL_ERR(trans, "scratch %d = 0x%08x\n", i, le32_to_cpu(txq->scratchbufs[i].scratch)); - iwl_trans_fw_error(trans); + iwl_write_prph(trans, DEVICE_SET_NMI_REG, 1); } /* @@ -1024,7 +1024,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) if (nfreed++ > 0) { IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n", idx, q->write_ptr, q->read_ptr); - iwl_trans_fw_error(trans); + iwl_write_prph(trans, DEVICE_SET_NMI_REG, 1); } } @@ -1583,6 +1583,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, get_cmd_string(trans_pcie, cmd->id)); ret = -ETIMEDOUT; + iwl_write_prph(trans, DEVICE_SET_NMI_REG, 1); iwl_trans_fw_error(trans); goto cancel; From 1f6bf0786ebdd05660b82babcf059cf2b7c9053d Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 16 Feb 2014 15:36:00 +0200 Subject: [PATCH 192/414] iwlwifi: mvm: set immediate apply time bit in time events Newer firmware support a new bit in the policy that allows to request to apply the time event immediately. Add this bit without removing the workarounds we used until now to support older firmares. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 1 + drivers/net/wireless/iwlwifi/mvm/time-event.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 4d808a91ea7f..807fa525cafe 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -712,6 +712,7 @@ enum { TE_V2_NOTIF_HOST_FRAG_END = BIT(5), TE_V2_NOTIF_INTERNAL_FRAG_START = BIT(6), TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7), + T2_V2_START_IMMEDIATELY = BIT(11), TE_V2_NOTIF_MSK = 0xff, diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index e145dd41e85e..61331245ad93 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -438,7 +438,8 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, time_cmd.duration = cpu_to_le32(duration); time_cmd.repeat = 1; time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START | - TE_V2_NOTIF_HOST_EVENT_END); + TE_V2_NOTIF_HOST_EVENT_END | + T2_V2_START_IMMEDIATELY); iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); } @@ -553,7 +554,8 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration)); time_cmd.repeat = 1; time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START | - TE_V2_NOTIF_HOST_EVENT_END); + TE_V2_NOTIF_HOST_EVENT_END | + T2_V2_START_IMMEDIATELY); return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); } From 5fc0f76c43bdb19f8080a25b653569666a637306 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Tue, 28 Jan 2014 01:35:32 +0200 Subject: [PATCH 193/414] iwlwifi: mvm: add Rx frames statistics via debugfs Collect statistics regarding rates and aggregations in Rx frames and export the data via debugfs. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 72 +++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 29 +++++++++ drivers/net/wireless/iwlwifi/mvm/rs.c | 73 +++++++++++++++++++++- drivers/net/wireless/iwlwifi/mvm/rx.c | 13 ++++ 4 files changed, 185 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 3278b4890823..e0ff43ed2482 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -531,6 +531,76 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, } #undef PRINT_STAT_LE32 +static ssize_t iwl_dbgfs_frame_stats_read(struct iwl_mvm *mvm, + char __user *user_buf, size_t count, + loff_t *ppos, + struct iwl_mvm_frame_stats *stats) +{ + char *buff; + int pos = 0, idx, i; + int ret; + size_t bufsz = 1024; + + buff = kmalloc(bufsz, GFP_KERNEL); + if (!buff) + return -ENOMEM; + + spin_lock_bh(&mvm->drv_stats_lock); + pos += scnprintf(buff + pos, bufsz - pos, + "Legacy/HT/VHT\t:\t%d/%d/%d\n", + stats->legacy_frames, + stats->ht_frames, + stats->vht_frames); + pos += scnprintf(buff + pos, bufsz - pos, "20/40/80\t:\t%d/%d/%d\n", + stats->bw_20_frames, + stats->bw_40_frames, + stats->bw_80_frames); + pos += scnprintf(buff + pos, bufsz - pos, "NGI/SGI\t\t:\t%d/%d\n", + stats->ngi_frames, + stats->sgi_frames); + pos += scnprintf(buff + pos, bufsz - pos, "SISO/MIMO2\t:\t%d/%d\n", + stats->siso_frames, + stats->mimo2_frames); + pos += scnprintf(buff + pos, bufsz - pos, "FAIL/SCSS\t:\t%d/%d\n", + stats->fail_frames, + stats->success_frames); + pos += scnprintf(buff + pos, bufsz - pos, "MPDUs agg\t:\t%d\n", + stats->agg_frames); + pos += scnprintf(buff + pos, bufsz - pos, "A-MPDUs\t\t:\t%d\n", + stats->ampdu_count); + pos += scnprintf(buff + pos, bufsz - pos, "Avg MPDUs/A-MPDU:\t%d\n", + stats->ampdu_count > 0 ? + (stats->agg_frames / stats->ampdu_count) : 0); + + pos += scnprintf(buff + pos, bufsz - pos, "Last Rates\n"); + + idx = stats->last_frame_idx - 1; + for (i = 0; i < ARRAY_SIZE(stats->last_rates); i++) { + idx = (idx + 1) % ARRAY_SIZE(stats->last_rates); + if (stats->last_rates[idx] == 0) + continue; + pos += scnprintf(buff + pos, bufsz - pos, "Rate[%d]: ", + (int)(ARRAY_SIZE(stats->last_rates) - i)); + pos += rs_pretty_print_rate(buff + pos, stats->last_rates[idx]); + } + spin_unlock_bh(&mvm->drv_stats_lock); + + ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos); + kfree(buff); + + return ret; +} + +static ssize_t iwl_dbgfs_drv_rx_stats_read(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + + return iwl_dbgfs_frame_stats_read(mvm, user_buf, count, ppos, + &mvm->drv_rx_stats); +} + static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { @@ -959,6 +1029,7 @@ MVM_DEBUGFS_READ_FILE_OPS(bt_notif); MVM_DEBUGFS_READ_FILE_OPS(bt_cmd); MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64); MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); +MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats); MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10); MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); @@ -990,6 +1061,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir, S_IRUSR | S_IWUSR); MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR); + MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 823765ea89a9..5fb51099f99d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -425,6 +425,28 @@ struct iwl_mvm_tt_mgmt { bool throttle; }; +#define IWL_MVM_NUM_LAST_FRAMES_UCODE_RATES 8 + +struct iwl_mvm_frame_stats { + u32 legacy_frames; + u32 ht_frames; + u32 vht_frames; + u32 bw_20_frames; + u32 bw_40_frames; + u32 bw_80_frames; + u32 bw_160_frames; + u32 sgi_frames; + u32 ngi_frames; + u32 siso_frames; + u32 mimo2_frames; + u32 agg_frames; + u32 ampdu_count; + u32 success_frames; + u32 fail_frames; + u32 last_rates[IWL_MVM_NUM_LAST_FRAMES_UCODE_RATES]; + int last_frame_idx; +}; + struct iwl_mvm { /* for logger access */ struct device *dev; @@ -526,6 +548,9 @@ struct iwl_mvm { struct debugfs_blob_wrapper nvm_sw_blob; struct debugfs_blob_wrapper nvm_calib_blob; struct debugfs_blob_wrapper nvm_prod_blob; + + struct iwl_mvm_frame_stats drv_rx_stats; + spinlock_t drv_stats_lock; #endif struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX]; @@ -810,6 +835,10 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) /* rate scaling */ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init); +void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, + struct iwl_mvm_frame_stats *stats, + u32 rate, bool agg); +int rs_pretty_print_rate(char *buf, const u32 rate); /* power management */ int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 77c6e36c71cd..399709f2be2e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2240,6 +2240,73 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta, } } +#ifdef CONFIG_IWLWIFI_DEBUGFS +static void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm, + struct iwl_mvm_frame_stats *stats) +{ + spin_lock_bh(&mvm->drv_stats_lock); + memset(stats, 0, sizeof(*stats)); + spin_unlock_bh(&mvm->drv_stats_lock); +} + +void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, + struct iwl_mvm_frame_stats *stats, + u32 rate, bool agg) +{ + u8 nss = 0, mcs = 0; + + spin_lock(&mvm->drv_stats_lock); + + if (agg) + stats->agg_frames++; + + stats->success_frames++; + + switch (rate & RATE_MCS_CHAN_WIDTH_MSK) { + case RATE_MCS_CHAN_WIDTH_20: + stats->bw_20_frames++; + break; + case RATE_MCS_CHAN_WIDTH_40: + stats->bw_40_frames++; + break; + case RATE_MCS_CHAN_WIDTH_80: + stats->bw_80_frames++; + break; + default: + WARN_ONCE(1, "bad BW. rate 0x%x", rate); + } + + if (rate & RATE_MCS_HT_MSK) { + stats->ht_frames++; + mcs = rate & RATE_HT_MCS_RATE_CODE_MSK; + nss = ((rate & RATE_HT_MCS_NSS_MSK) >> RATE_HT_MCS_NSS_POS) + 1; + } else if (rate & RATE_MCS_VHT_MSK) { + stats->vht_frames++; + mcs = rate & RATE_VHT_MCS_RATE_CODE_MSK; + nss = ((rate & RATE_VHT_MCS_NSS_MSK) >> + RATE_VHT_MCS_NSS_POS) + 1; + } else { + stats->legacy_frames++; + } + + if (nss == 1) + stats->siso_frames++; + else if (nss == 2) + stats->mimo2_frames++; + + if (rate & RATE_MCS_SGI_MSK) + stats->sgi_frames++; + else + stats->ngi_frames++; + + stats->last_rates[stats->last_frame_idx] = rate; + stats->last_frame_idx = (stats->last_frame_idx + 1) % + ARRAY_SIZE(stats->last_rates); + + spin_unlock(&mvm->drv_stats_lock); +} +#endif + /* * Called after adding a new station to initialize rate scaling */ @@ -2334,7 +2401,9 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, #ifdef CONFIG_MAC80211_DEBUGFS lq_sta->dbg_fixed_rate = 0; #endif - +#ifdef CONFIG_IWLWIFI_DEBUGFS + iwl_mvm_reset_frame_stats(mvm, &mvm->drv_rx_stats); +#endif rs_initialize_lq(mvm, sta, lq_sta, band, init); } @@ -2546,7 +2615,7 @@ static void rs_free_sta(void *mvm_r, struct ieee80211_sta *sta, } #ifdef CONFIG_MAC80211_DEBUGFS -static int rs_pretty_print_rate(char *buf, const u32 rate) +int rs_pretty_print_rate(char *buf, const u32 rate) { char *type, *bw; diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 817d3e0b37e2..6061553a5e44 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -77,6 +77,15 @@ int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, memcpy(&mvm->last_phy_info, pkt->data, sizeof(mvm->last_phy_info)); mvm->ampdu_ref++; + +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (mvm->last_phy_info.phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) { + spin_lock(&mvm->drv_stats_lock); + mvm->drv_rx_stats.ampdu_count++; + spin_unlock(&mvm->drv_stats_lock); + } +#endif + return 0; } @@ -391,6 +400,10 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, rx_status.band); } +#ifdef CONFIG_IWLWIFI_DEBUGFS + iwl_mvm_update_frame_stats(mvm, &mvm->drv_rx_stats, rate_n_flags, + rx_status.flag & RX_FLAG_AMPDU_DETAILS); +#endif iwl_mvm_pass_packet_to_mac80211(mvm, hdr, len, ampdu_status, rxb, &rx_status); return 0; From b1765e7afe8710ef4366dc722cc5bd487eb07973 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Thu, 20 Feb 2014 16:42:01 +0100 Subject: [PATCH 194/414] Bluetooth: Fix channel check when binding RFCOMM sock When binding RFCOMM socket with non-zero channel we're checking if there is already any other socket which has the same channel number assigned and then fail. This check does not consider situation where we have another socket connected to remote device on given channel number in which case we still should be able to bind local socket. This patch changes __rfcomm_get_sock_by_addr() to return only sockets in either BT_BOUND or BT_LISTEN states, also name is updated to better describe what this function does now. Signed-off-by: Andrzej Kaczmarek Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/sock.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 00573fb79030..c024e715512f 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -105,13 +105,18 @@ static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err) } /* ---- Socket functions ---- */ -static struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src) +static struct sock *__rfcomm_get_listen_sock_by_addr(u8 channel, bdaddr_t *src) { struct sock *sk = NULL; sk_for_each(sk, &rfcomm_sk_list.head) { - if (rfcomm_pi(sk)->channel == channel && - !bacmp(&rfcomm_pi(sk)->src, src)) + if (rfcomm_pi(sk)->channel != channel) + continue; + + if (bacmp(&rfcomm_pi(sk)->src, src)) + continue; + + if (sk->sk_state == BT_BOUND || sk->sk_state == BT_LISTEN) break; } @@ -331,6 +336,7 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr { struct sockaddr_rc *sa = (struct sockaddr_rc *) addr; struct sock *sk = sock->sk; + int chan = sa->rc_channel; int err = 0; BT_DBG("sk %p %pMR", sk, &sa->rc_bdaddr); @@ -352,12 +358,12 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr write_lock(&rfcomm_sk_list.lock); - if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) { + if (chan && __rfcomm_get_listen_sock_by_addr(chan, &sa->rc_bdaddr)) { err = -EADDRINUSE; } else { /* Save source address */ bacpy(&rfcomm_pi(sk)->src, &sa->rc_bdaddr); - rfcomm_pi(sk)->channel = sa->rc_channel; + rfcomm_pi(sk)->channel = chan; sk->sk_state = BT_BOUND; } @@ -439,7 +445,7 @@ static int rfcomm_sock_listen(struct socket *sock, int backlog) write_lock(&rfcomm_sk_list.lock); for (channel = 1; channel < 31; channel++) - if (!__rfcomm_get_sock_by_addr(channel, src)) { + if (!__rfcomm_get_listen_sock_by_addr(channel, src)) { rfcomm_pi(sk)->channel = channel; err = 0; break; From 3f959d46a60c20eedf6f228e49d820c5922ec68f Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 20 Feb 2014 11:55:56 -0800 Subject: [PATCH 195/414] Bluetooth: Provide option for changing LE advertising channel map For testing purposes it is useful to provide an option to change the advertising channel map. So add a debugfs option to allow this. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 31 +++++++++++++++++++++++++++++++ net/bluetooth/mgmt.c | 2 +- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3a8e22e9b25d..c0fcc041fbb5 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -178,6 +178,7 @@ struct hci_dev { __u16 page_scan_interval; __u16 page_scan_window; __u8 page_scan_type; + __u8 le_adv_channel_map; __u16 le_scan_interval; __u16 le_scan_window; __u16 le_conn_min_interval; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 877330b4876f..67192867c998 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -757,6 +757,34 @@ static int conn_max_interval_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(conn_max_interval_fops, conn_max_interval_get, conn_max_interval_set, "%llu\n"); +static int adv_channel_map_set(void *data, u64 val) +{ + struct hci_dev *hdev = data; + + if (val < 0x01 || val > 0x07) + return -EINVAL; + + hci_dev_lock(hdev); + hdev->le_adv_channel_map = val; + hci_dev_unlock(hdev); + + return 0; +} + +static int adv_channel_map_get(void *data, u64 *val) +{ + struct hci_dev *hdev = data; + + hci_dev_lock(hdev); + *val = hdev->le_adv_channel_map; + hci_dev_unlock(hdev); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(adv_channel_map_fops, adv_channel_map_get, + adv_channel_map_set, "%llu\n"); + static ssize_t lowpan_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1605,6 +1633,8 @@ static int __hci_init(struct hci_dev *hdev) hdev, &conn_min_interval_fops); debugfs_create_file("conn_max_interval", 0644, hdev->debugfs, hdev, &conn_max_interval_fops); + debugfs_create_file("adv_channel_map", 0644, hdev->debugfs, + hdev, &adv_channel_map_fops); debugfs_create_file("6lowpan", 0644, hdev->debugfs, hdev, &lowpan_debugfs_fops); } @@ -3264,6 +3294,7 @@ struct hci_dev *hci_alloc_dev(void) hdev->sniff_max_interval = 800; hdev->sniff_min_interval = 80; + hdev->le_adv_channel_map = 0x07; hdev->le_scan_interval = 0x0060; hdev->le_scan_window = 0x0030; hdev->le_conn_min_interval = 0x0028; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 5f5e388716ec..12fa6399c796 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1374,7 +1374,7 @@ static void enable_advertising(struct hci_request *req) cp.max_interval = __constant_cpu_to_le16(0x0800); cp.type = get_adv_type(hdev); cp.own_address_type = hdev->own_addr_type; - cp.channel_map = 0x07; + cp.channel_map = hdev->le_adv_channel_map; hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp); From a747439957ee2d1696a2a1494e5ce0516e153f10 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 20 Feb 2014 12:44:20 -0800 Subject: [PATCH 196/414] Bluetooth: Increase minor version of core module With the addition of Resolvable Private Address (RPA) resolution support for Bluetooth Low Energy connections, it makes sense to increase the minor version of the Bluetooth core module. The module version is not used anywhere, but it gives a nice extra hint for debugging purposes. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/af_bluetooth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 0c5866bb49b6..2021c481cdb6 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -31,7 +31,7 @@ #include #include -#define VERSION "2.18" +#define VERSION "2.19" /* Bluetooth sockets */ #define BT_MAX_PROTO 8 From b0dfd2ea12d92b49639ad84f24ddd00c7ac144b5 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Thu, 20 Feb 2014 13:52:16 +0100 Subject: [PATCH 197/414] cfg80211: regulatory: introduce NL80211_RRF_AUTO_BW rule flag Introduce NL80211_RRF_AUTO_BW rule flag. If this flag set maximum available bandwidth should be calculated base on contiguous rules and wider channels will be allowed to cross multiple contiguous/overlapping frequency ranges. In case of old kernels maximum bandwidth from regulatory rule will be used, while there is no NL80211_RRF_AUTO_BW flag. This fixes the previous commit 9752482083066af7ac18a5ca376f ("cfg80211: regulatory introduce maximum bandwidth calculation") which was found to be a problem for userspace API compatibility. Signed-off-by: Janusz Dziedzic [edit commit log, use sizeof()] Signed-off-by: Johannes Berg Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 9 ++-- net/wireless/genregdb.awk | 2 + net/wireless/nl80211.c | 7 +-- net/wireless/reg.c | 83 ++++++++++++++++++++---------------- 4 files changed, 58 insertions(+), 43 deletions(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 81481cff1dc1..ff72cab3cd3a 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2443,10 +2443,7 @@ enum nl80211_reg_type { * in KHz. This is not a center a frequency but an actual regulatory * band edge. * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this - * frequency range, in KHz. If not present or 0, maximum available - * bandwidth should be calculated base on contiguous rules and wider - * channels will be allowed to cross multiple contiguous/overlapping - * frequency ranges. + * frequency range, in KHz. * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain * for a given frequency range. The value is in mBi (100 * dBi). * If you don't have one then don't send this. @@ -2517,6 +2514,9 @@ enum nl80211_sched_scan_match_attr { * @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed, * this includes probe requests or modes of operation that require * beaconing. + * @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated + * base on contiguous rules and wider channels will be allowed to cross + * multiple contiguous/overlapping frequency ranges. */ enum nl80211_reg_rule_flags { NL80211_RRF_NO_OFDM = 1<<0, @@ -2528,6 +2528,7 @@ enum nl80211_reg_rule_flags { NL80211_RRF_PTMP_ONLY = 1<<6, NL80211_RRF_NO_IR = 1<<7, __NL80211_RRF_NO_IBSS = 1<<8, + NL80211_RRF_AUTO_BW = 1<<11, }; #define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk index 9a8217d2a908..fdfd3f063a9b 100644 --- a/net/wireless/genregdb.awk +++ b/net/wireless/genregdb.awk @@ -105,6 +105,8 @@ function parse_reg_rule() flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " } else if (flagarray[arg] == "NO-IR") { flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " + } else if (flagarray[arg] == "AUTO-BW") { + flags = flags "\n\t\t\tNL80211_RRF_AUTO_BW | " } } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index be836098d342..1e5a434e4224 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4628,6 +4628,8 @@ static int parse_reg_rule(struct nlattr *tb[], return -EINVAL; if (!tb[NL80211_ATTR_FREQ_RANGE_END]) return -EINVAL; + if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) + return -EINVAL; if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) return -EINVAL; @@ -4637,9 +4639,8 @@ static int parse_reg_rule(struct nlattr *tb[], nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]); freq_range->end_freq_khz = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]); - if (tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) - freq_range->max_bandwidth_khz = - nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); + freq_range->max_bandwidth_khz = + nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); power_rule->max_eirp = nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]); diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 27c5253e7a61..6b6f33ad78f2 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -563,9 +563,6 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, if (freq_range_tmp->end_freq_khz < freq_range->start_freq_khz) break; - if (freq_range_tmp->max_bandwidth_khz) - break; - freq_range = freq_range_tmp; } @@ -582,9 +579,6 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, if (freq_range_tmp->start_freq_khz > freq_range->end_freq_khz) break; - if (freq_range_tmp->max_bandwidth_khz) - break; - freq_range = freq_range_tmp; } @@ -729,21 +723,29 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1, max_bandwidth1 = freq_range1->max_bandwidth_khz; max_bandwidth2 = freq_range2->max_bandwidth_khz; - /* - * In case max_bandwidth1 == 0 and max_bandwith2 == 0 set - * output bandwidth as 0 (auto calculation). Next we will - * calculate this correctly in handle_channel function. - * In other case calculate output bandwidth here. - */ - if (max_bandwidth1 || max_bandwidth2) { - if (!max_bandwidth1) - max_bandwidth1 = reg_get_max_bandwidth(rd1, rule1); - if (!max_bandwidth2) - max_bandwidth2 = reg_get_max_bandwidth(rd2, rule2); - } + if (rule1->flags & NL80211_RRF_AUTO_BW) + max_bandwidth1 = reg_get_max_bandwidth(rd1, rule1); + if (rule2->flags & NL80211_RRF_AUTO_BW) + max_bandwidth2 = reg_get_max_bandwidth(rd2, rule2); freq_range->max_bandwidth_khz = min(max_bandwidth1, max_bandwidth2); + intersected_rule->flags = rule1->flags | rule2->flags; + + /* + * In case NL80211_RRF_AUTO_BW requested for both rules + * set AUTO_BW in intersected rule also. Next we will + * calculate BW correctly in handle_channel function. + * In other case remove AUTO_BW flag while we calculate + * maximum bandwidth correctly and auto calculation is + * not required. + */ + if ((rule1->flags & NL80211_RRF_AUTO_BW) && + (rule2->flags & NL80211_RRF_AUTO_BW)) + intersected_rule->flags |= NL80211_RRF_AUTO_BW; + else + intersected_rule->flags &= ~NL80211_RRF_AUTO_BW; + freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; if (freq_range->max_bandwidth_khz > freq_diff) freq_range->max_bandwidth_khz = freq_diff; @@ -753,8 +755,6 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1, power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain, power_rule2->max_antenna_gain); - intersected_rule->flags = rule1->flags | rule2->flags; - if (!is_valid_reg_rule(intersected_rule)) return -EINVAL; @@ -938,31 +938,42 @@ const char *reg_initiator_name(enum nl80211_reg_initiator initiator) EXPORT_SYMBOL(reg_initiator_name); #ifdef CONFIG_CFG80211_REG_DEBUG -static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan, +static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd, + struct ieee80211_channel *chan, const struct ieee80211_reg_rule *reg_rule) { const struct ieee80211_power_rule *power_rule; const struct ieee80211_freq_range *freq_range; - char max_antenna_gain[32]; + char max_antenna_gain[32], bw[32]; power_rule = ®_rule->power_rule; freq_range = ®_rule->freq_range; if (!power_rule->max_antenna_gain) - snprintf(max_antenna_gain, 32, "N/A"); + snprintf(max_antenna_gain, sizeof(max_antenna_gain), "N/A"); else - snprintf(max_antenna_gain, 32, "%d", power_rule->max_antenna_gain); + snprintf(max_antenna_gain, sizeof(max_antenna_gain), "%d", + power_rule->max_antenna_gain); + + if (reg_rule->flags & NL80211_RRF_AUTO_BW) + snprintf(bw, sizeof(bw), "%d KHz, %d KHz AUTO", + freq_range->max_bandwidth_khz, + reg_get_max_bandwidth(regd, reg_rule)); + else + snprintf(bw, sizeof(bw), "%d KHz", + freq_range->max_bandwidth_khz); REG_DBG_PRINT("Updating information on frequency %d MHz with regulatory rule:\n", chan->center_freq); - REG_DBG_PRINT("%d KHz - %d KHz @ %d KHz), (%s mBi, %d mBm)\n", + REG_DBG_PRINT("%d KHz - %d KHz @ %s), (%s mBi, %d mBm)\n", freq_range->start_freq_khz, freq_range->end_freq_khz, - freq_range->max_bandwidth_khz, max_antenna_gain, + bw, max_antenna_gain, power_rule->max_eirp); } #else -static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan, +static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd, + struct ieee80211_channel *chan, const struct ieee80211_reg_rule *reg_rule) { return; @@ -1022,17 +1033,16 @@ static void handle_channel(struct wiphy *wiphy, return; } - chan_reg_rule_print_dbg(chan, reg_rule); + regd = reg_get_regdomain(wiphy); + chan_reg_rule_print_dbg(regd, chan, reg_rule); power_rule = ®_rule->power_rule; freq_range = ®_rule->freq_range; max_bandwidth_khz = freq_range->max_bandwidth_khz; /* Check if auto calculation requested */ - if (!max_bandwidth_khz) { - regd = reg_get_regdomain(wiphy); + if (reg_rule->flags & NL80211_RRF_AUTO_BW) max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); - } if (max_bandwidth_khz < MHZ_TO_KHZ(40)) bw_flags = IEEE80211_CHAN_NO_HT40; @@ -1437,14 +1447,14 @@ static void handle_channel_custom(struct wiphy *wiphy, return; } - chan_reg_rule_print_dbg(chan, reg_rule); + chan_reg_rule_print_dbg(regd, chan, reg_rule); power_rule = ®_rule->power_rule; freq_range = ®_rule->freq_range; max_bandwidth_khz = freq_range->max_bandwidth_khz; /* Check if auto calculation requested */ - if (!max_bandwidth_khz) + if (reg_rule->flags & NL80211_RRF_AUTO_BW) max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); if (max_bandwidth_khz < MHZ_TO_KHZ(40)) @@ -2254,11 +2264,12 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) freq_range = ®_rule->freq_range; power_rule = ®_rule->power_rule; - if (!freq_range->max_bandwidth_khz) - snprintf(bw, 32, "%d KHz, AUTO", + if (reg_rule->flags & NL80211_RRF_AUTO_BW) + snprintf(bw, sizeof(bw), "%d KHz, %d KHz AUTO", + freq_range->max_bandwidth_khz, reg_get_max_bandwidth(rd, reg_rule)); else - snprintf(bw, 32, "%d KHz", + snprintf(bw, sizeof(bw), "%d KHz", freq_range->max_bandwidth_khz); /* From 0fcf8ac5acb60839ada695b069362761f1f2da71 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 20 Feb 2014 16:45:33 +0200 Subject: [PATCH 198/414] cfg80211: docbook: fix small formatting error docbook (or one of its friends) gets confused with semi-colons in the argument descriptions, causing it to think that the semi-colon is marking a new section in the description of addr_mask in wiphy struct. Prevent this by using hyphens instead of semi-colons in the mask example. Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7c9fe4b05927..b36a822b9028 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2796,7 +2796,7 @@ struct wiphy_vendor_command { * @perm_addr: permanent MAC address of this device * @addr_mask: If the device supports multiple MAC addresses by masking, * set this to a mask with variable bits set to 1, e.g. if the last - * four bits are variable then set it to 00:...:00:0f. The actual + * four bits are variable then set it to 00-00-00-00-00-0f. The actual * variable bits shall be determined by the interfaces added, with * interfaces not matching the mask being rejected to be brought up. * @n_addresses: number of addresses in @addresses. From b80edbc177800623dd07240e19e69c7b16ee5cba Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 20 Feb 2014 16:45:34 +0200 Subject: [PATCH 199/414] cfg80211: docbook: add interface combinations documentation Add the ieee80211_iface_limit and the ieee80211_iface_combination structures to docbook. Reformat the examples of combinations slightly, so it looks a bit better on docbook. Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- Documentation/DocBook/80211.tmpl | 2 ++ include/net/cfg80211.h | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl index 46ad6faee9ab..044b76436e83 100644 --- a/Documentation/DocBook/80211.tmpl +++ b/Documentation/DocBook/80211.tmpl @@ -98,6 +98,8 @@ !Finclude/net/cfg80211.h priv_to_wiphy !Finclude/net/cfg80211.h set_wiphy_dev !Finclude/net/cfg80211.h wdev_priv +!Finclude/net/cfg80211.h ieee80211_iface_limit +!Finclude/net/cfg80211.h ieee80211_iface_combination Actions and configuration diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index b36a822b9028..8c9ba44fb7cf 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2616,9 +2616,12 @@ struct ieee80211_iface_limit { * only in special cases. * @radar_detect_widths: bitmap of channel widths supported for radar detection * - * These examples can be expressed as follows: + * With this structure the driver can describe which interface + * combinations it supports concurrently. * - * Allow #STA <= 1, #AP <= 1, matching BI, channels = 1, 2 total: + * Examples: + * + * 1. Allow #STA <= 1, #AP <= 1, matching BI, channels = 1, 2 total: * * struct ieee80211_iface_limit limits1[] = { * { .max = 1, .types = BIT(NL80211_IFTYPE_STATION), }, @@ -2632,7 +2635,7 @@ struct ieee80211_iface_limit { * }; * * - * Allow #{AP, P2P-GO} <= 8, channels = 1, 8 total: + * 2. Allow #{AP, P2P-GO} <= 8, channels = 1, 8 total: * * struct ieee80211_iface_limit limits2[] = { * { .max = 8, .types = BIT(NL80211_IFTYPE_AP) | @@ -2646,7 +2649,8 @@ struct ieee80211_iface_limit { * }; * * - * Allow #STA <= 1, #{P2P-client,P2P-GO} <= 3 on two channels, 4 total. + * 3. Allow #STA <= 1, #{P2P-client,P2P-GO} <= 3 on two channels, 4 total. + * * This allows for an infrastructure connection and three P2P connections. * * struct ieee80211_iface_limit limits3[] = { From 30f55dc171a32d60e3753c9e0a3cf33a4d6c4610 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 20 Feb 2014 16:41:51 +0200 Subject: [PATCH 200/414] mac80211: allow drivers to request SMPS off Previously we were warning and using automatic when a driver sent an update request with SMPS off. This patch makes it possible for drivers to disable SMPS at runtime, for whatever reason. Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- net/mac80211/ht.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index afbe2b203c3e..c150b68436d7 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -482,8 +482,6 @@ void ieee80211_request_smps(struct ieee80211_vif *vif, return; if (vif->type == NL80211_IFTYPE_STATION) { - if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF)) - smps_mode = IEEE80211_SMPS_AUTOMATIC; if (sdata->u.mgd.driver_smps_mode == smps_mode) return; sdata->u.mgd.driver_smps_mode = smps_mode; From e5d2f954714bccd4a87e042720ae8e85f9a0aada Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 20 Feb 2014 16:36:20 +0200 Subject: [PATCH 201/414] nl80211: make sure we check for DFS with mesh channel switch Since mesh support for DFS channels was added, we also need to check for DFS channels when performing a channel switch with NL80211_IFTYPE_MESHPOINT. Signed-off-by: Luciano Coelho [use switch statement, slight code cleanup] Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1e5a434e4224..2c38b28a85b9 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5913,17 +5913,22 @@ skip_beacons: if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef)) return -EINVAL; - if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP || - dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO || - dev->ieee80211_ptr->iftype == NL80211_IFTYPE_ADHOC) { + switch (dev->ieee80211_ptr->iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: err = cfg80211_chandef_dfs_required(wdev->wiphy, ¶ms.chandef); - if (err < 0) { + if (err < 0) return err; - } else if (err) { + if (err) { radar_detect_width = BIT(params.chandef.width); params.radar_required = true; } + break; + default: + break; } err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, From 7b2106aea2638948806df248215b14efd84c5ffc Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 20 Feb 2014 16:36:21 +0200 Subject: [PATCH 202/414] cfg80211: remove radar requirements check from cfg80211_can_use_iftype_chan() We don't have to double check whether the parameters passed to cfg80211_can_use_iftype_chan() are correct. We should just make sure they *are* when we call this function. Remove the radar_detect argument check in cfg80211_can_use_iftype_chan() to simplify the code. Signed-off-by: Luciano Coelho [keep braces around a long comment + single statement] Signed-off-by: Johannes Berg --- net/wireless/ibss.c | 7 +++---- net/wireless/mesh.c | 6 ++++++ net/wireless/util.c | 31 +------------------------------ 3 files changed, 10 insertions(+), 34 deletions(-) diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 1470b90e438f..349db9ddc0d1 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -128,12 +128,11 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, #endif check_chan = params->chandef.chan; if (params->userspace_handles_dfs) { - /* use channel NULL to check for radar even if the current - * channel is not a radar channel - it might decide to change - * to DFS channel later. + /* Check for radar even if the current channel is not + * a radar channel - it might decide to change to DFS + * channel later. */ radar_detect_width = BIT(params->chandef.width); - check_chan = NULL; } err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index d42a3fcb2f67..5af5cc6b2c4c 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -236,6 +236,12 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, if (!netif_running(wdev->netdev)) return -ENETDOWN; + /* cfg80211_can_use_chan() calls + * cfg80211_can_use_iftype_chan() with no radar + * detection, so if we're trying to use a radar + * channel here, something is wrong. + */ + WARN_ON_ONCE(chandef->chan->flags & IEEE80211_CHAN_RADAR); err = cfg80211_can_use_chan(rdev, wdev, chandef->chan, CHAN_MODE_SHARED); if (err) diff --git a/net/wireless/util.c b/net/wireless/util.c index 780b4546c9c7..57b3ce7a6b92 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1269,7 +1269,6 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, enum cfg80211_chan_mode chmode; int num_different_channels = 0; int total = 1; - bool radar_required = false; int i, j; ASSERT_RTNL(); @@ -1277,35 +1276,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, if (WARN_ON(hweight32(radar_detect) > 1)) return -EINVAL; - switch (iftype) { - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_AP_VLAN: - case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_P2P_GO: - case NL80211_IFTYPE_WDS: - /* if the interface could potentially choose a DFS channel, - * then mark DFS as required. - */ - if (!chan) { - if (chanmode != CHAN_MODE_UNDEFINED && radar_detect) - radar_required = true; - break; - } - radar_required = !!(chan->flags & IEEE80211_CHAN_RADAR); - break; - case NL80211_IFTYPE_P2P_CLIENT: - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_P2P_DEVICE: - case NL80211_IFTYPE_MONITOR: - break; - case NUM_NL80211_IFTYPES: - case NL80211_IFTYPE_UNSPECIFIED: - default: - return -EINVAL; - } - - if (radar_required && !radar_detect) + if (WARN_ON(iftype >= NUM_NL80211_IFTYPES)) return -EINVAL; /* Always allow software iftypes */ From 6658ab80fd4ef940fc2366ddb66690a15ea69c18 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 20 Feb 2014 16:36:23 +0200 Subject: [PATCH 203/414] mac80211: ibss: handle cfg80211_chandef_dfs_required() error codes Error codes returned by cfg80211_chandef_dfs_required() are ignored when trying to join an IBSS. Fix this by printing an error and returning. Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- net/mac80211/ibss.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 4453e2725e40..e458ca0dffec 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -283,6 +283,11 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, &chandef); + if (err < 0) { + sdata_info(sdata, + "Failed to join IBSS, invalid chandef\n"); + return; + } if (err > 0) { if (!ifibss->userspace_handles_dfs) { sdata_info(sdata, From 668b7b19820b0801c425d31cc27fd6f499050e5c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 21 Feb 2014 16:03:31 +0200 Subject: [PATCH 204/414] Bluetooth: Fix iterating wrong list in hci_remove_irk() We should be iterating hdev->identity_resolving_keys in the hci_remove_irk() function instead of hdev->long_term_keys. This patch fixes the issue. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- net/bluetooth/hci_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 67192867c998..964aa8deb009 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2937,7 +2937,7 @@ void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type) { struct smp_irk *k, *tmp; - list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) { + list_for_each_entry_safe(k, tmp, &hdev->identity_resolving_keys, list) { if (bacmp(bdaddr, &k->bdaddr) || k->addr_type != addr_type) continue; From 1b60ef210e90cc116b9c976ff9fb8b656b3ebb76 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 21 Feb 2014 21:35:30 -0800 Subject: [PATCH 205/414] Bluetooth: Fix issue with missing management event opcode The event opcode for New Identity Resolving Key event is missing from supported event list. Just add it there. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 12fa6399c796..bc329d911706 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -106,6 +106,7 @@ static const u16 mgmt_events[] = { MGMT_EV_DEVICE_UNBLOCKED, MGMT_EV_DEVICE_UNPAIRED, MGMT_EV_PASSKEY_NOTIFY, + MGMT_EV_NEW_IRK, }; #define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000) From 524237cb4b566ae73ec24c56852489b85e426241 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 22 Feb 2014 19:06:31 +0200 Subject: [PATCH 206/414] Bluetooth: Add helper variables to smp_distribute_keys() This patch a couple of helper variables to the smp_distribute_keys function in order to avoid long chains of dereferences and thereby help readability. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index f06068072bdd..6355a460e9d0 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1132,22 +1132,24 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) { struct smp_cmd_pairing *req, *rsp; struct smp_chan *smp = conn->smp_chan; + struct hci_conn *hcon = conn->hcon; + struct hci_dev *hdev = hcon->hdev; __u8 *keydist; BT_DBG("conn %p force %d", conn, force); - if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) + if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; rsp = (void *) &smp->prsp[1]; /* The responder sends its keys first */ - if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07)) + if (!force && hcon->out && (rsp->resp_key_dist & 0x07)) return 0; req = (void *) &smp->preq[1]; - if (conn->hcon->out) { + if (hcon->out) { keydist = &rsp->init_key_dist; *keydist &= req->init_key_dist; } else { @@ -1160,7 +1162,6 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) if (*keydist & SMP_DIST_ENC_KEY) { struct smp_cmd_encrypt_info enc; struct smp_cmd_master_ident ident; - struct hci_conn *hcon = conn->hcon; struct smp_ltk *ltk; u8 authenticated; __le16 ediv; @@ -1172,7 +1173,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc); authenticated = hcon->sec_level == BT_SECURITY_HIGH; - ltk = hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, + ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK_SLAVE, authenticated, enc.ltk, smp->enc_key_size, ediv, ident.rand); smp->slave_ltk = ltk; @@ -1195,7 +1196,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) /* Just public address */ memset(&addrinfo, 0, sizeof(addrinfo)); - bacpy(&addrinfo.bdaddr, &conn->hcon->src); + bacpy(&addrinfo.bdaddr, &hcon->src); smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo), &addrinfo); @@ -1214,8 +1215,8 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) *keydist &= ~SMP_DIST_SIGN; } - if (conn->hcon->out || force || !(rsp->init_key_dist & 0x07)) { - clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); + if (hcon->out || force || !(rsp->init_key_dist & 0x07)) { + clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags); cancel_delayed_work_sync(&conn->security_timer); set_bit(SMP_FLAG_COMPLETE, &smp->smp_flags); smp_notify_keys(conn); From 863efaf224d24705c0ffdc59f2a0ec68f2d85b4f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 22 Feb 2014 19:06:32 +0200 Subject: [PATCH 207/414] Bluetooth: Add initial code for distributing local IRK This code adds a HCI_PRIVACY flag to track whether Privacy support is enabled (meaning we have a local IRK) and makes sure the IRK is distributed during SMP key distribution in case this flag is set. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/smp.c | 6 ++++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index fe4b06bfc150..5ff885ff29df 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -126,6 +126,7 @@ enum { HCI_SSP_ENABLED, HCI_SC_ENABLED, HCI_SC_ONLY, + HCI_PRIVACY, HCI_RPA_RESOLVING, HCI_HS_ENABLED, HCI_LE_ENABLED, diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index c0fcc041fbb5..68bbcabdd9fd 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -303,6 +303,8 @@ struct hci_dev { __u8 scan_rsp_data[HCI_MAX_AD_LENGTH]; __u8 scan_rsp_data_len; + __u8 irk[16]; + int (*open)(struct hci_dev *hdev); int (*close)(struct hci_dev *hdev); int (*flush)(struct hci_dev *hdev); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 6355a460e9d0..8ef50c790b96 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -265,6 +265,9 @@ static void build_pairing_cmd(struct l2cap_conn *conn, if (test_bit(HCI_RPA_RESOLVING, &hdev->dev_flags)) remote_dist |= SMP_DIST_ID_KEY; + if (test_bit(HCI_PRIVACY, &hdev->dev_flags)) + local_dist |= SMP_DIST_ID_KEY; + if (rsp == NULL) { req->io_capability = conn->hcon->io_capability; req->oob_flag = SMP_OOB_NOT_PRESENT; @@ -1189,8 +1192,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) struct smp_cmd_ident_addr_info addrinfo; struct smp_cmd_ident_info idinfo; - /* Send a dummy key */ - get_random_bytes(idinfo.irk, sizeof(idinfo.irk)); + memcpy(idinfo.irk, hdev->irk, sizeof(idinfo.irk)); smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo); From 199a2fb14d1d4cb2a1eb2fe05b725f36bb4f55ba Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 22 Feb 2014 19:06:33 +0200 Subject: [PATCH 208/414] Bluetooth: Move enable/disable_advertising higher up in mgmt.c These functions will soon be needed by the RPA regeneration timeout so move them higher up in mgmt.c to avoid a forward declaration. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 88 ++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bc329d911706..37a6c4eab881 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -812,6 +812,50 @@ static void update_class(struct hci_request *req) hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod); } +static u8 get_adv_type(struct hci_dev *hdev) +{ + struct pending_cmd *cmd; + bool connectable; + + /* If there's a pending mgmt command the flag will not yet have + * it's final value, so check for this first. + */ + cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev); + if (cmd) { + struct mgmt_mode *cp = cmd->param; + connectable = !!cp->val; + } else { + connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags); + } + + return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND; +} + +static void enable_advertising(struct hci_request *req) +{ + struct hci_dev *hdev = req->hdev; + struct hci_cp_le_set_adv_param cp; + u8 enable = 0x01; + + memset(&cp, 0, sizeof(cp)); + cp.min_interval = __constant_cpu_to_le16(0x0800); + cp.max_interval = __constant_cpu_to_le16(0x0800); + cp.type = get_adv_type(hdev); + cp.own_address_type = hdev->own_addr_type; + cp.channel_map = hdev->le_adv_channel_map; + + hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp); + + hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); +} + +static void disable_advertising(struct hci_request *req) +{ + u8 enable = 0x00; + + hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); +} + static void service_cache_off(struct work_struct *work) { struct hci_dev *hdev = container_of(work, struct hci_dev, @@ -1345,50 +1389,6 @@ static void write_fast_connectable(struct hci_request *req, bool enable) hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type); } -static u8 get_adv_type(struct hci_dev *hdev) -{ - struct pending_cmd *cmd; - bool connectable; - - /* If there's a pending mgmt command the flag will not yet have - * it's final value, so check for this first. - */ - cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev); - if (cmd) { - struct mgmt_mode *cp = cmd->param; - connectable = !!cp->val; - } else { - connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags); - } - - return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND; -} - -static void enable_advertising(struct hci_request *req) -{ - struct hci_dev *hdev = req->hdev; - struct hci_cp_le_set_adv_param cp; - u8 enable = 0x01; - - memset(&cp, 0, sizeof(cp)); - cp.min_interval = __constant_cpu_to_le16(0x0800); - cp.max_interval = __constant_cpu_to_le16(0x0800); - cp.type = get_adv_type(hdev); - cp.own_address_type = hdev->own_addr_type; - cp.channel_map = hdev->le_adv_channel_map; - - hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp); - - hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); -} - -static void disable_advertising(struct hci_request *req) -{ - u8 enable = 0x00; - - hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); -} - static void set_connectable_complete(struct hci_dev *hdev, u8 status) { struct pending_cmd *cmd; From 755a900fcde16c66223a85259859a3b534b6c64c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 22 Feb 2014 19:06:34 +0200 Subject: [PATCH 209/414] Bluetooth: Add mgmt defines for privacy This patch adds basic mgmt defines for enabling privacy. This includes a new setting flag as well as the Set Privacy command. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 2e46251e8aec..62d560624e3d 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -96,6 +96,7 @@ struct mgmt_rp_read_index_list { #define MGMT_SETTING_ADVERTISING 0x00000400 #define MGMT_SETTING_SECURE_CONN 0x00000800 #define MGMT_SETTING_DEBUG_KEYS 0x00001000 +#define MGMT_SETTING_PRIVACY 0x00002000 #define MGMT_OP_READ_INFO 0x0004 #define MGMT_READ_INFO_SIZE 0 @@ -389,6 +390,13 @@ struct mgmt_cp_set_scan_params { #define MGMT_OP_SET_DEBUG_KEYS 0x002E +#define MGMT_OP_SET_PRIVACY 0x002F +struct mgmt_cp_set_privacy { + __u8 privacy; + __u8 irk[16]; +} __packed; +#define MGMT_SET_PRIVACY_SIZE 17 + struct mgmt_irk_info { struct mgmt_addr_info addr; __u8 val[16]; From 0f4bd942f13dd15a1b290953cdd7cd6aca11be1f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 22 Feb 2014 19:06:35 +0200 Subject: [PATCH 210/414] Bluetooth: Add Privacy flag to mgmt supported/current settings This patch makes sure that the Privacy flag is available in the mgmt supported settings for all LE capable controllers and in the current settings whenever the HCI_PRIVACY flag is set. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 37a6c4eab881..301b18a1c6a0 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -390,6 +390,7 @@ static u32 get_supported_settings(struct hci_dev *hdev) if (lmp_le_capable(hdev)) { settings |= MGMT_SETTING_LE; settings |= MGMT_SETTING_ADVERTISING; + settings |= MGMT_SETTING_PRIVACY; } return settings; @@ -438,6 +439,9 @@ static u32 get_current_settings(struct hci_dev *hdev) if (test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags)) settings |= MGMT_SETTING_DEBUG_KEYS; + if (test_bit(HCI_PRIVACY, &hdev->dev_flags)) + settings |= MGMT_SETTING_PRIVACY; + return settings; } From fde73834eadb56962fd3b00f231ce58de5f00170 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 12 Feb 2014 22:02:38 +0100 Subject: [PATCH 211/414] iwlwifi: nvm: remove reading valid antennas from NVM These values aren't used as the firmware values should be used, so reading them is pointless and hides potential errors when somebody uses these values. Leave them zero to make it clearer that they can't be used. We can't remove the struct members as the DVM driver does read the values from EEPROM/OTP and the structure is shared between drivers. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 17 ----------------- drivers/net/wireless/iwlwifi/mvm/fw.c | 2 -- 2 files changed, 19 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 80c40967cd35..eeb3a838c1bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -425,8 +425,6 @@ static void iwl_set_radio_cfg(const struct iwl_cfg *cfg, data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg); data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg); data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg); - data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK(radio_cfg); - data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK(radio_cfg); return; } @@ -435,8 +433,6 @@ static void iwl_set_radio_cfg(const struct iwl_cfg *cfg, data->radio_cfg_step = NVM_RF_CFG_STEP_MSK_FAMILY_8000(radio_cfg); data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK_FAMILY_8000(radio_cfg); data->radio_cfg_pnum = NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(radio_cfg); - data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(radio_cfg); - data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(radio_cfg); } static void iwl_set_hw_address(const struct iwl_cfg *cfg, @@ -496,19 +492,6 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) data->sku_cap_11n_enable = false; - /* check overrides (some devices have wrong NVM) */ - if (cfg->valid_tx_ant) - data->valid_tx_ant = cfg->valid_tx_ant; - if (cfg->valid_rx_ant) - data->valid_rx_ant = cfg->valid_rx_ant; - - if (!data->valid_tx_ant || !data->valid_rx_ant) { - IWL_ERR_DEV(dev, "invalid antennas (0x%x, 0x%x)\n", - data->valid_tx_ant, data->valid_rx_ant); - kfree(data); - return NULL; - } - data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw); if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 979b35bae056..93e1b4d64869 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -358,8 +358,6 @@ out: GFP_KERNEL); if (!mvm->nvm_data) return -ENOMEM; - mvm->nvm_data->valid_rx_ant = 1; - mvm->nvm_data->valid_tx_ant = 1; mvm->nvm_data->bands[0].channels = mvm->nvm_data->channels; mvm->nvm_data->bands[0].n_channels = 1; mvm->nvm_data->bands[0].n_bitrates = 1; From d6cb37a35932d179a58f20b5ad6806d8592d36b4 Mon Sep 17 00:00:00 2001 From: Inbal Hacohen Date: Sun, 23 Feb 2014 10:34:11 +0200 Subject: [PATCH 212/414] iwlwifi: mvm: remove redundant define in fw.c This define is a leftover from dvm (in mvm, it was replaced by MVM_UCODE_ALIVE_TIMEOUT). Signed-off-by: Inbal Hacohen Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 93e1b4d64869..7ce20062f32d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -369,8 +369,6 @@ out: return ret; } -#define UCODE_CALIB_TIMEOUT (2*HZ) - int iwl_mvm_up(struct iwl_mvm *mvm) { int ret, i; From a2978b1162c5a55f8411e34519d343713e8ec7a3 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Thu, 20 Feb 2014 11:00:01 +0200 Subject: [PATCH 213/414] iwlwifi: mvm: prepare infrastructure for more TLV flags We use the TLV flags as a handshake between the firmware and the driver. These flags allow the firmware to advertise its capabilities and API version. Since we are running short of bits, we add a new infrastructure which is more scalable, yet backward compatible. We make now the difference between API changes and the capabilities. Both can have an index which allows to scale at will. Signed-off-by: Eran Harary Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-drv.c | 44 ++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-fw-file.h | 17 +++++++++ drivers/net/wireless/iwlwifi/iwl-fw.h | 4 ++ 3 files changed, 65 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 662d9936485c..d49e9b9ac06a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -404,6 +404,38 @@ static int iwl_set_default_calib(struct iwl_drv *drv, const u8 *data) return 0; } +static int iwl_set_ucode_api_flags(struct iwl_drv *drv, const u8 *data, + struct iwl_ucode_capabilities *capa) +{ + const struct iwl_ucode_api *ucode_api = (void *)data; + u32 api_index = le32_to_cpu(ucode_api->api_index); + + if (api_index >= IWL_API_ARRAY_SIZE) { + IWL_ERR(drv, "api_index larger than supported by driver\n"); + return -EINVAL; + } + + capa->api[api_index] = le32_to_cpu(ucode_api->api_flags); + + return 0; +} + +static int iwl_set_ucode_capabilities(struct iwl_drv *drv, const u8 *data, + struct iwl_ucode_capabilities *capa) +{ + const struct iwl_ucode_capa *ucode_capa = (void *)data; + u32 api_index = le32_to_cpu(ucode_capa->api_index); + + if (api_index >= IWL_CAPABILITIES_ARRAY_SIZE) { + IWL_ERR(drv, "api_index larger than supported by driver\n"); + return -EINVAL; + } + + capa->capa[api_index] = le32_to_cpu(ucode_capa->api_capa); + + return 0; +} + static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv, const struct firmware *ucode_raw, struct iwl_firmware_pieces *pieces) @@ -638,6 +670,18 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, */ capa->flags = le32_to_cpup((__le32 *)tlv_data); break; + case IWL_UCODE_TLV_API_CHANGES_SET: + if (tlv_len != sizeof(struct iwl_ucode_api)) + goto invalid_tlv_len; + if (iwl_set_ucode_api_flags(drv, tlv_data, capa)) + goto tlv_error; + break; + case IWL_UCODE_TLV_ENABLED_CAPABILITIES: + if (tlv_len != sizeof(struct iwl_ucode_capa)) + goto invalid_tlv_len; + if (iwl_set_ucode_capabilities(drv, tlv_data, capa)) + goto tlv_error; + break; case IWL_UCODE_TLV_INIT_EVTLOG_PTR: if (tlv_len != sizeof(u32)) goto invalid_tlv_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 88e2d6eb569f..b45e576a4b57 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -126,6 +126,8 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_SECURE_SEC_WOWLAN = 26, IWL_UCODE_TLV_NUM_OF_CPU = 27, IWL_UCODE_TLV_CSCHEME = 28, + IWL_UCODE_TLV_API_CHANGES_SET = 29, + IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30, }; struct iwl_ucode_tlv { @@ -158,4 +160,19 @@ struct iwl_tlv_ucode_header { u8 data[0]; }; +/* + * ucode TLVs + * + * ability to get extension for: flags & capabilities from ucode binaries files + */ +struct iwl_ucode_api { + __le32 api_index; + __le32 api_flags; +} __packed; + +struct iwl_ucode_capa { + __le32 api_index; + __le32 api_capa; +} __packed; + #endif /* __iwl_fw_file_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index af6b4528d499..f04ff871dc6d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -165,11 +165,15 @@ enum iwl_ucode_sec { * just an offset to the HW address. */ #define IWL_UCODE_SECTION_MAX 12 +#define IWL_API_ARRAY_SIZE 1 +#define IWL_CAPABILITIES_ARRAY_SIZE 1 struct iwl_ucode_capabilities { u32 max_probe_length; u32 standard_phy_calibration_size; u32 flags; + u32 api[IWL_API_ARRAY_SIZE]; + u32 capa[IWL_CAPABILITIES_ARRAY_SIZE]; }; /* one for each uCode image (inst/data, init/runtime/wowlan) */ From 82b715c211a53e80a1db83b9b71995a05fe32908 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 11 Feb 2014 16:54:42 +0200 Subject: [PATCH 214/414] iwlwifi: mvm: fix a few wd_disable comments Few minor comments. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-drv.c | 3 +-- drivers/net/wireless/iwlwifi/iwl-modparams.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index d49e9b9ac06a..847a0eded40a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1351,8 +1351,7 @@ MODULE_PARM_DESC(antenna_coupling, module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO); MODULE_PARM_DESC(wd_disable, - "Disable stuck queue watchdog timer 0=system default, " - "1=disable, 2=enable (default: 0)"); + "Disable stuck queue watchdog timer 0=system default, 1=disable (default: 1)"); module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO); MODULE_PARM_DESC(nvm_file, "NVM file name"); diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index 0a84ade7edac..1d100f24804c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h @@ -93,7 +93,7 @@ enum iwl_power_level { * use IWL_DISABLE_HT_* constants * @amsdu_size_8K: enable 8K amsdu size, default = 0 * @restart_fw: restart firmware, default = 1 - * @wd_disable: enable stuck queue check, default = 0 + * @wd_disable: disable stuck queue check, default = 1 * @bt_coex_active: enable bt coex, default = true * @led_mode: system default, default = 0 * @power_save: disable power save, default = false From 7be2edbbb87a34fbf1441991a679af94fe1d981d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 23 Feb 2014 19:42:17 +0200 Subject: [PATCH 215/414] Bluetooth: Ensure hci_conn always contains the local identity address To be consistent with the remote address info in hci_conn we want it to also contain the local identity address information. This patch updates the code to copy the right values in place whenever an LE connection has been established. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 4327b129d38e..064d619344b3 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3625,6 +3625,26 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) } } + /* Ensure that the hci_conn contains the identity address type + * regardless of which address the connection was made with. + * + * If the controller has a public BD_ADDR, then by default + * use that one. If this is a LE only controller without + * a public address, default to the static random address. + * + * For debugging purposes it is possible to force + * controllers with a public address to use the static + * random address instead. + */ + if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags) || + !bacmp(&hdev->bdaddr, BDADDR_ANY)) { + bacpy(&conn->src, &hdev->static_addr); + conn->src_type = ADDR_LE_DEV_RANDOM; + } else { + bacpy(&conn->src, &hdev->bdaddr); + conn->src_type = ADDR_LE_DEV_PUBLIC; + } + /* Lookup the identity address from the stored connection * address and address type. * From 82d4b3592378e88ddbb42a8db9bd4a99c399c3c4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 23 Feb 2014 19:42:18 +0200 Subject: [PATCH 216/414] Bluetooth: Set the correct values for Identity Address Information The SMP Identity Address Information PDU should contain our Identity Address. This patch updates the code to copy the correct values from the hci_conn object. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 8ef50c790b96..b9eef494fc0a 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1196,9 +1196,14 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo); - /* Just public address */ - memset(&addrinfo, 0, sizeof(addrinfo)); + /* The hci_conn contains the local identity address + * after the connection has been established. + * + * This is true even when the connection has been + * established using a resolvable random address. + */ bacpy(&addrinfo.bdaddr, &hcon->src); + addrinfo.addr_type = hcon->src_type; smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo), &addrinfo); From b1e2b3ae97620752905e58a9682fad7222796566 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 23 Feb 2014 19:42:19 +0200 Subject: [PATCH 217/414] Bluetooth: Add SMP function for generating RPAs We need a function in smp.c to generate Resolvable Random Addresses in order to support privacy. The local RPA will need to be generated before advertising, scanning or connecting and regenerated at periodic intervals. This patch adds the necessary function for RPA generation. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 18 ++++++++++++++++++ net/bluetooth/smp.h | 1 + 2 files changed, 19 insertions(+) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index b9eef494fc0a..79a80f44c832 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -124,6 +124,24 @@ bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16], return !memcmp(bdaddr->b, hash, 3); } +int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa) +{ + int err; + + get_random_bytes(&rpa->b[3], 3); + + rpa->b[5] &= 0x3f; /* Clear two most significant bits */ + rpa->b[5] |= 0x40; /* Set second most significant bit */ + + err = smp_ah(tfm, irk, &rpa->b[3], rpa->b); + if (err < 0) + return err; + + BT_DBG("RPA %pMR", rpa); + + return 0; +} + static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16], u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia, u8 _rat, bdaddr_t *ra, u8 res[16]) diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index d8cc543f523c..f32f1212f650 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -152,5 +152,6 @@ void smp_chan_destroy(struct l2cap_conn *conn); bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *bdaddr); +int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa); #endif /* __SMP_H */ From d6bfd59caef7e543c7786af9664309dd1a7f6396 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 23 Feb 2014 19:42:20 +0200 Subject: [PATCH 218/414] Bluetooth: Add timer for regenerating local RPA This patch adds a timer for updating the local RPA periodically. The default timeout is set to 15 minutes. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/hci_core.h | 5 +++++ net/bluetooth/hci_core.c | 4 ++++ net/bluetooth/mgmt.c | 27 +++++++++++++++++++++++++++ 4 files changed, 37 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 5ff885ff29df..1bb45a47a78a 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -127,6 +127,7 @@ enum { HCI_SC_ENABLED, HCI_SC_ONLY, HCI_PRIVACY, + HCI_RPA_EXPIRED, HCI_RPA_RESOLVING, HCI_HS_ENABLED, HCI_LE_ENABLED, diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 68bbcabdd9fd..6415514e4f17 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -130,6 +130,9 @@ struct oob_data { #define HCI_MAX_SHORT_NAME_LENGTH 10 +/* Default LE RPA expiry time, 15 minutes */ +#define HCI_DEFAULT_RPA_TIMEOUT (15 * 60) + struct amp_assoc { __u16 len; __u16 offset; @@ -304,6 +307,8 @@ struct hci_dev { __u8 scan_rsp_data_len; __u8 irk[16]; + __u32 rpa_timeout; + struct delayed_work rpa_expired; int (*open)(struct hci_dev *hdev); int (*close)(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 964aa8deb009..92d35811b61e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2102,6 +2102,7 @@ static int hci_dev_do_open(struct hci_dev *hdev) if (!ret) { hci_dev_hold(hdev); + set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags); set_bit(HCI_UP, &hdev->flags); hci_notify(hdev, HCI_DEV_UP); if (!test_bit(HCI_SETUP, &hdev->dev_flags) && @@ -2199,6 +2200,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) cancel_delayed_work(&hdev->service_cache); cancel_delayed_work_sync(&hdev->le_scan_disable); + cancel_delayed_work_sync(&hdev->rpa_expired); hci_dev_lock(hdev); hci_inquiry_cache_flush(hdev); @@ -3300,6 +3302,8 @@ struct hci_dev *hci_alloc_dev(void) hdev->le_conn_min_interval = 0x0028; hdev->le_conn_max_interval = 0x0038; + hdev->rpa_timeout = HCI_DEFAULT_RPA_TIMEOUT; + mutex_init(&hdev->lock); mutex_init(&hdev->req_lock); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 301b18a1c6a0..4522da18d8e5 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -881,12 +881,39 @@ static void service_cache_off(struct work_struct *work) hci_req_run(&req, NULL); } +static void rpa_expired(struct work_struct *work) +{ + struct hci_dev *hdev = container_of(work, struct hci_dev, + rpa_expired.work); + struct hci_request req; + + BT_DBG(""); + + set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags); + + if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags) || + hci_conn_num(hdev, LE_LINK) > 0) + return; + + /* The generation of a new RPA and programming it into the + * controller happens in the enable_advertising() function. + */ + + hci_req_init(&req, hdev); + + disable_advertising(&req); + enable_advertising(&req); + + hci_req_run(&req, NULL); +} + static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev) { if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) return; INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off); + INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired); /* Non-mgmt controlled devices get this bit set * implicitly so that pairing works for them, however From ebd3a74765377b7528bb372aab2890638790301d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 23 Feb 2014 19:42:21 +0200 Subject: [PATCH 219/414] Bluetooth: Add hci_update_random_address() convenience function This patch adds a convenience function for updating the local random address which is needed before advertising, scanning and initiating LE connections. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_core.c | 55 ++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 6415514e4f17..2506963c7a06 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1257,6 +1257,8 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], __u8 ltk[16]); +int hci_update_random_address(struct hci_request *req, u8 *own_addr_type); + #define SCO_AIRMODE_MASK 0x0003 #define SCO_AIRMODE_CVSD 0x0000 #define SCO_AIRMODE_TRANSP 0x0003 diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 92d35811b61e..7bc67b4e47a7 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3276,6 +3276,61 @@ static void le_scan_disable_work(struct work_struct *work) BT_ERR("Disable LE scanning request failed: err %d", err); } +int hci_update_random_address(struct hci_request *req, u8 *own_addr_type) +{ + struct hci_dev *hdev = req->hdev; + int err; + + /* If privacy is enabled use a resolvable private address. If + * the current RPA has expired or there's something else than an + * RPA currently in use regenerate a new one. + */ + if (test_bit(HCI_PRIVACY, &hdev->dev_flags)) { + bdaddr_t rpa; + int to; + + *own_addr_type = ADDR_LE_DEV_RANDOM; + + if (!test_and_clear_bit(HCI_RPA_EXPIRED, &hdev->dev_flags) && + hci_bdaddr_is_rpa(&hdev->random_addr, ADDR_LE_DEV_RANDOM)) + return 0; + + err = smp_generate_rpa(hdev->tfm_aes, hdev->irk, &rpa); + if (err < 0) { + BT_ERR("%s failed to generate new RPA", hdev->name); + return err; + } + + hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, &rpa); + + to = msecs_to_jiffies(hdev->rpa_timeout * 1000); + queue_delayed_work(hdev->workqueue, &hdev->rpa_expired, to); + + return 0; + } + + /* If forcing static address is in use or there is no public + * address use the static address as random address (but skip + * the HCI command if the current random address is already the + * static one. + */ + if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags) || + !bacmp(&hdev->bdaddr, BDADDR_ANY)) { + *own_addr_type = ADDR_LE_DEV_RANDOM; + if (bacmp(&hdev->static_addr, &hdev->random_addr)) + hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, + &hdev->static_addr); + return 0; + } + + /* Neither privacy nor static address is being used so use a + * public address. + */ + *own_addr_type = ADDR_LE_DEV_PUBLIC; + + return 0; +} + /* Alloc HCI device */ struct hci_dev *hci_alloc_dev(void) { From 85030be4c5ce39e709b2cb5d4f8ee8779af8e50b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 23 Feb 2014 19:42:22 +0200 Subject: [PATCH 220/414] Bluetooth: Use hci_update_random_address() when connecting LE When we initiate LE connections we need to update the local random address if necessary. This patch updates the LE connection creation mechanism to use the new hci_update_random_address() function to set the own_address_type parameter and to update the local random address if necessary. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index bd66c52eff95..4cb337d6401f 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -556,16 +556,22 @@ static int hci_create_le_conn(struct hci_conn *conn) struct hci_dev *hdev = conn->hdev; struct hci_cp_le_create_conn cp; struct hci_request req; + u8 own_addr_type; int err; hci_req_init(&req, hdev); memset(&cp, 0, sizeof(cp)); + + err = hci_update_random_address(&req, &own_addr_type); + if (err < 0) + return err; + cp.scan_interval = cpu_to_le16(hdev->le_scan_interval); cp.scan_window = cpu_to_le16(hdev->le_scan_window); bacpy(&cp.peer_addr, &conn->dst); cp.peer_addr_type = conn->dst_type; - cp.own_address_type = conn->src_type; + cp.own_address_type = own_addr_type; cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval); cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval); cp.supervision_timeout = __constant_cpu_to_le16(0x002a); From 8f2a0601a5d68d0dbd2221613dda7fb6fee32a6b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 23 Feb 2014 19:42:23 +0200 Subject: [PATCH 221/414] Bluetooth: Use hci_update_random_address() for enabling advertising When we enable advertising we need to update the local random address if necessary. This patch takes advantage of the hci_update_random_address() function to set the own_address_type variable and to update the local random address if necessary. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4522da18d8e5..8df287ba9ba3 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -839,13 +839,17 @@ static void enable_advertising(struct hci_request *req) { struct hci_dev *hdev = req->hdev; struct hci_cp_le_set_adv_param cp; - u8 enable = 0x01; + u8 own_addr_type, enable = 0x01; memset(&cp, 0, sizeof(cp)); + + if (hci_update_random_address(req, &own_addr_type) < 0) + return; + cp.min_interval = __constant_cpu_to_le16(0x0800); cp.max_interval = __constant_cpu_to_le16(0x0800); cp.type = get_adv_type(hdev); - cp.own_address_type = hdev->own_addr_type; + cp.own_address_type = own_addr_type; cp.channel_map = hdev->le_adv_channel_map; hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp); From d9483943601ba7095af42a159faacf7746a74bc9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 23 Feb 2014 19:42:24 +0200 Subject: [PATCH 222/414] Bluetooth: Use hci_update_random_address() for initiating LE scan When we start LE scanning we need to update the local random address if necessary. This patch updates the code to use hci_update_random_address() for setting the own_address_type scan parameter and updating the local random address if necessary. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 8df287ba9ba3..e369c871c702 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3294,7 +3294,7 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, struct hci_request req; /* General inquiry access code (GIAC) */ u8 lap[3] = { 0x33, 0x8b, 0x9e }; - u8 status; + u8 status, own_addr_type; int err; BT_DBG("%s", hdev->name); @@ -3387,10 +3387,19 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, } memset(¶m_cp, 0, sizeof(param_cp)); + + err = hci_update_random_address(&req, &own_addr_type); + if (err < 0) { + err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, + MGMT_STATUS_FAILED); + mgmt_pending_remove(cmd); + goto failed; + } + param_cp.type = LE_SCAN_ACTIVE; param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT); param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN); - param_cp.own_address_type = hdev->own_addr_type; + param_cp.own_address_type = own_addr_type; hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp), ¶m_cp); From 8f71c6c3157d12c90d3cf920dd5e94045679fdce Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 23 Feb 2014 19:42:25 +0200 Subject: [PATCH 223/414] Bluetooth: Don't write static address during power on Since we always update the random address before enabling advertising, scanning and initiating LE connections there is no need to write the random address add power on. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e369c871c702..49d52a37bdac 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4608,11 +4608,6 @@ static int powered_update_hci(struct hci_dev *hdev) } if (lmp_le_capable(hdev)) { - /* Set random address to static address if configured */ - if (bacmp(&hdev->static_addr, BDADDR_ANY)) - hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6, - &hdev->static_addr); - /* Make sure the controller has a good default for * advertising data. This also applies to the case * where BR/EDR was toggled during the AUTO_OFF phase. From c982b2ea29af7a78685b9e32ea028917a07b783e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 23 Feb 2014 19:42:26 +0200 Subject: [PATCH 224/414] Bluetooth: Add debugfs entry for RPA regeneration timeout This patch adds a rpa_timeout debugfs entry which can be used to set the RPA regeneration timeout to something else than the default 15 minutes. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 7bc67b4e47a7..629919be071c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -492,6 +492,37 @@ static int idle_timeout_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(idle_timeout_fops, idle_timeout_get, idle_timeout_set, "%llu\n"); +static int rpa_timeout_set(void *data, u64 val) +{ + struct hci_dev *hdev = data; + + /* Require the RPA timeout to be at least 30 seconds and at most + * 24 hours. + */ + if (val < 30 || val > (60 * 60 * 24)) + return -EINVAL; + + hci_dev_lock(hdev); + hdev->rpa_timeout = val; + hci_dev_unlock(hdev); + + return 0; +} + +static int rpa_timeout_get(void *data, u64 *val) +{ + struct hci_dev *hdev = data; + + hci_dev_lock(hdev); + *val = hdev->rpa_timeout; + hci_dev_unlock(hdev); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(rpa_timeout_fops, rpa_timeout_get, + rpa_timeout_set, "%llu\n"); + static int sniff_min_interval_set(void *data, u64 val) { struct hci_dev *hdev = data; @@ -1612,6 +1643,8 @@ static int __hci_init(struct hci_dev *hdev) hdev, &random_address_fops); debugfs_create_file("static_address", 0444, hdev->debugfs, hdev, &static_address_fops); + debugfs_create_file("rpa_timeout", 0644, hdev->debugfs, + hdev, &rpa_timeout_fops); /* For controllers with a public address, provide a debug * option to force the usage of the configured static From 62b04cd124cb76ce0b9a6391c6c046c08c1ac8b7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 23 Feb 2014 19:42:27 +0200 Subject: [PATCH 225/414] Bluetooth: Add support for Set Privacy command This patch adds support for handling the Set Privacy mgmt command, including copying the value to hdev->irk and toggling the HCI_PRIVACY flag. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 48 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 49d52a37bdac..37305facf4d6 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -81,6 +81,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_SET_SCAN_PARAMS, MGMT_OP_SET_SECURE_CONN, MGMT_OP_SET_DEBUG_KEYS, + MGMT_OP_SET_PRIVACY, MGMT_OP_LOAD_IRKS, }; @@ -4227,6 +4228,51 @@ unlock: return err; } +static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data, + u16 len) +{ + struct mgmt_cp_set_privacy *cp = cp_data; + bool changed; + int err; + + BT_DBG("request for %s", hdev->name); + + if (!lmp_le_capable(hdev)) + return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY, + MGMT_STATUS_NOT_SUPPORTED); + + if (cp->privacy != 0x00 && cp->privacy != 0x01) + return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY, + MGMT_STATUS_INVALID_PARAMS); + + if (hdev_is_powered(hdev)) + return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY, + MGMT_STATUS_REJECTED); + + hci_dev_lock(hdev); + + if (cp->privacy) { + changed = !test_and_set_bit(HCI_PRIVACY, &hdev->dev_flags); + memcpy(hdev->irk, cp->irk, sizeof(hdev->irk)); + set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags); + } else { + changed = test_and_clear_bit(HCI_PRIVACY, &hdev->dev_flags); + memset(hdev->irk, 0, sizeof(hdev->irk)); + clear_bit(HCI_RPA_EXPIRED, &hdev->dev_flags); + } + + err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev); + if (err < 0) + goto unlock; + + if (changed) + err = new_settings(hdev, sk); + +unlock: + hci_dev_unlock(hdev); + return err; +} + static bool irk_is_valid(struct mgmt_irk_info *irk) { switch (irk->addr.type) { @@ -4441,7 +4487,7 @@ static const struct mgmt_handler { { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE }, { set_secure_conn, false, MGMT_SETTING_SIZE }, { set_debug_keys, false, MGMT_SETTING_SIZE }, - { }, + { set_privacy, false, MGMT_SET_PRIVACY_SIZE }, { load_irks, true, MGMT_LOAD_IRKS_SIZE }, }; From e26b1ffa11bb1e0afa194823623ee64b7e143993 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 23 Feb 2014 19:42:28 +0200 Subject: [PATCH 226/414] Bluetooth: Fix setting correct src_type when connecting LE This patch ensures that conn->src_type contains the same address type as is used for initiating the connection while the connection attempt is in progress. Once connected this value will be overwritten with the identity address type. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 4cb337d6401f..a1efa1c62de8 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -567,6 +567,8 @@ static int hci_create_le_conn(struct hci_conn *conn) if (err < 0) return err; + conn->src_type = own_addr_type; + cp.scan_interval = cpu_to_le16(hdev->le_scan_interval); cp.scan_window = cpu_to_le16(hdev->le_scan_window); bacpy(&cp.peer_addr, &conn->dst); @@ -653,7 +655,6 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, return ERR_PTR(-ENOMEM); conn->dst_type = dst_type; - conn->src_type = hdev->own_addr_type; conn->state = BT_CONNECT; conn->out = true; From 7bf32048b1af87942d311ef1620995ffc89c07d8 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 23 Feb 2014 19:42:29 +0200 Subject: [PATCH 227/414] Bluetooth: Remove unneeded hdev->own_addr_type Now that the identity address type is always looked up for all successful connections, the hdev->own_addr_type variable has become completely unnecessary. Simply remove it. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_core.c | 17 +---------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2506963c7a06..43b6d1131c4d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -156,7 +156,6 @@ struct hci_dev { bdaddr_t bdaddr; bdaddr_t random_addr; bdaddr_t static_addr; - __u8 own_addr_type; __u8 dev_name[HCI_MAX_NAME_LENGTH]; __u8 short_name[HCI_MAX_SHORT_NAME_LENGTH]; __u8 eir[HCI_MAX_EIR_LENGTH]; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 629919be071c..1651de959d9c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1506,23 +1506,8 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) if (hdev->commands[5] & 0x10) hci_setup_link_policy(req); - if (lmp_le_capable(hdev)) { - /* If the controller has a public BD_ADDR, then by default - * use that one. If this is a LE only controller without - * a public address, default to the random address. - * - * For debugging purposes it is possible to force - * controllers with a public address to use the - * random address instead. - */ - if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags) || - !bacmp(&hdev->bdaddr, BDADDR_ANY)) - hdev->own_addr_type = ADDR_LE_DEV_RANDOM; - else - hdev->own_addr_type = ADDR_LE_DEV_PUBLIC; - + if (lmp_le_capable(hdev)) hci_set_le_support(req); - } /* Read features beyond page 1 if available */ for (p = 2; p < HCI_MAX_PAGES && p <= hdev->max_page; p++) { From ac345813c4ac5a0e66261e9812f0fe94729c0eb2 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 23 Feb 2014 12:44:25 -0800 Subject: [PATCH 228/414] Bluetooth: Expose current identity information in debugfs When using LE Privacy it is useful to know the local identity address, identity address type and identity resolving key. For debugging purposes add these information to debugfs. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 42 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 1651de959d9c..80462a126ebd 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -579,6 +579,42 @@ static int sniff_max_interval_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(sniff_max_interval_fops, sniff_max_interval_get, sniff_max_interval_set, "%llu\n"); +static int identity_show(struct seq_file *f, void *p) +{ + struct hci_dev *hdev = f->private; + bdaddr_t *addr; + u8 addr_type; + + hci_dev_lock(hdev); + + if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags) || + !bacmp(&hdev->bdaddr, BDADDR_ANY)) { + addr = &hdev->static_addr; + addr_type = ADDR_LE_DEV_RANDOM; + } else { + addr = &hdev->bdaddr; + addr_type = ADDR_LE_DEV_PUBLIC; + } + + seq_printf(f, "%pMR (type %u) %*phN\n", addr, addr_type, 16, hdev->irk); + + hci_dev_unlock(hdev); + + return 0; +} + +static int identity_open(struct inode *inode, struct file *file) +{ + return single_open(file, identity_show, inode->i_private); +} + +static const struct file_operations identity_fops = { + .open = identity_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int random_address_show(struct seq_file *f, void *p) { struct hci_dev *hdev = f->private; @@ -1624,12 +1660,14 @@ static int __hci_init(struct hci_dev *hdev) } if (lmp_le_capable(hdev)) { + debugfs_create_file("identity", 0400, hdev->debugfs, + hdev, &identity_fops); + debugfs_create_file("rpa_timeout", 0644, hdev->debugfs, + hdev, &rpa_timeout_fops); debugfs_create_file("random_address", 0444, hdev->debugfs, hdev, &random_address_fops); debugfs_create_file("static_address", 0444, hdev->debugfs, hdev, &static_address_fops); - debugfs_create_file("rpa_timeout", 0644, hdev->debugfs, - hdev, &rpa_timeout_fops); /* For controllers with a public address, provide a debug * option to force the usage of the configured static From 94b1fc92cd7cf550460ffd4bcc08c2707564aa49 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 23 Feb 2014 20:25:54 -0800 Subject: [PATCH 229/414] Bluetooth: Use unresolvable private address for active scanning When running active scanning during LE discovery, do not reveal the own identity to the peer devices. In case LE privacy has been enabled, then a resolvable private address is used. If the LE privacy option is off, then use an unresolvable private address. The public address or static random address is never used in active scanning anymore. This ensures that scan request are send using a random address. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 3 ++- net/bluetooth/hci_conn.c | 5 ++++- net/bluetooth/hci_core.c | 18 +++++++++++++++++- net/bluetooth/mgmt.c | 8 ++++++-- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 43b6d1131c4d..0ee9cd11b3ef 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1256,7 +1256,8 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], __u8 ltk[16]); -int hci_update_random_address(struct hci_request *req, u8 *own_addr_type); +int hci_update_random_address(struct hci_request *req, bool require_privacy, + u8 *own_addr_type); #define SCO_AIRMODE_MASK 0x0003 #define SCO_AIRMODE_CVSD 0x0000 diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index a1efa1c62de8..3d6b1cf07d23 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -563,7 +563,10 @@ static int hci_create_le_conn(struct hci_conn *conn) memset(&cp, 0, sizeof(cp)); - err = hci_update_random_address(&req, &own_addr_type); + /* Update random address, but set require_privacy to false so + * that we never connect with an unresolvable address. + */ + err = hci_update_random_address(&req, false, &own_addr_type); if (err < 0) return err; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 80462a126ebd..31e68ade309d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3332,7 +3332,8 @@ static void le_scan_disable_work(struct work_struct *work) BT_ERR("Disable LE scanning request failed: err %d", err); } -int hci_update_random_address(struct hci_request *req, u8 *own_addr_type) +int hci_update_random_address(struct hci_request *req, bool require_privacy, + u8 *own_addr_type) { struct hci_dev *hdev = req->hdev; int err; @@ -3365,6 +3366,21 @@ int hci_update_random_address(struct hci_request *req, u8 *own_addr_type) return 0; } + /* In case of required privacy without resolvable private address, + * use an unresolvable private address. This is useful for active + * scanning and non-connectable advertising. + */ + if (require_privacy) { + bdaddr_t urpa; + + get_random_bytes(&urpa, 6); + urpa.b[5] &= 0x3f; /* Clear two most significant bits */ + + *own_addr_type = ADDR_LE_DEV_RANDOM; + hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, &urpa); + return 0; + } + /* If forcing static address is in use or there is no public * address use the static address as random address (but skip * the HCI command if the current random address is already the diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 37305facf4d6..5d309d4ab527 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -844,7 +844,7 @@ static void enable_advertising(struct hci_request *req) memset(&cp, 0, sizeof(cp)); - if (hci_update_random_address(req, &own_addr_type) < 0) + if (hci_update_random_address(req, false, &own_addr_type) < 0) return; cp.min_interval = __constant_cpu_to_le16(0x0800); @@ -3389,7 +3389,11 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, memset(¶m_cp, 0, sizeof(param_cp)); - err = hci_update_random_address(&req, &own_addr_type); + /* All active scans will be done with either a resolvable + * private address (when privacy feature has been enabled) + * or unresolvable private address. + */ + err = hci_update_random_address(&req, true, &own_addr_type); if (err < 0) { err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, MGMT_STATUS_FAILED); From 41c90c186a3b51207cb1f2583fbadec3c76e4730 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 23 Feb 2014 20:25:55 -0800 Subject: [PATCH 230/414] Bluetooth: Use privacy mode for non-connectable advertising When enabling non-connectable advertising, there is no need to advertise with a public address or static address. In case LE privacy has not been enabled a unresolvable private address will be used. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 5d309d4ab527..53b9408af16b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -841,12 +841,14 @@ static void enable_advertising(struct hci_request *req) struct hci_dev *hdev = req->hdev; struct hci_cp_le_set_adv_param cp; u8 own_addr_type, enable = 0x01; + bool require_privacy; - memset(&cp, 0, sizeof(cp)); + require_privacy = !test_bit(HCI_CONNECTABLE, &hdev->dev_flags); - if (hci_update_random_address(req, false, &own_addr_type) < 0) + if (hci_update_random_address(req, require_privacy, &own_addr_type) < 0) return; + memset(&cp, 0, sizeof(cp)); cp.min_interval = __constant_cpu_to_le16(0x0800); cp.max_interval = __constant_cpu_to_le16(0x0800); cp.type = get_adv_type(hdev); From 2b5224dca5a9257a3df8cc9f93978ecb3757b9c2 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 23 Feb 2014 20:39:22 -0800 Subject: [PATCH 231/414] Bluetooth: Store current RPA and update it if needed The RPA needs to be stored to know which is the current one. Otherwise it is impossible to ensure that always the correct RPA can be programmed into the controller when it is needed. Current code checks if the address in the controller is a RPA, but that can potentially lead to using a RPA that can not be resolved with the IRK that has been distributed. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 11 +++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 0ee9cd11b3ef..fb3b677ff8a6 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -308,6 +308,7 @@ struct hci_dev { __u8 irk[16]; __u32 rpa_timeout; struct delayed_work rpa_expired; + bdaddr_t rpa; int (*open)(struct hci_dev *hdev); int (*close)(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 31e68ade309d..9f1c3d7d1d74 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3339,26 +3339,25 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy, int err; /* If privacy is enabled use a resolvable private address. If - * the current RPA has expired or there's something else than an - * RPA currently in use regenerate a new one. + * current RPA has expired or there is something else than + * the current RPA in use, then generate a new one. */ if (test_bit(HCI_PRIVACY, &hdev->dev_flags)) { - bdaddr_t rpa; int to; *own_addr_type = ADDR_LE_DEV_RANDOM; if (!test_and_clear_bit(HCI_RPA_EXPIRED, &hdev->dev_flags) && - hci_bdaddr_is_rpa(&hdev->random_addr, ADDR_LE_DEV_RANDOM)) + !bacmp(&hdev->random_addr, &hdev->rpa)) return 0; - err = smp_generate_rpa(hdev->tfm_aes, hdev->irk, &rpa); + err = smp_generate_rpa(hdev->tfm_aes, hdev->irk, &hdev->rpa); if (err < 0) { BT_ERR("%s failed to generate new RPA", hdev->name); return err; } - hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, &rpa); + hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, &hdev->rpa); to = msecs_to_jiffies(hdev->rpa_timeout * 1000); queue_delayed_work(hdev->workqueue, &hdev->rpa_expired, to); From 473deef2c9e99c548c04c58856bdf1e271806079 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 23 Feb 2014 20:39:23 -0800 Subject: [PATCH 232/414] Bluetooth: Export current local RPA with identity information The identity information in debugfs currently do not include the current in use local RPA. Since the RPA is now stored in the controller information, include it in the debugfs as well. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9f1c3d7d1d74..4bb4f4e7bbbe 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -596,7 +596,8 @@ static int identity_show(struct seq_file *f, void *p) addr_type = ADDR_LE_DEV_PUBLIC; } - seq_printf(f, "%pMR (type %u) %*phN\n", addr, addr_type, 16, hdev->irk); + seq_printf(f, "%pMR (type %u) %*phN %pMR\n", addr, addr_type, + 16, hdev->irk, &hdev->rpa); hci_dev_unlock(hdev); From c21c0ea07b30eb670be96e67199d1f984512ef96 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 24 Feb 2014 11:10:30 +0200 Subject: [PATCH 233/414] Bluetooth: Enable RPA resolving if mgmt_set_privacy is called A user space that supports the Set Privacy command is also expected to be able to handle New IRK events. Therefore, set the HCI_RPA_RESOLVING flag whenever the Set Privacy command is received. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 53b9408af16b..9865e523df20 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4257,6 +4257,11 @@ static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data, hci_dev_lock(hdev); + /* If user space supports this command it is also expected to + * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag. + */ + set_bit(HCI_RPA_RESOLVING, &hdev->dev_flags); + if (cp->privacy) { changed = !test_and_set_bit(HCI_PRIVACY, &hdev->dev_flags); memcpy(hdev->irk, cp->irk, sizeof(hdev->irk)); From 4518bb0fb5eda46a9b118a6fbd9661e62a34a5b6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 24 Feb 2014 20:35:07 +0200 Subject: [PATCH 234/414] Bluetooth: Fix canceling RPA expiry timer The RPA expiry timer is only initialized inside mgmt.c when we receive the first command from user space. This action also involves setting the HCI_MGMT flag for the first time so that flag acts as a good indicator of whether the delayed work variable can be touched or not. This patch fixes hci_dev_do_close to first check the flag. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 4bb4f4e7bbbe..669c76ec659a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2257,7 +2257,9 @@ static int hci_dev_do_close(struct hci_dev *hdev) cancel_delayed_work(&hdev->service_cache); cancel_delayed_work_sync(&hdev->le_scan_disable); - cancel_delayed_work_sync(&hdev->rpa_expired); + + if (test_bit(HCI_MGMT, &hdev->dev_flags)) + cancel_delayed_work_sync(&hdev->rpa_expired); hci_dev_lock(hdev); hci_inquiry_cache_flush(hdev); From f4f07505005932ca5f6c8003323bd38dbd0c769c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 24 Feb 2014 14:52:16 +0200 Subject: [PATCH 235/414] Bluetooth: Add convenience function for getting total connection count This patch adds a convenience function to return the number of connections in the conn_hash list. This will be useful once we update the power off procedure to disconnect any open connections. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index fb3b677ff8a6..d2d756753714 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -561,6 +561,13 @@ static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type) } } +static inline unsigned int hci_conn_count(struct hci_dev *hdev) +{ + struct hci_conn_hash *c = &hdev->conn_hash; + + return c->acl_num + c->amp_num + c->sco_num + c->le_num; +} + static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev, __u16 handle) { From 778b235a3be0588da1909f7ef75b4bc3dbc09dfc Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 24 Feb 2014 14:52:17 +0200 Subject: [PATCH 236/414] Bluetooth: Move HCI_ADVERTISING handling into mgmt.c We'll soon need to make decisions on toggling the HCI_ADVERTISING flag based on pending mgmt_set_powered commands. Therefore, move the handling from hci_event.c into mgmt.c. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_event.c | 8 ++------ net/bluetooth/mgmt.c | 8 ++++++++ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index d2d756753714..6ff882e727d4 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1174,6 +1174,7 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered); void mgmt_discoverable_timeout(struct hci_dev *hdev); void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable); void mgmt_connectable(struct hci_dev *hdev, u8 connectable); +void mgmt_advertising(struct hci_dev *hdev, u8 advertising); void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 064d619344b3..dea465ba276b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -991,12 +991,8 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); - if (!status) { - if (*sent) - set_bit(HCI_ADVERTISING, &hdev->dev_flags); - else - clear_bit(HCI_ADVERTISING, &hdev->dev_flags); - } + if (!status) + mgmt_advertising(hdev, *sent); hci_dev_unlock(hdev); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9865e523df20..d39e57e9fed6 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4832,6 +4832,14 @@ void mgmt_connectable(struct hci_dev *hdev, u8 connectable) new_settings(hdev, NULL); } +void mgmt_advertising(struct hci_dev *hdev, u8 advertising) +{ + if (advertising) + set_bit(HCI_ADVERTISING, &hdev->dev_flags); + else + clear_bit(HCI_ADVERTISING, &hdev->dev_flags); +} + void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) { u8 mgmt_err = mgmt_status(status); From 12d4a3b2ccb3ac2bd56e7c216d6e7f44730006f3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 24 Feb 2014 14:52:18 +0200 Subject: [PATCH 237/414] Bluetooth: Move check for MGMT_CONNECTED flag into mgmt.c Once mgmt_set_powered(off) starts doing disconnections we'll need to care about any disconnections in mgmt.c and not just those with the MGMT_CONNECTED flag set. Therefore, move the check into mgmt.c from hci_event.c. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 3 ++- net/bluetooth/hci_event.c | 7 ++++--- net/bluetooth/mgmt.c | 6 +++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 6ff882e727d4..269c8201a362 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1182,7 +1182,8 @@ void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u32 flags, u8 *name, u8 name_len, u8 *dev_class); void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 reason); + u8 link_type, u8 addr_type, u8 reason, + bool mgmt_connected); void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index dea465ba276b..877cee844b9e 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1842,6 +1842,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) struct hci_ev_disconn_complete *ev = (void *) skb->data; u8 reason = hci_to_mgmt_reason(ev->reason); struct hci_conn *conn; + bool mgmt_connected; u8 type; BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); @@ -1860,9 +1861,9 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->state = BT_CLOSED; - if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) - mgmt_device_disconnected(hdev, &conn->dst, conn->type, - conn->dst_type, reason); + mgmt_connected = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags); + mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type, + reason, mgmt_connected); if (conn->type == ACL_LINK && conn->flush_key) hci_remove_link_key(hdev, &conn->dst); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d39e57e9fed6..bdc831b3bb97 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5012,11 +5012,15 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data) } void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 reason) + u8 link_type, u8 addr_type, u8 reason, + bool mgmt_connected) { struct mgmt_ev_device_disconnected ev; struct sock *sk = NULL; + if (!mgmt_connected) + return; + if (link_type != ACL_LINK && link_type != LE_LINK) return; From bd107999338fbb2e084acebc635333a5cd156b09 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 24 Feb 2014 14:52:19 +0200 Subject: [PATCH 238/414] Bluetooth: Don't clear HCI_DISCOVERABLE when powering off Once mgmt_set_powered(off) is updated to clear the scan mode we should not just blindly clear the HCI_DISCOVERABLE flag in mgmt_discoverable() but first check if there is a pending set_powered operation. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bdc831b3bb97..769b5dc0270d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4790,6 +4790,10 @@ void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev)) return; + /* Powering off may clear the scan mode - don't let that interfere */ + if (!discoverable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) + return; + if (discoverable) { changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags); } else { From ce3f24cfb2a2287409acad3dd990570fe62d0af4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 24 Feb 2014 14:52:20 +0200 Subject: [PATCH 239/414] Bluetooth: Don't clear HCI_CONNECTABLE when powering off Once mgmt_set_powered(off) is updated to clear the scan mode we should not just blindly clear the HCI_CONNECTABLE flag in mgmt_connectable() but first check if there is a pending set_powered operation. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 769b5dc0270d..5899ac7264ff 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4827,6 +4827,10 @@ void mgmt_connectable(struct hci_dev *hdev, u8 connectable) if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) return; + /* Powering off may clear the scan mode - don't let that interfere */ + if (!connectable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) + return; + if (connectable) changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags); else From 7c4cfab8082f1398dc7bc091166dd302a44b015b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 24 Feb 2014 14:52:21 +0200 Subject: [PATCH 240/414] Bluetooth: Don't clear HCI_ADVERTISING when powering off Once mgmt_set_powered(off) is updated to clear the scan mode we should not just blindly clear the HCI_ADVERTISING flag in mgmt_advertising() but first check if there is a pending set_powered operation. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 5899ac7264ff..610ac32e797b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4842,6 +4842,10 @@ void mgmt_connectable(struct hci_dev *hdev, u8 connectable) void mgmt_advertising(struct hci_dev *hdev, u8 advertising) { + /* Powering off may stop advertising - don't let that interfere */ + if (!advertising && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) + return; + if (advertising) set_bit(HCI_ADVERTISING, &hdev->dev_flags); else From 8b064a3ad377c016a17e74f676e7a204c2b8c9f2 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 24 Feb 2014 14:52:22 +0200 Subject: [PATCH 241/414] Bluetooth: Clean up HCI state when doing power off To be friendly to user space and to behave well with controllers that lack a proper internal power off procedure we should try to clean up as much state as possible before requesting the HCI driver to power off. This patch updates the power off procedure that's triggered by mgmt_set_powered to clean any scan modes, stop LE scanning and advertising and to disconnect any open connections. The asynchronous cleanup procedure uses the HCI request framework, however since HCI_Disconnect is only covered until its Command Status event we need some extra tracking/waiting of disconnections. This is done by monitoring when hci_conn_count() indicates that there are no more connections. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 70 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 610ac32e797b..25b8b278debd 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1026,6 +1026,49 @@ static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev) sizeof(settings)); } +static void clean_up_hci_complete(struct hci_dev *hdev, u8 status) +{ + BT_DBG("%s status 0x%02x", hdev->name, status); + + if (hci_conn_count(hdev) == 0) + queue_work(hdev->req_workqueue, &hdev->power_off.work); +} + +static int clean_up_hci_state(struct hci_dev *hdev) +{ + struct hci_request req; + struct hci_conn *conn; + + hci_req_init(&req, hdev); + + if (test_bit(HCI_ISCAN, &hdev->flags) || + test_bit(HCI_PSCAN, &hdev->flags)) { + u8 scan = 0x00; + hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); + } + + if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) + disable_advertising(&req); + + if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) { + struct hci_cp_le_set_scan_enable cp; + + memset(&cp, 0, sizeof(cp)); + cp.enable = LE_SCAN_DISABLE; + hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); + } + + list_for_each_entry(conn, &hdev->conn_hash.list, list) { + struct hci_cp_disconnect dc; + + dc.handle = cpu_to_le16(conn->handle); + dc.reason = 0x15; /* Terminated due to Power Off */ + hci_req_add(&req, HCI_OP_DISCONNECT, sizeof(dc), &dc); + } + + return hci_req_run(&req, clean_up_hci_complete); +} + static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { @@ -1069,12 +1112,19 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, goto failed; } - if (cp->val) + if (cp->val) { queue_work(hdev->req_workqueue, &hdev->power_on); - else - queue_work(hdev->req_workqueue, &hdev->power_off.work); + err = 0; + } else { + /* Disconnect connections, stop scans, etc */ + err = clean_up_hci_state(hdev); - err = 0; + /* ENODATA means there were no HCI commands queued */ + if (err == -ENODATA) { + queue_work(hdev->req_workqueue, &hdev->power_off.work); + err = 0; + } + } failed: hci_dev_unlock(hdev); @@ -5028,8 +5078,20 @@ void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, bool mgmt_connected) { struct mgmt_ev_device_disconnected ev; + struct pending_cmd *power_off; struct sock *sk = NULL; + power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev); + if (power_off) { + struct mgmt_mode *cp = power_off->param; + + /* The connection is still in hci_conn_hash so test for 1 + * instead of 0 to know if this is the last one. + */ + if (!cp->val && hci_conn_count(hdev) == 1) + queue_work(hdev->req_workqueue, &hdev->power_off.work); + } + if (!mgmt_connected) return; From 161d7855543520cde5f49df788b0ea0553a9f83a Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 24 Feb 2014 14:35:46 -0500 Subject: [PATCH 242/414] Revert "Staging: rtl8812ae: remove modules field of rate_control_ops" This reverts commit 35582ad9d342025653aaf28ed321bf5352488d7f. This should not have been merged through this tree... Signed-off-by: John W. Linville --- drivers/staging/rtl8821ae/rc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/rtl8821ae/rc.c b/drivers/staging/rtl8821ae/rc.c index 0cc32c60ddee..d387f13ea7dc 100644 --- a/drivers/staging/rtl8821ae/rc.c +++ b/drivers/staging/rtl8821ae/rc.c @@ -286,6 +286,7 @@ static void rtl_rate_free_sta(void *rtlpriv, } static struct rate_control_ops rtl_rate_ops = { + .module = NULL, .name = "rtl_rc", .alloc = rtl_rate_alloc, .free = rtl_rate_free, From c42c65c1d5863bca54e45ea25ecb24a3def29f59 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 14 Feb 2014 12:03:13 +0300 Subject: [PATCH 243/414] mwifiex: memory corruption in mwifiex_tdls_add_vht_capab() There is a typo here because the names are confusingly similar. The intent was sizeof(struct ieee80211_vht_cap) (size 12) but sizeof(struct ieee80211_ht_cap) (size 32) was used. Anway, it's cleaner to just specify the variable instead of the type. Fixes: 5f6d5983394f ('mwifiex: add VHT support for TDLS') Signed-off-by: Dan Carpenter Acked-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/tdls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index 5efd456af571..1ba2a16ee471 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -180,7 +180,7 @@ static int mwifiex_tdls_add_vht_capab(struct mwifiex_private *priv, memset(&vht_cap, 0, sizeof(struct ieee80211_vht_cap)); mwifiex_fill_vht_cap_tlv(priv, &vht_cap, priv->curr_bss_params.band); - memcpy(pos, &vht_cap, sizeof(struct ieee80211_ht_cap)); + memcpy(pos, &vht_cap, sizeof(vht_cap)); return 0; } From e51048cdf0bdf1358c39839eabb22a06674af9ed Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Fri, 14 Feb 2014 19:03:44 +0100 Subject: [PATCH 244/414] rtlwifi: avoid accessing RCR directly The rtl*_set_check_bssid functions are mostly the same, but access the RCR register in different ways. Use the get_hw_reg abstraction layer (which reads rtlpci->receive_config for PCI devices and mac->rx_conf for USB). There is no functional change for cases where receive_config was accessed directly. For rtl8192ce, there is still no change because nothing modifies REG_RCR or receive_config. For rtl8192cu, it now also applies changes to rx_conf from configure_filter, but that can be considered a bug which is fixed later. Signed-off-by: Peter Wu Acked-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8188ee/hw.c | 5 +++-- drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | 4 +++- drivers/net/wireless/rtlwifi/rtl8192cu/hw.c | 4 +++- drivers/net/wireless/rtlwifi/rtl8192de/hw.c | 6 ++++-- drivers/net/wireless/rtlwifi/rtl8192se/hw.c | 5 +++-- drivers/net/wireless/rtlwifi/rtl8723ae/hw.c | 5 +++-- 6 files changed, 19 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c index e06971be7df7..ce2226cd2e4f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c @@ -1235,12 +1235,13 @@ static int _rtl88ee_set_media_status(struct ieee80211_hw *hw, void rtl88ee_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - u32 reg_rcr = rtlpci->receive_config; + u32 reg_rcr; if (rtlpriv->psc.rfpwr_state != ERFON) return; + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); + if (check_bssid == true) { reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index a82b30a1996c..25e178c80d70 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -1200,11 +1200,13 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw, void rtl92ce_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) { struct rtl_priv *rtlpriv = rtl_priv(hw); - u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR); + u32 reg_rcr; if (rtlpriv->psc.rfpwr_state != ERFON) return; + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); + if (check_bssid) { reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 468bf73cc883..49ad10668078 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -1379,11 +1379,13 @@ void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtlpriv); - u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR); + u32 reg_rcr; if (rtlpriv->psc.rfpwr_state != ERFON) return; + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); + if (check_bssid) { u8 tmp; if (IS_NORMAL_CHIP(rtlhal->version)) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c index c4a7db9135d6..c16aa6b59527 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c @@ -1138,11 +1138,13 @@ static int _rtl92de_set_media_status(struct ieee80211_hw *hw, void rtl92de_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - u32 reg_rcr = rtlpci->receive_config; + u32 reg_rcr; if (rtlpriv->psc.rfpwr_state != ERFON) return; + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); + if (check_bssid) { reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c index 4f461786a7eb..5aa39ef42eba 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c @@ -1135,12 +1135,13 @@ void rtl92se_set_mac_addr(struct rtl_io *io, const u8 *addr) void rtl92se_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - u32 reg_rcr = rtlpci->receive_config; + u32 reg_rcr; if (rtlpriv->psc.rfpwr_state != ERFON) return; + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); + if (check_bssid) { reg_rcr |= (RCR_CBSSID); rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c index c333dfd116b8..4680816f9597 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c @@ -1112,12 +1112,13 @@ static int _rtl8723ae_set_media_status(struct ieee80211_hw *hw, void rtl8723ae_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - u32 reg_rcr = rtlpci->receive_config; + u32 reg_rcr; if (rtlpriv->psc.rfpwr_state != ERFON) return; + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); + if (check_bssid == true) { reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, From 711f145ad0e93a914644d3e7998c28267bd3c136 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Fri, 14 Feb 2014 19:03:45 +0100 Subject: [PATCH 245/414] rtlwifi: properly apply filter flags commit 0baa0fd76f3f5a134461d6cf30294f6bb1bb824c ("rtlwifi: Convert core routines for addition of rtl8192se and rtl8192de") removed setting HW_VAR_RCR, HW_VAR_MGT_FILTER and HW_VAR_CTRL_FILTER. The last two are probably done because some hardware does not support them. The first is probably a mistake. This patch adds the missing set_hw_reg call. For PCI support, rx_conf is not touched directly. Instead, get_hw_reg is used to abstract between receive_config (for PCI) and rx_conf (for USB). This was tested on a 10ec:8176 Realtek RTL8188CE (according to the label on the mini-PCIe card). Before this patch, `iw wlan0 set monitor otherbss` did not capture frames from other BSS's. After this patch, it does print packets. Tested-by: Peter Wu Signed-off-by: Peter Wu Acked-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/core.c | 70 ++++++++++++++++------------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 2d337a0c3df0..6df4df090b73 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -475,38 +475,12 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u32 rx_conf; *new_flags &= RTL_SUPPORTED_FILTERS; if (!changed_flags) return; - /*TODO: we disable broadcase now, so enable here */ - if (changed_flags & FIF_ALLMULTI) { - if (*new_flags & FIF_ALLMULTI) { - mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AM] | - rtlpriv->cfg->maps[MAC_RCR_AB]; - RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, - "Enable receive multicast frame\n"); - } else { - mac->rx_conf &= ~(rtlpriv->cfg->maps[MAC_RCR_AM] | - rtlpriv->cfg->maps[MAC_RCR_AB]); - RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, - "Disable receive multicast frame\n"); - } - } - - if (changed_flags & FIF_FCSFAIL) { - if (*new_flags & FIF_FCSFAIL) { - mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACRC32]; - RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, - "Enable receive FCS error frame\n"); - } else { - mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACRC32]; - RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, - "Disable receive FCS error frame\n"); - } - } - /* if ssid not set to hw don't check bssid * here just used for linked scanning, & linked * and nolink check bssid is set in set network_type */ @@ -522,14 +496,46 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw, } } + /* must be called after set_chk_bssid since that function modifies the + * RCR register too. */ + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&rx_conf)); + + /*TODO: we disable broadcase now, so enable here */ + if (changed_flags & FIF_ALLMULTI) { + if (*new_flags & FIF_ALLMULTI) { + rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AM] | + rtlpriv->cfg->maps[MAC_RCR_AB]; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "Enable receive multicast frame\n"); + } else { + rx_conf &= ~(rtlpriv->cfg->maps[MAC_RCR_AM] | + rtlpriv->cfg->maps[MAC_RCR_AB]); + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "Disable receive multicast frame\n"); + } + } + + if (changed_flags & FIF_FCSFAIL) { + if (*new_flags & FIF_FCSFAIL) { + rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACRC32]; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "Enable receive FCS error frame\n"); + } else { + rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACRC32]; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, + "Disable receive FCS error frame\n"); + } + } + + if (changed_flags & FIF_CONTROL) { if (*new_flags & FIF_CONTROL) { - mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF]; + rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF]; RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "Enable receive control frame\n"); } else { - mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF]; + rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF]; RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "Disable receive control frame\n"); } @@ -537,15 +543,17 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw, if (changed_flags & FIF_OTHER_BSS) { if (*new_flags & FIF_OTHER_BSS) { - mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AAP]; + rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AAP]; RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "Enable receive other BSS's frame\n"); } else { - mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_AAP]; + rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_AAP]; RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "Disable receive other BSS's frame\n"); } } + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(&rx_conf)); } static int rtl_op_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, From cc1ad9d267d336fcb50c26c9e3fe1a9b78302e78 Mon Sep 17 00:00:00 2001 From: "Zhao, Gang" Date: Sun, 16 Feb 2014 22:31:37 +0800 Subject: [PATCH 246/414] b43: Kconfig: let config B43_BCMA_PIO depends on B43 Logically, config B43_BCMA_PIO should depend on B43. This also solves the problem that sub options of b43 driver didn't indent correctly in make menuconfig's ncurses window. Signed-off-by: Zhao, Gang Signed-off-by: John W. Linville --- drivers/net/wireless/b43/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 51ff0b198d0a..088d544ec63f 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -92,7 +92,7 @@ config B43_SDIO # if we can do DMA. config B43_BCMA_PIO bool - depends on B43_BCMA + depends on B43 && B43_BCMA select BCMA_BLOCKIO default y From 1a2b250bfe32c780fe371feff56c6bd6117097fa Mon Sep 17 00:00:00 2001 From: "Zhao, Gang" Date: Sun, 16 Feb 2014 22:31:38 +0800 Subject: [PATCH 247/414] b43: return true / false instead of numbers in functions which return bool value Signed-off-by: Zhao, Gang Signed-off-by: John W. Linville --- drivers/net/wireless/b43/debugfs.h | 2 +- drivers/net/wireless/b43/phy_common.c | 4 ++-- drivers/net/wireless/b43/pio.c | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h index 822aad8842f4..50517b801cb4 100644 --- a/drivers/net/wireless/b43/debugfs.h +++ b/drivers/net/wireless/b43/debugfs.h @@ -86,7 +86,7 @@ void b43_debugfs_log_txstat(struct b43_wldev *dev, static inline bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature) { - return 0; + return false; } static inline void b43_debugfs_init(void) diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index f01676ac481b..dbaa51890198 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -133,9 +133,9 @@ void b43_phy_exit(struct b43_wldev *dev) bool b43_has_hardware_pctl(struct b43_wldev *dev) { if (!dev->phy.hardware_power_control) - return 0; + return false; if (!dev->phy.ops->supports_hwpctl) - return 0; + return false; return dev->phy.ops->supports_hwpctl(dev); } diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index a73ff8c9deb5..a4ff5e2a42b9 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -637,7 +637,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q) ctl = b43_piorx_read32(q, B43_PIO8_RXCTL); if (!(ctl & B43_PIO8_RXCTL_FRAMERDY)) - return 0; + return false; b43_piorx_write32(q, B43_PIO8_RXCTL, B43_PIO8_RXCTL_FRAMERDY); for (i = 0; i < 10; i++) { @@ -651,7 +651,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q) ctl = b43_piorx_read16(q, B43_PIO_RXCTL); if (!(ctl & B43_PIO_RXCTL_FRAMERDY)) - return 0; + return false; b43_piorx_write16(q, B43_PIO_RXCTL, B43_PIO_RXCTL_FRAMERDY); for (i = 0; i < 10; i++) { @@ -662,7 +662,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q) } } b43dbg(q->dev->wl, "PIO RX timed out\n"); - return 1; + return true; data_ready: /* Get the preamble (RX header) */ @@ -759,7 +759,7 @@ data_ready: b43_rx(q->dev, skb, rxhdr); - return 1; + return true; rx_error: if (err_msg) @@ -769,7 +769,7 @@ rx_error: else b43_piorx_write16(q, B43_PIO_RXCTL, B43_PIO_RXCTL_DATARDY); - return 1; + return true; } void b43_pio_rx(struct b43_pio_rxqueue *q) From da1bc3c4888c31e0b8a8bd4703bb1e7ed42f3be4 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 17 Feb 2014 15:25:01 +0530 Subject: [PATCH 248/414] net: wireless: wl3501_cs: Remove duplicate include linux/etherdevice.h was included twice. Signed-off-by: Sachin Kamat Signed-off-by: John W. Linville --- drivers/net/wireless/wl3501_cs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index d24d4a958c67..66bca677c4fa 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -43,7 +43,6 @@ #include #include #include -#include #include From 0867c8874ef0f32aa0ef4f7d7aef0a0109d939a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 18 Feb 2014 10:07:52 +0100 Subject: [PATCH 249/414] hostap: add Netgear MA401 card MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a relatively old Prism2 card which is correctly supported by the hostap driver. Signed-off-by: Cédric Le Goater Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_cs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 9f825f2620da..b6ec51923b20 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -677,6 +677,8 @@ static const struct pcmcia_device_id hostap_cs_ids[] = { PCMCIA_DEVICE_PROD_ID12( "ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee), + PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", + 0xa37434e9, 0x9762e8f1), PCMCIA_DEVICE_PROD_ID123( "Pretec", "CompactWLAN Card 802.11b", "2.5", 0x1cadd3e5, 0xe697636c, 0x7a5bfcf1), From 16847f47bab6f23fbaf17c5beeb0db1db0836b6a Mon Sep 17 00:00:00 2001 From: Avinash kumar Date: Tue, 18 Feb 2014 17:04:10 +0530 Subject: [PATCH 250/414] drivers:net:wireless:airo.c:checkpatch.pl cleanup removed following warnings- drivers/net/wireless/airo.c:39: WARNING: Use #include instead of drivers/net/wireless/airo.c:48: WARNING: Use #include instead of Signed-off-by: Avinash Kumar Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index edf4b57c4aaa..79c4a7692d50 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include From 7b4f663ee60d24f791aeb4d58569fa18c59fc440 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 18 Feb 2014 20:41:08 +0200 Subject: [PATCH 251/414] ath9k: Enable U-APSD AP mode support mac80211 handles the actual operations, so ath9k can just indicate support for this. Based on initial tests, this combination seems to work fine. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- 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 07a0315dd2f6..4856a1739ade 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -949,6 +949,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ; hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; hw->queues = 4; hw->max_rates = 4; From 629873f22eadcd29f47969822eb640d3690116c8 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Tue, 18 Feb 2014 15:47:55 -0800 Subject: [PATCH 252/414] mwifiex: use del_timer_sync instead of del_timer Use SMP safe del_timer_sync instead of del_timer for cancelling timers. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/11n_rxreorder.c | 2 +- drivers/net/wireless/mwifiex/cmdevt.c | 2 +- drivers/net/wireless/mwifiex/init.c | 2 +- drivers/net/wireless/mwifiex/main.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index b361257fb65e..1cfdbfe2b59f 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -142,7 +142,7 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv, mwifiex_11n_dispatch_pkt(priv, tbl, (tbl->start_win + tbl->win_size) & (MAX_TID_VALUE - 1)); - del_timer(&tbl->timer_context.timer); + del_timer_sync(&tbl->timer_context.timer); spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); list_del(&tbl->list); diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 21544602043c..f4faeaf322be 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -786,7 +786,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) unsigned long flags; /* Now we got response from FW, cancel the command timer */ - del_timer(&adapter->cmd_timer); + del_timer_sync(&adapter->cmd_timer); if (!adapter->curr_cmd || !adapter->curr_cmd->resp_skb) { resp = (struct host_cmd_ds_command *) adapter->upld_buf; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index a4cd2cb066ed..759492817aeb 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -620,7 +620,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) /* cancel current command */ if (adapter->curr_cmd) { dev_warn(adapter->dev, "curr_cmd is still in processing\n"); - del_timer(&adapter->cmd_timer); + del_timer_sync(&adapter->cmd_timer); mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd); adapter->curr_cmd = NULL; } diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 4d79761b9c87..f87ce28a8060 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -194,7 +194,7 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter) if (adapter->if_ops.cleanup_if) adapter->if_ops.cleanup_if(adapter); - del_timer(&adapter->cmd_timer); + del_timer_sync(&adapter->cmd_timer); /* Free private structures */ for (i = 0; i < adapter->priv_num; i++) { From c1c2ce0ce3ffb4989506e03247ee80949a0bfa25 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Tue, 18 Feb 2014 15:47:56 -0800 Subject: [PATCH 253/414] mwifiex: remove redundant del_timer While modifying timer, we need not delete timer. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/11n_rxreorder.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index 1cfdbfe2b59f..eb17282b364f 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -466,7 +466,6 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, start_win = tbl->start_win; win_size = tbl->win_size; end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1); - del_timer(&tbl->timer_context.timer); mod_timer(&tbl->timer_context.timer, jiffies + msecs_to_jiffies(MIN_FLUSH_TIMER_MS * win_size)); From e3c91683b5c6498df19e5fba51fdb61fef5f4227 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 18 Feb 2014 15:47:57 -0800 Subject: [PATCH 254/414] mwifiex: enable obss scan offload feature flag We don't perform OBSS scan internally. As we intend to use corresponding feature in application, we will enable this flag. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 6948a97af839..68c51a8e5bea 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2908,7 +2908,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->features |= NL80211_FEATURE_HT_IBSS | NL80211_FEATURE_INACTIVITY_TIMER | - NL80211_FEATURE_LOW_PRIORITY_SCAN; + NL80211_FEATURE_LOW_PRIORITY_SCAN | + NL80211_FEATURE_NEED_OBSS_SCAN; /* Reserve space for mwifiex specific private data for BSS */ wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv); From 59f01183a7846c1621a23dd88182f5a890f38717 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 19 Feb 2014 09:15:09 +0100 Subject: [PATCH 255/414] iwl3945: fix wakeup interrupt We have only 5 tx queues on 3945, updating il->txq[5] results in writing random value to HBUS_TARG_WRPTR register. Additionally use spin lock to protect txq->write_ptr and txq->need_update fields also modified in TX path. Tested-by: Pedro Francisco Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/3945-mac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index 0487461ae4da..46b32d41aa2f 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -1495,12 +1495,14 @@ il3945_irq_tasklet(struct il_priv *il) if (inta & CSR_INT_BIT_WAKEUP) { D_ISR("Wakeup interrupt\n"); il_rx_queue_update_write_ptr(il, &il->rxq); + + spin_lock_irqsave(&il->lock, flags); il_txq_update_write_ptr(il, &il->txq[0]); il_txq_update_write_ptr(il, &il->txq[1]); il_txq_update_write_ptr(il, &il->txq[2]); il_txq_update_write_ptr(il, &il->txq[3]); il_txq_update_write_ptr(il, &il->txq[4]); - il_txq_update_write_ptr(il, &il->txq[5]); + spin_unlock_irqrestore(&il->lock, flags); il->isr_stats.wakeup++; handled |= CSR_INT_BIT_WAKEUP; From 8e67427aca2f0dda148181af930732734f6e2e42 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 19 Feb 2014 09:15:10 +0100 Subject: [PATCH 256/414] iwlegacy: merge reclaim check Merge reclaim check for 3945 & 4965. This add some more checks for 3945, most importantly N_RX notify. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/3945-mac.c | 9 +-------- drivers/net/wireless/iwlegacy/4965-mac.c | 12 +----------- drivers/net/wireless/iwlegacy/common.h | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index 46b32d41aa2f..dc1d20cf64ee 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -1248,14 +1248,7 @@ il3945_rx_handle(struct il_priv *il) len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK; len += sizeof(u32); /* account for status word */ - /* Reclaim a command buffer only if this packet is a response - * to a (driver-originated) command. - * If the packet (e.g. Rx frame) originated from uCode, - * there is no command buffer to reclaim. - * Ucode should set SEQ_RX_FRAME bit if ucode-originated, - * but apparently a few don't get set; catch them here. */ - reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && - pkt->hdr.cmd != N_STATS && pkt->hdr.cmd != C_TX; + reclaim = il_need_reclaim(il, pkt); /* Based on type of command response or notification, * handle those that need handling via function in diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 43f488a8cda2..50673f7e30bc 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -4274,17 +4274,7 @@ il4965_rx_handle(struct il_priv *il) len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK; len += sizeof(u32); /* account for status word */ - /* Reclaim a command buffer only if this packet is a response - * to a (driver-originated) command. - * If the packet (e.g. Rx frame) originated from uCode, - * there is no command buffer to reclaim. - * Ucode should set SEQ_RX_FRAME bit if ucode-originated, - * but apparently a few don't get set; catch them here. */ - reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && - (pkt->hdr.cmd != N_RX_PHY) && (pkt->hdr.cmd != N_RX) && - (pkt->hdr.cmd != N_RX_MPDU) && - (pkt->hdr.cmd != N_COMPRESSED_BA) && - (pkt->hdr.cmd != N_STATS) && (pkt->hdr.cmd != C_TX); + reclaim = il_need_reclaim(il, pkt); /* Based on type of command response or notification, * handle those that need handling via function in diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h index ad123d66ab6c..21964d2cad83 100644 --- a/drivers/net/wireless/iwlegacy/common.h +++ b/drivers/net/wireless/iwlegacy/common.h @@ -1978,6 +1978,20 @@ void il_wr_prph(struct il_priv *il, u32 addr, u32 val); u32 il_read_targ_mem(struct il_priv *il, u32 addr); void il_write_targ_mem(struct il_priv *il, u32 addr, u32 val); +static inline bool il_need_reclaim(struct il_priv *il, struct il_rx_pkt *pkt) +{ + /* Reclaim a command buffer only if this packet is a response + * to a (driver-originated) command. If the packet (e.g. Rx frame) + * originated from uCode, there is no command buffer to reclaim. + * Ucode should set SEQ_RX_FRAME bit if ucode-originated, but + * apparently a few don't get set; catch them here. + */ + return !(pkt->hdr.sequence & SEQ_RX_FRAME) && + pkt->hdr.cmd != N_STATS && pkt->hdr.cmd != C_TX && + pkt->hdr.cmd != N_RX_PHY && pkt->hdr.cmd != N_RX && + pkt->hdr.cmd != N_RX_MPDU && pkt->hdr.cmd != N_COMPRESSED_BA; +} + static inline void _il_write8(struct il_priv *il, u32 ofs, u8 val) { From dbdac2b581811e1f2a573454451136c2497de4fc Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 19 Feb 2014 09:15:11 +0100 Subject: [PATCH 257/414] iwlegacy: properly enable power saving Even if we mark PS on, device still worked in normal mode. Patch corrects that and now we send proper powertable command to device, which put it in sleep mode when PS is on. Reported-and-tested-by: Tino Keitel Tested-by: Pedro Francisco Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/commands.h | 3 +- drivers/net/wireless/iwlegacy/common.c | 83 ++++++++++++++++++++---- drivers/net/wireless/iwlegacy/common.h | 1 + 3 files changed, 72 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/iwlegacy/commands.h b/drivers/net/wireless/iwlegacy/commands.h index 048421511988..dd744135c956 100644 --- a/drivers/net/wireless/iwlegacy/commands.h +++ b/drivers/net/wireless/iwlegacy/commands.h @@ -2270,7 +2270,8 @@ struct il_spectrum_notification { */ #define IL_POWER_VEC_SIZE 5 -#define IL_POWER_DRIVER_ALLOW_SLEEP_MSK cpu_to_le16(BIT(0)) +#define IL_POWER_DRIVER_ALLOW_SLEEP_MSK cpu_to_le16(BIT(0)) +#define IL_POWER_SLEEP_OVER_DTIM_MSK cpu_to_le16(BIT(2)) #define IL_POWER_PCI_PM_MSK cpu_to_le16(BIT(3)) struct il3945_powertable_cmd { diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index 02e8233ccf29..4f42174d9994 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -1078,29 +1078,82 @@ EXPORT_SYMBOL(il_get_channel_info); * Setting power level allows the card to go to sleep when not busy. * * We calculate a sleep command based on the required latency, which - * we get from mac80211. In order to handle thermal throttling, we can - * also use pre-defined power levels. + * we get from mac80211. */ -/* - * This defines the old power levels. They are still used by default - * (level 1) and for thermal throttle (levels 3 through 5) - */ - -struct il_power_vec_entry { - struct il_powertable_cmd cmd; - u8 no_dtim; /* number of skip dtim */ -}; +#define SLP_VEC(X0, X1, X2, X3, X4) { \ + cpu_to_le32(X0), \ + cpu_to_le32(X1), \ + cpu_to_le32(X2), \ + cpu_to_le32(X3), \ + cpu_to_le32(X4) \ +} static void -il_power_sleep_cam_cmd(struct il_priv *il, struct il_powertable_cmd *cmd) +il_build_powertable_cmd(struct il_priv *il, struct il_powertable_cmd *cmd) { + const __le32 interval[3][IL_POWER_VEC_SIZE] = { + SLP_VEC(2, 2, 4, 6, 0xFF), + SLP_VEC(2, 4, 7, 10, 10), + SLP_VEC(4, 7, 10, 10, 0xFF) + }; + int i, dtim_period, no_dtim; + u32 max_sleep; + bool skip; + memset(cmd, 0, sizeof(*cmd)); if (il->power_data.pci_pm) cmd->flags |= IL_POWER_PCI_PM_MSK; - D_POWER("Sleep command for CAM\n"); + /* if no Power Save, we are done */ + if (il->power_data.ps_disabled) + return; + + cmd->flags = IL_POWER_DRIVER_ALLOW_SLEEP_MSK; + cmd->keep_alive_seconds = 0; + cmd->debug_flags = 0; + cmd->rx_data_timeout = cpu_to_le32(25 * 1024); + cmd->tx_data_timeout = cpu_to_le32(25 * 1024); + cmd->keep_alive_beacons = 0; + + dtim_period = il->vif ? il->vif->bss_conf.dtim_period : 0; + + if (dtim_period <= 2) { + memcpy(cmd->sleep_interval, interval[0], sizeof(interval[0])); + no_dtim = 2; + } else if (dtim_period <= 10) { + memcpy(cmd->sleep_interval, interval[1], sizeof(interval[1])); + no_dtim = 2; + } else { + memcpy(cmd->sleep_interval, interval[2], sizeof(interval[2])); + no_dtim = 0; + } + + if (dtim_period == 0) { + dtim_period = 1; + skip = false; + } else { + skip = !!no_dtim; + } + + if (skip) { + __le32 tmp = cmd->sleep_interval[IL_POWER_VEC_SIZE - 1]; + + max_sleep = le32_to_cpu(tmp); + if (max_sleep == 0xFF) + max_sleep = dtim_period * (skip + 1); + else if (max_sleep > dtim_period) + max_sleep = (max_sleep / dtim_period) * dtim_period; + cmd->flags |= IL_POWER_SLEEP_OVER_DTIM_MSK; + } else { + max_sleep = dtim_period; + cmd->flags &= ~IL_POWER_SLEEP_OVER_DTIM_MSK; + } + + for (i = 0; i < IL_POWER_VEC_SIZE; i++) + if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) + cmd->sleep_interval[i] = cpu_to_le32(max_sleep); } static int @@ -1173,7 +1226,8 @@ il_power_update_mode(struct il_priv *il, bool force) { struct il_powertable_cmd cmd; - il_power_sleep_cam_cmd(il, &cmd); + il_build_powertable_cmd(il, &cmd); + return il_power_set_mode(il, &cmd, force); } EXPORT_SYMBOL(il_power_update_mode); @@ -5081,6 +5135,7 @@ set_ch_out: } if (changed & (IEEE80211_CONF_CHANGE_PS | IEEE80211_CONF_CHANGE_IDLE)) { + il->power_data.ps_disabled = !(conf->flags & IEEE80211_CONF_PS); ret = il_power_update_mode(il, false); if (ret) D_MAC80211("Error setting sleep level\n"); diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h index 21964d2cad83..13145ad2c0db 100644 --- a/drivers/net/wireless/iwlegacy/common.h +++ b/drivers/net/wireless/iwlegacy/common.h @@ -1123,6 +1123,7 @@ struct il_power_mgr { struct il_powertable_cmd sleep_cmd_next; int debug_sleep_level_override; bool pci_pm; + bool ps_disabled; }; struct il_priv { From 434bb46c36c545b4a81c02c73e24560c303c3388 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Feb 2014 15:44:23 -0500 Subject: [PATCH 258/414] wireless/rt2x00: don't use PREPARE_WORK in rt2800usb.c PREPARE_[DELAYED_]WORK() are being phased out. They have few users and a nasty surprise in terms of reentrancy guarantee as workqueue considers work items to be different if they don't have the same work function. Update rt2800usb.c to use INIT_WORK() instead of PREPARE_WORK(). As the work item isn't in active use during rt2800usb_probe_hw(), this doesn't cause any behavior difference. It would probably be best to route this with other related updates through the workqueue tree. Only compile tested. Signed-off-by: Tejun Heo Cc: Ivo van Doorn Cc: Gertjan van Wingerde Cc: Helmut Schaa Cc: linux-wireless@vger.kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 14a90ddf585c..a49c3d73ea2c 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -764,7 +764,7 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Overwrite TX done handler */ - PREPARE_WORK(&rt2x00dev->txdone_work, rt2800usb_work_txdone); + INIT_WORK(&rt2x00dev->txdone_work, rt2800usb_work_txdone); return 0; } From 443626e5a956d0c740034e53cf4164c2c1069cd4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 21 Feb 2014 11:45:36 +0100 Subject: [PATCH 259/414] ath9k: list more reset causes in debugfs Number of MAC hangs and stuck beacons were missing Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index ab7264c1d8f7..f42ed3b17330 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -865,6 +865,12 @@ static ssize_t read_file_reset(struct file *file, char __user *user_buf, len += scnprintf(buf + len, sizeof(buf) - len, "%17s: %2d\n", "PLL RX Hang", sc->debug.stats.reset[RESET_TYPE_PLL_HANG]); + len += scnprintf(buf + len, sizeof(buf) - len, + "%17s: %2d\n", "MAC Hang", + sc->debug.stats.reset[RESET_TYPE_MAC_HANG]); + len += scnprintf(buf + len, sizeof(buf) - len, + "%17s: %2d\n", "Stuck Beacon", + sc->debug.stats.reset[RESET_TYPE_BEACON_STUCK]); len += scnprintf(buf + len, sizeof(buf) - len, "%17s: %2d\n", "MCI Reset", sc->debug.stats.reset[RESET_TYPE_MCI]); From 2120ac96744f9517f19241b7c0adb796eeb53eb6 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 21 Feb 2014 14:46:43 -0800 Subject: [PATCH 260/414] ath9k: Use static const Trivially reduces text size too. $ size drivers/net/wireless/ath/ath9k/debug.o* text data bss dec hex filename 34436 2528 5128 42092 a46c drivers/net/wireless/ath/ath9k/debug.o.new 34464 2528 5128 42120 a488 drivers/net/wireless/ath/ath9k/debug.o.old Signed-off-by: Joe Perches Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index f42ed3b17330..f8924efdad55 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -135,7 +135,8 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf, struct ath_softc *sc = file->private_data; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_hw *ah = sc->sc_ah; - unsigned int len = 0, size = 1024; + unsigned int len = 0; + const unsigned int size = 1024; ssize_t retval = 0; char *buf; @@ -307,13 +308,13 @@ static ssize_t read_file_antenna_diversity(struct file *file, struct ath_antenna_stats *as_main = &sc->debug.stats.ant_stats[ANT_MAIN]; struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT]; struct ath_hw_antcomb_conf div_ant_conf; - unsigned int len = 0, size = 1024; + unsigned int len = 0; + const unsigned int size = 1024; ssize_t retval = 0; char *buf; - char *lna_conf_str[4] = {"LNA1_MINUS_LNA2", - "LNA2", - "LNA1", - "LNA1_PLUS_LNA2"}; + static const char *lna_conf_str[4] = { + "LNA1_MINUS_LNA2", "LNA2", "LNA1", "LNA1_PLUS_LNA2" + }; buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) @@ -716,10 +717,13 @@ static ssize_t read_file_queues(struct file *file, char __user *user_buf, struct ath_softc *sc = file->private_data; struct ath_txq *txq; char *buf; - unsigned int len = 0, size = 1024; + unsigned int len = 0; + const unsigned int size = 1024; ssize_t retval = 0; int i; - char *qname[4] = {"VO", "VI", "BE", "BK"}; + static const char *qname[4] = { + "VO", "VI", "BE", "BK" + }; buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) From cd6cfd7311a385144a2f9c74f692ae2df3ae033f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 22 Feb 2014 14:52:48 +0100 Subject: [PATCH 261/414] ath9k: do not set half/quarter channel flags in AR_PHY_MODE 5/10 MHz channel bandwidth is configured via the PLL clock, instead of the AR_PHY_MODE register. Using that register is AR93xx specific, and makes the mode incompatible with earlier chipsets. In some early versions, these flags were apparently applied at the wrong point in time and thus did not cause connectivity issues, however now they are causing problems, as pointed out in this OpenWrt ticket: https://dev.openwrt.org/ticket/14916 Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 09facba1dc6d..8927fc34d84c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -868,10 +868,6 @@ static void ar9003_hw_set_rfmode(struct ath_hw *ah, if (IS_CHAN_A_FAST_CLOCK(ah, chan)) rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); - if (IS_CHAN_QUARTER_RATE(chan)) - rfMode |= AR_PHY_MODE_QUARTER; - if (IS_CHAN_HALF_RATE(chan)) - rfMode |= AR_PHY_MODE_HALF; if (rfMode & (AR_PHY_MODE_QUARTER | AR_PHY_MODE_HALF)) REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, From affad456f2a8fa5351c711dd91763387976a6400 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 22 Feb 2014 14:52:49 +0100 Subject: [PATCH 262/414] ath9k: make some hardware reset log messages debug-only On some chips, baseband watchdog hangs are more common than others, and the driver has support for handling them. Interrupts even after a watchdog hang are also quite common, so there's not much point in spamming the user's logfiles. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index afce549a097b..14a7524b4b50 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -451,7 +451,7 @@ void ath9k_tasklet(unsigned long data) * interrupts are enabled in the reset routine. */ atomic_inc(&ah->intr_ref_cnt); - ath_dbg(common, ANY, "FATAL: Skipping interrupts\n"); + ath_dbg(common, RESET, "FATAL: Skipping interrupts\n"); goto out; } @@ -471,7 +471,7 @@ void ath9k_tasklet(unsigned long data) * interrupts are enabled in the reset routine. */ atomic_inc(&ah->intr_ref_cnt); - ath_dbg(common, ANY, + ath_dbg(common, RESET, "BB_WATCHDOG: Skipping interrupts\n"); goto out; } @@ -484,7 +484,7 @@ void ath9k_tasklet(unsigned long data) type = RESET_TYPE_TX_GTT; ath9k_queue_reset(sc, type); atomic_inc(&ah->intr_ref_cnt); - ath_dbg(common, ANY, + ath_dbg(common, RESET, "GTT: Skipping interrupts\n"); goto out; } From ef1b4141d0430583743a6045901e4d1a73557a33 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 22 Feb 2014 14:55:57 +0100 Subject: [PATCH 263/414] ath5k: set SURVEY_INFO_IN_USE on get_survey Only one channel is returned - the one currently being used. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 4ee01f654235..afb23b3cc7be 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -681,6 +681,7 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) survey->channel = conf->chandef.chan; survey->noise = ah->ah_noise_floor; survey->filled = SURVEY_INFO_NOISE_DBM | + SURVEY_INFO_IN_USE | SURVEY_INFO_CHANNEL_TIME | SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_RX | From ede81a2a1250dc9296a2b9bf384bba4e336a02e2 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Tue, 25 Feb 2014 17:16:22 +0100 Subject: [PATCH 264/414] Bluetooth: Fix NULL pointer dereference when sending data When trying to allocate skb for new PDU, l2cap_chan is unlocked so we can sleep waiting for memory as otherwise there's possible deadlock as fixed in e454c84464. However, in a6a5568c03 lock was moved from socket to channel level and it's no longer safe to just unlock and lock again without checking l2cap_chan state since channel can be disconnected when lock is not held. This patch adds missing checks for l2cap_chan state when returning from call which allocates skb. Scenario is easily reproducible by running rfcomm-tester in a loop. BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] l2cap_do_send+0x29/0x120 [bluetooth] PGD 0 Oops: 0000 [#1] SMP Modules linked in: CPU: 7 PID: 4038 Comm: krfcommd Not tainted 3.14.0-rc2+ #15 Hardware name: Dell Inc. OptiPlex 790/0HY9JP, BIOS A10 11/24/2011 task: ffff8802bdd731c0 ti: ffff8801ec986000 task.ti: ffff8801ec986000 RIP: 0010:[] [] l2cap_do_send+0x29/0x120 RSP: 0018:ffff8801ec987ad8 EFLAGS: 00010202 RAX: 0000000000000000 RBX: ffff8800c5796800 RCX: 0000000000000000 RDX: ffff880410e7a800 RSI: ffff8802b6c1da00 RDI: ffff8800c5796800 RBP: ffff8801ec987af8 R08: 00000000000000c0 R09: 0000000000000300 R10: 000000000000573b R11: 000000000000573a R12: ffff8802b6c1da00 R13: 0000000000000000 R14: ffff8802b6c1da00 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffff88042dce0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 000000041257c000 CR4: 00000000000407e0 Stack: ffff8801ec987d78 ffff8800c5796800 ffff8801ec987d78 0000000000000000 ffff8801ec987ba8 ffffffffa0449e37 0000000000000004 ffff8801ec987af0 ffff8801ec987d40 0000000000000282 0000000000000000 ffffffff00000004 Call Trace: [] l2cap_chan_send+0xaa7/0x1120 [bluetooth] [] ? _raw_spin_unlock_bh+0x20/0x40 [] l2cap_sock_sendmsg+0xcb/0x110 [bluetooth] [] sock_sendmsg+0xaf/0xc0 [] ? update_curr+0x141/0x200 [] ? dequeue_entity+0x181/0x520 [] kernel_sendmsg+0x40/0x60 [] rfcomm_send_frame+0x45/0x70 [rfcomm] [] ? internal_add_timer+0x20/0x50 [] rfcomm_send_cmd+0x34/0x60 [rfcomm] [] rfcomm_send_disc+0x75/0xa0 [rfcomm] [] rfcomm_run+0x8cc/0x1a30 [rfcomm] [] ? rfcomm_check_accept+0xc0/0xc0 [rfcomm] [] kthread+0xc9/0xe0 [] ? flush_kthread_worker+0xb0/0xb0 [] ret_from_fork+0x7c/0xb0 [] ? flush_kthread_worker+0xb0/0xb0 Code: 00 00 66 66 66 66 90 55 48 89 e5 48 83 ec 20 f6 05 d6 a3 02 00 04 RIP [] l2cap_do_send+0x29/0x120 [bluetooth] RSP CR2: 0000000000000000 Signed-off-by: Andrzej Kaczmarek Acked-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 6ace116f3b39..7bd78c5487fb 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2434,6 +2434,14 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, if (IS_ERR(skb)) return PTR_ERR(skb); + /* Channel lock is released before requesting new skb and then + * reacquired thus we need to recheck channel state. + */ + if (chan->state != BT_CONNECTED) { + kfree_skb(skb); + return -ENOTCONN; + } + l2cap_do_send(chan, skb); return len; } @@ -2483,6 +2491,14 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, if (IS_ERR(skb)) return PTR_ERR(skb); + /* Channel lock is released before requesting new skb and then + * reacquired thus we need to recheck channel state. + */ + if (chan->state != BT_CONNECTED) { + kfree_skb(skb); + return -ENOTCONN; + } + l2cap_do_send(chan, skb); err = len; break; From a4858cb942b9afa57c1220aa5d9b536a0d7ec623 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 25 Feb 2014 19:56:31 +0200 Subject: [PATCH 265/414] Bluetooth: Fix advertising address type when toggling connectable When the connectable setting is toggled using mgmt_set_connectable the HCI_CONNECTABLE flag will only be set once the related HCI commands succeed. When determining what kind of advertising to do we need to therefore also check whether there is a pending Set Connectable command in addition to the current flag value. The enable_advertising function was already taking care of this for the advertising type with the help of the get_adv_type function, but was failing to do the same for the address type selection. This patch converts the get_adv_type function to be more generic in that it returns the expected connectable state and updates the enable_advertising function to use the return value both for the advertising type as well as the advertising address type. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 25b8b278debd..d6e269287cfc 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -817,10 +817,9 @@ static void update_class(struct hci_request *req) hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod); } -static u8 get_adv_type(struct hci_dev *hdev) +static bool get_connectable(struct hci_dev *hdev) { struct pending_cmd *cmd; - bool connectable; /* If there's a pending mgmt command the flag will not yet have * it's final value, so check for this first. @@ -828,12 +827,10 @@ static u8 get_adv_type(struct hci_dev *hdev) cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev); if (cmd) { struct mgmt_mode *cp = cmd->param; - connectable = !!cp->val; - } else { - connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags); + return cp->val; } - return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND; + return test_bit(HCI_CONNECTABLE, &hdev->dev_flags); } static void enable_advertising(struct hci_request *req) @@ -841,17 +838,21 @@ static void enable_advertising(struct hci_request *req) struct hci_dev *hdev = req->hdev; struct hci_cp_le_set_adv_param cp; u8 own_addr_type, enable = 0x01; - bool require_privacy; + bool connectable; - require_privacy = !test_bit(HCI_CONNECTABLE, &hdev->dev_flags); + connectable = get_connectable(hdev); - if (hci_update_random_address(req, require_privacy, &own_addr_type) < 0) + /* Set require_privacy to true only when non-connectable + * advertising is used. In that case it is fine to use a + * non-resolvable private address. + */ + if (hci_update_random_address(req, !connectable, &own_addr_type) < 0) return; memset(&cp, 0, sizeof(cp)); cp.min_interval = __constant_cpu_to_le16(0x0800); cp.max_interval = __constant_cpu_to_le16(0x0800); - cp.type = get_adv_type(hdev); + cp.type = connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND; cp.own_address_type = own_addr_type; cp.channel_map = hdev->le_adv_channel_map; From a9a58f861218aee89fbe8ed4db054a7eee6f58c2 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 25 Feb 2014 22:24:37 +0200 Subject: [PATCH 266/414] Bluetooth: Ignore IRKs with no Identity Address The Core Specification (4.1) leaves room for sending an SMP Identity Address Information PDU with an all-zeros BD_ADDR value. This essentially means that we would not have an Identity Address for the device and the only means of identifying it would be the IRK value itself. Due to lack of any known implementations behaving like this it's best to keep our implementation as simple as possible as far as handling such situations is concerned. This patch updates the Identity Address Information handler function to simply ignore the IRK received from such a device. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 79a80f44c832..50355d045992 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1003,6 +1003,19 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, skb_pull(skb, sizeof(*info)); + /* Strictly speaking the Core Specification (4.1) allows sending + * an empty address which would force us to rely on just the IRK + * as "identity information". However, since such + * implementations are not known of and in order to not over + * complicate our implementation, simply pretend that we never + * received an IRK for such a device. + */ + if (!bacmp(&info->bdaddr, BDADDR_ANY)) { + BT_ERR("Ignoring IRK with no identity address"); + smp_distribute_keys(conn, 1); + return 0; + } + bacpy(&smp->id_addr, &info->bdaddr); smp->id_addr_type = info->addr_type; From 9747a9f31756362e1b9d0b2347c25ae5120c3319 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 26 Feb 2014 23:33:43 +0200 Subject: [PATCH 267/414] Bluetooth: Track not yet received keys in SMP To make is easier to track which keys we've received and which ones we're still waiting for simply clear the corresponding key bits from smp->remote_key_dist as they get received. This will allow us to simplify the code for checking for SMP completion in subsequent patches. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 50355d045992..fe41df5c320c 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -948,6 +948,9 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY)) return 0; + /* Mark the information as received */ + smp->remote_key_dist &= ~SMP_DIST_ENC_KEY; + skb_pull(skb, sizeof(*rp)); hci_dev_lock(hdev); @@ -1001,6 +1004,9 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, if (!(smp->remote_key_dist & SMP_DIST_ID_KEY)) return 0; + /* Mark the information as received */ + smp->remote_key_dist &= ~SMP_DIST_ID_KEY; + skb_pull(skb, sizeof(*info)); /* Strictly speaking the Core Specification (4.1) allows sending From efabba37fec4cf093fedcfcba443d0f04b606eb4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 26 Feb 2014 23:33:44 +0200 Subject: [PATCH 268/414] Bluetooth: Simplify logic for checking for SMP completion Now that smp->remote_key_dist is tracking the keys we're still waiting for we can use it to simplify the logic for checking whether we're done with key distribution or not. At the same time the reliance on the "force" parameter of smp_distribute_keys goes away and it can completely be removed in a subsequent patch. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index fe41df5c320c..1b17adfffef8 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1184,7 +1184,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) rsp = (void *) &smp->prsp[1]; /* The responder sends its keys first */ - if (!force && hcon->out && (rsp->resp_key_dist & 0x07)) + if (hcon->out && (smp->remote_key_dist & 0x07)) return 0; req = (void *) &smp->preq[1]; @@ -1259,13 +1259,16 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) *keydist &= ~SMP_DIST_SIGN; } - if (hcon->out || force || !(rsp->init_key_dist & 0x07)) { - clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags); - cancel_delayed_work_sync(&conn->security_timer); - set_bit(SMP_FLAG_COMPLETE, &smp->smp_flags); - smp_notify_keys(conn); - smp_chan_destroy(conn); - } + /* If there are still keys to be received wait for them */ + if ((smp->remote_key_dist & 0x07)) + return 0; + + clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags); + cancel_delayed_work_sync(&conn->security_timer); + set_bit(SMP_FLAG_COMPLETE, &smp->smp_flags); + smp_notify_keys(conn); + + smp_chan_destroy(conn); return 0; } From 4bd6d38e7f58b163138d3fea8fa135de523bfb92 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 26 Feb 2014 23:33:45 +0200 Subject: [PATCH 269/414] Bluetooth: Remove unneeded "force" parameter from smp_distribute_keys() Now that to-be-received keys are properly tracked we no-longer need the "force" parameter to smp_distribute_keys(). It was essentially acting as an indicator whether all keys have been received, but now it's just redundant together with smp->remote_key_dist. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 2 +- net/bluetooth/smp.c | 10 +++++----- net/bluetooth/smp.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 7bd78c5487fb..d8d990215158 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7267,7 +7267,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (hcon->type == LE_LINK) { if (!status && encrypt) - smp_distribute_keys(conn, 0); + smp_distribute_keys(conn); cancel_delayed_work(&conn->security_timer); } diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 1b17adfffef8..0de98fe23330 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -960,7 +960,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) rp->ediv, rp->rand); smp->ltk = ltk; if (!(smp->remote_key_dist & SMP_DIST_ID_KEY)) - smp_distribute_keys(conn, 1); + smp_distribute_keys(conn); hci_dev_unlock(hdev); return 0; @@ -1018,7 +1018,7 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, */ if (!bacmp(&info->bdaddr, BDADDR_ANY)) { BT_ERR("Ignoring IRK with no identity address"); - smp_distribute_keys(conn, 1); + smp_distribute_keys(conn); return 0; } @@ -1039,7 +1039,7 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, l2cap_conn_update_id_addr(hcon); - smp_distribute_keys(conn, 1); + smp_distribute_keys(conn); return 0; } @@ -1168,7 +1168,7 @@ static void smp_notify_keys(struct l2cap_conn *conn) } } -int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) +int smp_distribute_keys(struct l2cap_conn *conn) { struct smp_cmd_pairing *req, *rsp; struct smp_chan *smp = conn->smp_chan; @@ -1176,7 +1176,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) struct hci_dev *hdev = hcon->hdev; __u8 *keydist; - BT_DBG("conn %p force %d", conn, force); + BT_DBG("conn %p", conn); if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index f32f1212f650..1b8af35b292c 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -145,7 +145,7 @@ struct smp_chan { bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level); int smp_conn_security(struct hci_conn *hcon, __u8 sec_level); int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb); -int smp_distribute_keys(struct l2cap_conn *conn, __u8 force); +int smp_distribute_keys(struct l2cap_conn *conn); int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey); void smp_chan_destroy(struct l2cap_conn *conn); From b1efcc2870687ec3e3c51fa72210b8e4fa465df8 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 26 Feb 2014 20:21:40 -0300 Subject: [PATCH 270/414] Bluetooth: Create hci_req_add_le_scan_disable helper This patch moves stop LE scanning duplicate code to one single place and reuses it. This will avoid more duplicate code in upcoming patches. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_core.c | 14 ++++++++++---- net/bluetooth/mgmt.c | 12 ++---------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 269c8201a362..bef65d0a14f0 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1129,6 +1129,8 @@ void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen, const void *param, u8 event); void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status); +void hci_req_add_le_scan_disable(struct hci_request *req); + struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen, const void *param, u32 timeout); struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 669c76ec659a..9a078cf81d3f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3318,7 +3318,6 @@ static void le_scan_disable_work(struct work_struct *work) { struct hci_dev *hdev = container_of(work, struct hci_dev, le_scan_disable.work); - struct hci_cp_le_set_scan_enable cp; struct hci_request req; int err; @@ -3326,9 +3325,7 @@ static void le_scan_disable_work(struct work_struct *work) hci_req_init(&req, hdev); - memset(&cp, 0, sizeof(cp)); - cp.enable = LE_SCAN_DISABLE; - hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); + hci_req_add_le_scan_disable(&req); err = hci_req_run(&req, le_scan_disable_work_complete); if (err) @@ -4872,3 +4869,12 @@ static void hci_cmd_work(struct work_struct *work) } } } + +void hci_req_add_le_scan_disable(struct hci_request *req) +{ + struct hci_cp_le_set_scan_enable cp; + + memset(&cp, 0, sizeof(cp)); + cp.enable = LE_SCAN_DISABLE; + hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); +} diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d6e269287cfc..cfcaf97c998b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1052,11 +1052,7 @@ static int clean_up_hci_state(struct hci_dev *hdev) disable_advertising(&req); if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) { - struct hci_cp_le_set_scan_enable cp; - - memset(&cp, 0, sizeof(cp)); - cp.enable = LE_SCAN_DISABLE; - hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); + hci_req_add_le_scan_disable(&req); } list_for_each_entry(conn, &hdev->conn_hash.list, list) { @@ -3527,7 +3523,6 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, struct hci_cp_remote_name_req_cancel cp; struct inquiry_entry *e; struct hci_request req; - struct hci_cp_le_set_scan_enable enable_cp; int err; BT_DBG("%s", hdev->name); @@ -3563,10 +3558,7 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, } else { cancel_delayed_work(&hdev->le_scan_disable); - memset(&enable_cp, 0, sizeof(enable_cp)); - enable_cp.enable = LE_SCAN_DISABLE; - hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, - sizeof(enable_cp), &enable_cp); + hci_req_add_le_scan_disable(&req); } break; From 06c053fb54c10be49ef30fc9b6b01e42cc9a1b61 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 26 Feb 2014 20:21:41 -0300 Subject: [PATCH 271/414] Bluetooth: Declare le_conn_failed in hci_core.h This patch adds the "hci_" prefix to le_conn_failed() helper and declares it in hci_core.h so it can be reused in hci_event.c. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_conn.c | 4 ++-- net/bluetooth/hci_event.c | 6 +----- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index bef65d0a14f0..4253bdfc2f81 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -653,6 +653,8 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role); void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active); +void hci_le_conn_failed(struct hci_conn *conn, u8 status); + /* * hci_conn_get() and hci_conn_put() are used to control the life-time of an * "hci_conn" object. They do not guarantee that the hci_conn object is running, diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 3d6b1cf07d23..dc8aad946426 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -515,7 +515,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) EXPORT_SYMBOL(hci_get_route); /* This function requires the caller holds hdev->lock */ -static void le_conn_failed(struct hci_conn *conn, u8 status) +void hci_le_conn_failed(struct hci_conn *conn, u8 status) { struct hci_dev *hdev = conn->hdev; @@ -545,7 +545,7 @@ static void create_le_conn_complete(struct hci_dev *hdev, u8 status) if (!conn) goto done; - le_conn_failed(conn, status); + hci_le_conn_failed(conn, status); done: hci_dev_unlock(hdev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 877cee844b9e..eaa69650b1e5 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3658,11 +3658,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) } if (ev->status) { - mgmt_connect_failed(hdev, &conn->dst, conn->type, - conn->dst_type, ev->status); - hci_proto_connect_cfm(conn, ev->status); - conn->state = BT_CLOSED; - hci_conn_del(conn); + hci_le_conn_failed(conn, ev->status); goto unlock; } From 2acf3d9066b36e1b05db42bfe43152eee07a5e9e Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 26 Feb 2014 20:21:42 -0300 Subject: [PATCH 272/414] Bluetooth: Stop scanning on LE connection Some LE controllers don't support scanning and creating a connection at the same time. So we should always stop scanning in order to establish the connection. Since we may prematurely stop the discovery procedure in favor of the connection establishment, we should also cancel hdev->le_scan_ disable delayed work and set the discovery state to DISCOVERY_STOPPED. This change does a small improvement since it is not mandatory the user stops scanning before connecting anymore. Moreover, this change is required by upcoming LE auto connection mechanism in order to work properly with controllers that don't support background scanning and connection establishment at the same time. In future, we might want to do a small optimization by checking if controller is able to scan and connect at the same time. For now, we want the simplest approach so we always stop scanning (even if the controller is able to carry out both operations). Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_conn.c | 92 ++++++++++++++++++++++++++++++++++++- 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 1bb45a47a78a..c3834d3aecbb 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -356,6 +356,7 @@ enum { /* ---- HCI Error Codes ---- */ #define HCI_ERROR_AUTH_FAILURE 0x05 +#define HCI_ERROR_MEMORY_EXCEEDED 0x07 #define HCI_ERROR_CONNECTION_TIMEOUT 0x08 #define HCI_ERROR_REJ_BAD_ADDR 0x0f #define HCI_ERROR_REMOTE_USER_TERM 0x13 diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index dc8aad946426..2b8bfda3ea35 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -594,12 +594,86 @@ static int hci_create_le_conn(struct hci_conn *conn) return 0; } +static void hci_req_add_le_create_conn(struct hci_request *req, + struct hci_conn *conn) +{ + struct hci_cp_le_create_conn cp; + struct hci_dev *hdev = conn->hdev; + u8 own_addr_type; + + memset(&cp, 0, sizeof(cp)); + + /* Update random address, but set require_privacy to false so + * that we never connect with an unresolvable address. + */ + if (hci_update_random_address(req, false, &own_addr_type)) + return; + + /* Save the address type used for this connnection attempt so we able + * to retrieve this information if we need it. + */ + conn->src_type = own_addr_type; + + cp.scan_interval = cpu_to_le16(hdev->le_scan_interval); + cp.scan_window = cpu_to_le16(hdev->le_scan_window); + bacpy(&cp.peer_addr, &conn->dst); + cp.peer_addr_type = conn->dst_type; + cp.own_address_type = own_addr_type; + cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval); + cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval); + cp.supervision_timeout = __constant_cpu_to_le16(0x002a); + cp.min_ce_len = __constant_cpu_to_le16(0x0000); + cp.max_ce_len = __constant_cpu_to_le16(0x0000); + + hci_req_add(req, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp); +} + +static void stop_scan_complete(struct hci_dev *hdev, u8 status) +{ + struct hci_request req; + struct hci_conn *conn; + int err; + + conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); + if (!conn) + return; + + if (status) { + BT_DBG("HCI request failed to stop scanning: status 0x%2.2x", + status); + + hci_dev_lock(hdev); + hci_le_conn_failed(conn, status); + hci_dev_unlock(hdev); + return; + } + + /* Since we may have prematurely stopped discovery procedure, we should + * update discovery state. + */ + cancel_delayed_work(&hdev->le_scan_disable); + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + + hci_req_init(&req, hdev); + + hci_req_add_le_create_conn(&req, conn); + + err = hci_req_run(&req, create_le_conn_complete); + if (err) { + hci_dev_lock(hdev); + hci_le_conn_failed(conn, HCI_ERROR_MEMORY_EXCEEDED); + hci_dev_unlock(hdev); + return; + } +} + static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, u8 dst_type, u8 sec_level, u8 auth_type) { struct hci_conn_params *params; struct hci_conn *conn; struct smp_irk *irk; + struct hci_request req; int err; if (test_bit(HCI_ADVERTISING, &hdev->flags)) @@ -675,9 +749,23 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, conn->le_conn_max_interval = hdev->le_conn_max_interval; } - err = hci_create_le_conn(conn); - if (err) + hci_req_init(&req, hdev); + + /* If controller is scanning, we stop it since some controllers are + * not able to scan and connect at the same time. + */ + if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) { + hci_req_add_le_scan_disable(&req); + err = hci_req_run(&req, stop_scan_complete); + } else { + hci_req_add_le_create_conn(&req, conn); + err = hci_req_run(&req, create_le_conn_complete); + } + + if (err) { + hci_conn_del(conn); return ERR_PTR(err); + } done: hci_conn_hold(conn); From c99ed8343cdf84279f4d1937d25a3b644a14ed0d Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 26 Feb 2014 20:21:43 -0300 Subject: [PATCH 273/414] Bluetooth: Remove unused function This patch removes hci_create_le_conn() since it is not used anymore. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 43 ---------------------------------------- 1 file changed, 43 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 2b8bfda3ea35..296b8ee42451 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -551,49 +551,6 @@ done: hci_dev_unlock(hdev); } -static int hci_create_le_conn(struct hci_conn *conn) -{ - struct hci_dev *hdev = conn->hdev; - struct hci_cp_le_create_conn cp; - struct hci_request req; - u8 own_addr_type; - int err; - - hci_req_init(&req, hdev); - - memset(&cp, 0, sizeof(cp)); - - /* Update random address, but set require_privacy to false so - * that we never connect with an unresolvable address. - */ - err = hci_update_random_address(&req, false, &own_addr_type); - if (err < 0) - return err; - - conn->src_type = own_addr_type; - - cp.scan_interval = cpu_to_le16(hdev->le_scan_interval); - cp.scan_window = cpu_to_le16(hdev->le_scan_window); - bacpy(&cp.peer_addr, &conn->dst); - cp.peer_addr_type = conn->dst_type; - cp.own_address_type = own_addr_type; - cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval); - cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval); - cp.supervision_timeout = __constant_cpu_to_le16(0x002a); - cp.min_ce_len = __constant_cpu_to_le16(0x0000); - cp.max_ce_len = __constant_cpu_to_le16(0x0000); - - hci_req_add(&req, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp); - - err = hci_req_run(&req, create_le_conn_complete); - if (err) { - hci_conn_del(conn); - return err; - } - - return 0; -} - static void hci_req_add_le_create_conn(struct hci_request *req, struct hci_conn *conn) { From 04a6c5898e8cbb46313b7d425001b701f0fa4e3d Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 26 Feb 2014 20:21:44 -0300 Subject: [PATCH 274/414] Bluetooth: Refactor HCI connection code hci_connect() is a very simple and useless wrapper of hci_connect_acl and hci_connect_le functions. Addtionally, all places where hci_connect is called the link type value is passed explicitly. This way, we can safely delete hci_connect, declare hci_connect_acl and hci_connect_le in hci_core.h and call them directly. No functionality is changed by this patch. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 6 ++++-- net/bluetooth/hci_conn.c | 24 ++++-------------------- net/bluetooth/l2cap_core.c | 7 +++---- net/bluetooth/mgmt.c | 8 ++++---- 4 files changed, 15 insertions(+), 30 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4253bdfc2f81..20bdb2eafeea 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -641,8 +641,10 @@ void hci_chan_del(struct hci_chan *chan); void hci_chan_list_flush(struct hci_conn *conn); struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle); -struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, - __u8 dst_type, __u8 sec_level, __u8 auth_type); +struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, + u8 dst_type, u8 sec_level, u8 auth_type); +struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, + u8 sec_level, u8 auth_type); struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, __u16 setting); int hci_conn_check_link_mode(struct hci_conn *conn); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 296b8ee42451..5c392aaed5a9 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -624,8 +624,8 @@ static void stop_scan_complete(struct hci_dev *hdev, u8 status) } } -static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, - u8 dst_type, u8 sec_level, u8 auth_type) +struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, + u8 dst_type, u8 sec_level, u8 auth_type) { struct hci_conn_params *params; struct hci_conn *conn; @@ -729,8 +729,8 @@ done: return conn; } -static struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, - u8 sec_level, u8 auth_type) +struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, + u8 sec_level, u8 auth_type) { struct hci_conn *acl; @@ -799,22 +799,6 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, return sco; } -/* Create SCO, ACL or LE connection. */ -struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, - __u8 dst_type, __u8 sec_level, __u8 auth_type) -{ - BT_DBG("%s dst %pMR type 0x%x", hdev->name, dst, type); - - switch (type) { - case LE_LINK: - return hci_connect_le(hdev, dst, dst_type, sec_level, auth_type); - case ACL_LINK: - return hci_connect_acl(hdev, dst, sec_level, auth_type); - } - - return ERR_PTR(-EINVAL); -} - /* Check link security requirement */ int hci_conn_check_link_mode(struct hci_conn *conn) { diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d8d990215158..ab5e2bd113ed 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7109,11 +7109,10 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, auth_type = l2cap_get_auth_type(chan); if (bdaddr_type_is_le(dst_type)) - hcon = hci_connect(hdev, LE_LINK, dst, dst_type, - chan->sec_level, auth_type); + hcon = hci_connect_le(hdev, dst, dst_type, chan->sec_level, + auth_type); else - hcon = hci_connect(hdev, ACL_LINK, dst, dst_type, - chan->sec_level, auth_type); + hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index cfcaf97c998b..9fc7c1d9fcbb 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2816,11 +2816,11 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, auth_type = HCI_AT_DEDICATED_BONDING_MITM; if (cp->addr.type == BDADDR_BREDR) - conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, - cp->addr.type, sec_level, auth_type); + conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level, + auth_type); else - conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, - cp->addr.type, sec_level, auth_type); + conn = hci_connect_le(hdev, &cp->addr.bdaddr, cp->addr.type, + sec_level, auth_type); if (IS_ERR(conn)) { int status; From 6f77d8c757523f675679d845ff0e15d3276a168a Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 26 Feb 2014 20:21:45 -0300 Subject: [PATCH 275/414] Bluetooth: Move address type conversion to outside hci_connect_le This patch moves address type conversion (L2CAP address type to HCI address type) to outside hci_connect_le. This way, we avoid back and forth address type conversion in a comming patch. So hci_connect_le() now expects 'dst_type' parameter in HCI address type convention. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 6 ------ net/bluetooth/l2cap_core.c | 12 ++++++++++-- net/bluetooth/mgmt.c | 16 +++++++++++++--- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 5c392aaed5a9..46b27133740f 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -659,12 +659,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, if (conn) return ERR_PTR(-EBUSY); - /* Convert from L2CAP channel address type to HCI address type */ - if (dst_type == BDADDR_LE_PUBLIC) - dst_type = ADDR_LE_DEV_PUBLIC; - else - dst_type = ADDR_LE_DEV_RANDOM; - /* When given an identity address with existing identity * resolving key, the connection needs to be established * to a resolvable random address. diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ab5e2bd113ed..9ed2168fa59f 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7108,11 +7108,19 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, auth_type = l2cap_get_auth_type(chan); - if (bdaddr_type_is_le(dst_type)) + if (bdaddr_type_is_le(dst_type)) { + /* Convert from L2CAP channel address type to HCI address type + */ + if (dst_type == BDADDR_LE_PUBLIC) + dst_type = ADDR_LE_DEV_PUBLIC; + else + dst_type = ADDR_LE_DEV_RANDOM; + hcon = hci_connect_le(hdev, dst, dst_type, chan->sec_level, auth_type); - else + } else { hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type); + } if (IS_ERR(hcon)) { err = PTR_ERR(hcon); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9fc7c1d9fcbb..bad23d5fdd35 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2815,12 +2815,22 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, else auth_type = HCI_AT_DEDICATED_BONDING_MITM; - if (cp->addr.type == BDADDR_BREDR) + if (cp->addr.type == BDADDR_BREDR) { conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level, auth_type); - else - conn = hci_connect_le(hdev, &cp->addr.bdaddr, cp->addr.type, + } else { + u8 addr_type; + + /* Convert from L2CAP channel address type to HCI address type + */ + if (cp->addr.type == BDADDR_LE_PUBLIC) + addr_type = ADDR_LE_DEV_PUBLIC; + else + addr_type = ADDR_LE_DEV_RANDOM; + + conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type, sec_level, auth_type); + } if (IS_ERR(conn)) { int status; From 77a77a30ae893a63467c51e45de18d0bdfa612e4 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 26 Feb 2014 20:21:46 -0300 Subject: [PATCH 276/414] Bluetooth: Introduce hdev->pend_le_conn list This patch introduces the hdev->pend_le_conn list which holds the device addresses the kernel should autonomously connect. It also introduces some helper functions to manipulate the list. The list and helper functions will be used by the next patch which implements the LE auto connection infrastructure. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 7 ++++ net/bluetooth/hci_core.c | 68 ++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 20bdb2eafeea..e08405d02649 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -284,6 +284,7 @@ struct hci_dev { struct list_head identity_resolving_keys; struct list_head remote_oob_data; struct list_head le_conn_params; + struct list_head pend_le_conns; struct hci_dev_stats stat; @@ -799,6 +800,12 @@ void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); void hci_conn_params_clear(struct hci_dev *hdev); +struct bdaddr_list *hci_pend_le_conn_lookup(struct hci_dev *hdev, + bdaddr_t *addr, u8 addr_type); +void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); +void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); +void hci_pend_le_conns_clear(struct hci_dev *hdev); + void hci_uuids_clear(struct hci_dev *hdev); void hci_link_keys_clear(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9a078cf81d3f..142ecd846ccd 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3259,6 +3259,72 @@ void hci_conn_params_clear(struct hci_dev *hdev) BT_DBG("All LE connection parameters were removed"); } +/* This function requires the caller holds hdev->lock */ +struct bdaddr_list *hci_pend_le_conn_lookup(struct hci_dev *hdev, + bdaddr_t *addr, u8 addr_type) +{ + struct bdaddr_list *entry; + + list_for_each_entry(entry, &hdev->pend_le_conns, list) { + if (bacmp(&entry->bdaddr, addr) == 0 && + entry->bdaddr_type == addr_type) + return entry; + } + + return NULL; +} + +/* This function requires the caller holds hdev->lock */ +void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) +{ + struct bdaddr_list *entry; + + entry = hci_pend_le_conn_lookup(hdev, addr, addr_type); + if (entry) + return; + + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) { + BT_ERR("Out of memory"); + return; + } + + bacpy(&entry->bdaddr, addr); + entry->bdaddr_type = addr_type; + + list_add(&entry->list, &hdev->pend_le_conns); + + BT_DBG("addr %pMR (type %u)", addr, addr_type); +} + +/* This function requires the caller holds hdev->lock */ +void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) +{ + struct bdaddr_list *entry; + + entry = hci_pend_le_conn_lookup(hdev, addr, addr_type); + if (!entry) + return; + + list_del(&entry->list); + kfree(entry); + + BT_DBG("addr %pMR (type %u)", addr, addr_type); +} + +/* This function requires the caller holds hdev->lock */ +void hci_pend_le_conns_clear(struct hci_dev *hdev) +{ + struct bdaddr_list *entry, *tmp; + + list_for_each_entry_safe(entry, tmp, &hdev->pend_le_conns, list) { + list_del(&entry->list); + kfree(entry); + } + + BT_DBG("All LE pending connections cleared"); +} + static void inquiry_complete(struct hci_dev *hdev, u8 status) { if (status) { @@ -3441,6 +3507,7 @@ struct hci_dev *hci_alloc_dev(void) INIT_LIST_HEAD(&hdev->identity_resolving_keys); INIT_LIST_HEAD(&hdev->remote_oob_data); INIT_LIST_HEAD(&hdev->le_conn_params); + INIT_LIST_HEAD(&hdev->pend_le_conns); INIT_LIST_HEAD(&hdev->conn_hash.list); INIT_WORK(&hdev->rx_work, hci_rx_work); @@ -3642,6 +3709,7 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_smp_irks_clear(hdev); hci_remote_oob_data_clear(hdev); hci_conn_params_clear(hdev); + hci_pend_le_conns_clear(hdev); hci_dev_unlock(hdev); hci_dev_put(hdev); From a4790dbd43d1617b09d57e96494fde5a4b01980a Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 26 Feb 2014 20:21:47 -0300 Subject: [PATCH 277/414] Bluetooth: Introduce LE auto connection infrastructure This patch introduces the LE auto connection infrastructure which will be used to implement the LE auto connection options. In summary, the auto connection mechanism works as follows: Once the first pending LE connection is created, the background scanning is started. When the target device is found in range, the kernel autonomously starts the connection attempt. If connection is established successfully, that pending LE connection is deleted and the background is stopped. To achieve that, this patch introduces the hci_update_background_scan() which controls the background scanning state. This function starts or stops the background scanning based on the hdev->pend_le_conns list. If there is no pending LE connection, the background scanning is stopped. Otherwise, we start the background scanning. Then, every time a pending LE connection is added we call hci_update_ background_scan() so the background scanning is started (in case it is not already running). Likewise, every time a pending LE connection is deleted we call hci_update_background_scan() so the background scanning is stopped (in case this was the last pending LE connection) or it is started again (in case we have more pending LE connections). Finally, we also call hci_update_background_scan() in hci_le_conn_failed() so the background scan is restarted in case the connection establishment fails. This way the background scanning keeps running until all pending LE connection are established. At this point, resolvable addresses are not support by this infrastructure. The proper support is added in upcoming patches. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 + net/bluetooth/hci_conn.c | 5 ++ net/bluetooth/hci_core.c | 94 +++++++++++++++++++++++++++++++- net/bluetooth/hci_event.c | 38 +++++++++++++ 4 files changed, 137 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e08405d02649..617cf495a449 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -806,6 +806,8 @@ void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); void hci_pend_le_conns_clear(struct hci_dev *hdev); +void hci_update_background_scan(struct hci_dev *hdev); + void hci_uuids_clear(struct hci_dev *hdev); void hci_link_keys_clear(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 46b27133740f..7d6f05e3cae8 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -527,6 +527,11 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status) hci_proto_connect_cfm(conn, status); hci_conn_del(conn); + + /* Since we may have temporarily stopped the background scanning in + * favor of connection establishment, we should restart it. + */ + hci_update_background_scan(hdev); } static void create_le_conn_complete(struct hci_dev *hdev, u8 status) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 142ecd846ccd..9a08f341f0a4 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3281,7 +3281,7 @@ void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) entry = hci_pend_le_conn_lookup(hdev, addr, addr_type); if (entry) - return; + goto done; entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { @@ -3295,6 +3295,9 @@ void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) list_add(&entry->list, &hdev->pend_le_conns); BT_DBG("addr %pMR (type %u)", addr, addr_type); + +done: + hci_update_background_scan(hdev); } /* This function requires the caller holds hdev->lock */ @@ -3304,12 +3307,15 @@ void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) entry = hci_pend_le_conn_lookup(hdev, addr, addr_type); if (!entry) - return; + goto done; list_del(&entry->list); kfree(entry); BT_DBG("addr %pMR (type %u)", addr, addr_type); + +done: + hci_update_background_scan(hdev); } /* This function requires the caller holds hdev->lock */ @@ -4946,3 +4952,87 @@ void hci_req_add_le_scan_disable(struct hci_request *req) cp.enable = LE_SCAN_DISABLE; hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); } + +static void update_background_scan_complete(struct hci_dev *hdev, u8 status) +{ + if (status) + BT_DBG("HCI request failed to update background scanning: " + "status 0x%2.2x", status); +} + +/* This function controls the background scanning based on hdev->pend_le_conns + * list. If there are pending LE connection we start the background scanning, + * otherwise we stop it. + * + * This function requires the caller holds hdev->lock. + */ +void hci_update_background_scan(struct hci_dev *hdev) +{ + struct hci_cp_le_set_scan_param param_cp; + struct hci_cp_le_set_scan_enable enable_cp; + struct hci_request req; + struct hci_conn *conn; + int err; + + hci_req_init(&req, hdev); + + if (list_empty(&hdev->pend_le_conns)) { + /* If there is no pending LE connections, we should stop + * the background scanning. + */ + + /* If controller is not scanning we are done. */ + if (!test_bit(HCI_LE_SCAN, &hdev->dev_flags)) + return; + + hci_req_add_le_scan_disable(&req); + + BT_DBG("%s stopping background scanning", hdev->name); + } else { + u8 own_addr_type; + + /* If there is at least one pending LE connection, we should + * keep the background scan running. + */ + + /* If controller is already scanning we are done. */ + if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) + return; + + /* If controller is connecting, we should not start scanning + * since some controllers are not able to scan and connect at + * the same time. + */ + conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); + if (conn) + return; + + /* Set require_privacy to true to avoid identification from + * unknown peer devices. Since this is passive scanning, no + * SCAN_REQ using the local identity should be sent. Mandating + * privacy is just an extra precaution. + */ + if (hci_update_random_address(&req, true, &own_addr_type)) + return; + + memset(¶m_cp, 0, sizeof(param_cp)); + param_cp.type = LE_SCAN_PASSIVE; + param_cp.interval = cpu_to_le16(hdev->le_scan_interval); + param_cp.window = cpu_to_le16(hdev->le_scan_window); + param_cp.own_address_type = own_addr_type; + hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp), + ¶m_cp); + + memset(&enable_cp, 0, sizeof(enable_cp)); + enable_cp.enable = LE_SCAN_ENABLE; + enable_cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE; + hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp), + &enable_cp); + + BT_DBG("%s starting background scanning", hdev->name); + } + + err = hci_req_run(&req, update_background_scan_complete); + if (err) + BT_ERR("Failed to run HCI request: err %d", err); +} diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index eaa69650b1e5..b6631d7e2ddf 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3677,25 +3677,63 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_proto_connect_cfm(conn, ev->status); + hci_pend_le_conn_del(hdev, &conn->dst, conn->dst_type); + unlock: hci_dev_unlock(hdev); } +/* This function requires the caller holds hdev->lock */ +static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, + u8 addr_type) +{ + struct hci_conn *conn; + + if (!hci_pend_le_conn_lookup(hdev, addr, addr_type)) + return; + + conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, + HCI_AT_NO_BONDING); + if (!IS_ERR(conn)) + return; + + switch (PTR_ERR(conn)) { + case -EBUSY: + /* If hci_connect() returns -EBUSY it means there is already + * an LE connection attempt going on. Since controllers don't + * support more than one connection attempt at the time, we + * don't consider this an error case. + */ + break; + default: + BT_DBG("Failed to connect: err %ld", PTR_ERR(conn)); + } +} + static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb) { u8 num_reports = skb->data[0]; void *ptr = &skb->data[1]; s8 rssi; + hci_dev_lock(hdev); + while (num_reports--) { struct hci_ev_le_advertising_info *ev = ptr; + if (ev->evt_type == LE_ADV_IND || + ev->evt_type == LE_ADV_DIRECT_IND) + check_pending_le_conn(hdev, &ev->bdaddr, + ev->bdaddr_type); + rssi = ev->data[ev->length]; mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type, NULL, rssi, 0, 1, ev->data, ev->length); ptr += sizeof(*ev) + ev->length + 1; } + + hci_dev_unlock(hdev); } static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) From 9fcb18ef3acb51e54b6bca6d2d803676ac86813d Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 26 Feb 2014 20:21:48 -0300 Subject: [PATCH 278/414] Bluetooth: Introduce LE auto connect options This patch introduces the LE auto connection options: HCI_AUTO_CONN_ ALWAYS and HCI_AUTO_CONN_LINK_LOSS. Their working mechanism are described as follows: The HCI_AUTO_CONN_ALWAYS option configures the kernel to always re- establish the connection, no matter the reason the connection was terminated. This feature is required by some LE profiles such as HID over GATT, Health Thermometer and Blood Pressure. These profiles require the host autonomously connect to the device as soon as it enters in connectable mode (start advertising) so the device is able to delivery notifications or indications. The BT_AUTO_CONN_LINK_LOSS option configures the kernel to re- establish the connection in case the connection was terminated due to a link loss. This feature is required by the majority of LE profiles such as Proximity, Find Me, Cycling Speed and Cadence and Time. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 9 ++++++++- net/bluetooth/hci_core.c | 11 +++++++---- net/bluetooth/hci_event.c | 18 ++++++++++++++++++ 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 617cf495a449..b159810f67a6 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -402,6 +402,12 @@ struct hci_conn_params { u16 conn_min_interval; u16 conn_max_interval; + + enum { + HCI_AUTO_CONN_DISABLED, + HCI_AUTO_CONN_ALWAYS, + HCI_AUTO_CONN_LINK_LOSS, + } auto_connect; }; extern struct list_head hci_dev_list; @@ -796,7 +802,8 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, - u16 conn_min_interval, u16 conn_max_interval); + u8 auto_connect, u16 conn_min_interval, + u16 conn_max_interval); void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); void hci_conn_params_clear(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9a08f341f0a4..f4224dc58e4d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3202,7 +3202,8 @@ struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, /* This function requires the caller holds hdev->lock */ void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, - u16 conn_min_interval, u16 conn_max_interval) + u8 auto_connect, u16 conn_min_interval, + u16 conn_max_interval) { struct hci_conn_params *params; @@ -3210,6 +3211,7 @@ void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, if (params) { params->conn_min_interval = conn_min_interval; params->conn_max_interval = conn_max_interval; + params->auto_connect = auto_connect; return; } @@ -3223,12 +3225,13 @@ void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, params->addr_type = addr_type; params->conn_min_interval = conn_min_interval; params->conn_max_interval = conn_max_interval; + params->auto_connect = auto_connect; list_add(¶ms->list, &hdev->le_conn_params); - BT_DBG("addr %pMR (type %u) conn_min_interval 0x%.4x " - "conn_max_interval 0x%.4x", addr, addr_type, conn_min_interval, - conn_max_interval); + BT_DBG("addr %pMR (type %u) auto_connect %u conn_min_interval 0x%.4x " + "conn_max_interval 0x%.4x", addr, addr_type, auto_connect, + conn_min_interval, conn_max_interval); } /* This function requires the caller holds hdev->lock */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index b6631d7e2ddf..46da8b6f4368 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1841,6 +1841,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_disconn_complete *ev = (void *) skb->data; u8 reason = hci_to_mgmt_reason(ev->reason); + struct hci_conn_params *params; struct hci_conn *conn; bool mgmt_connected; u8 type; @@ -1868,6 +1869,23 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) if (conn->type == ACL_LINK && conn->flush_key) hci_remove_link_key(hdev, &conn->dst); + params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); + if (params) { + switch (params->auto_connect) { + case HCI_AUTO_CONN_LINK_LOSS: + if (ev->reason != HCI_ERROR_CONNECTION_TIMEOUT) + break; + /* Fall through */ + + case HCI_AUTO_CONN_ALWAYS: + hci_pend_le_conn_add(hdev, &conn->dst, conn->dst_type); + break; + + default: + break; + } + } + type = conn->type; hci_proto_disconn_cfm(conn, ev->reason); From cef952ce760a1113207b277af65a6ea2644a1b4a Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 26 Feb 2014 20:21:49 -0300 Subject: [PATCH 279/414] Bluetooth: Connection parameters and auto connection This patch modifies hci_conn_params_add() and hci_conn_params_del() so they also add/delete pending LE connections according to the auto_ connect option. This way, background scan is automatically triggered/ untriggered when connection parameters are added/removed. For instance, when a new connection parameters with HCI_AUTO_CONN_ALWAYS option is added and we are not connected to the device, we add a pending LE connection for that device. Likewise, when the connection parameters are updated we add or delete a pending LE connection according to its new auto_connect option. Finally, when the connection parameter is deleted we also delete the pending LE connection (if any). Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 42 +++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f4224dc58e4d..89ff09249eee 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3200,6 +3200,23 @@ struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, return NULL; } +static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type) +{ + struct hci_conn *conn; + + conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr); + if (!conn) + return false; + + if (conn->dst_type != type) + return false; + + if (conn->state != BT_CONNECTED) + return false; + + return true; +} + /* This function requires the caller holds hdev->lock */ void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, u8 auto_connect, u16 conn_min_interval, @@ -3208,12 +3225,8 @@ void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, struct hci_conn_params *params; params = hci_conn_params_lookup(hdev, addr, addr_type); - if (params) { - params->conn_min_interval = conn_min_interval; - params->conn_max_interval = conn_max_interval; - params->auto_connect = auto_connect; - return; - } + if (params) + goto update; params = kzalloc(sizeof(*params), GFP_KERNEL); if (!params) { @@ -3223,11 +3236,24 @@ void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, bacpy(¶ms->addr, addr); params->addr_type = addr_type; + + list_add(¶ms->list, &hdev->le_conn_params); + +update: params->conn_min_interval = conn_min_interval; params->conn_max_interval = conn_max_interval; params->auto_connect = auto_connect; - list_add(¶ms->list, &hdev->le_conn_params); + switch (auto_connect) { + case HCI_AUTO_CONN_DISABLED: + case HCI_AUTO_CONN_LINK_LOSS: + hci_pend_le_conn_del(hdev, addr, addr_type); + break; + case HCI_AUTO_CONN_ALWAYS: + if (!is_connected(hdev, addr, addr_type)) + hci_pend_le_conn_add(hdev, addr, addr_type); + break; + } BT_DBG("addr %pMR (type %u) auto_connect %u conn_min_interval 0x%.4x " "conn_max_interval 0x%.4x", addr, addr_type, auto_connect, @@ -3243,6 +3269,8 @@ void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) if (!params) return; + hci_pend_le_conn_del(hdev, addr, addr_type); + list_del(¶ms->list); kfree(params); From c54c3860e3dbaa68128dbb288b2806dd86c230cc Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 26 Feb 2014 20:21:50 -0300 Subject: [PATCH 280/414] Bluetooth: Temporarily stop background scanning on discovery If the user sends a mgmt start discovery command while the background scanning is running, we should temporarily stop it. Once the discovery finishes, we start the background scanning again. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 2 ++ net/bluetooth/mgmt.c | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 89ff09249eee..507a137a584b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1786,6 +1786,8 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) switch (state) { case DISCOVERY_STOPPED: + hci_update_background_scan(hdev); + if (hdev->discovery.state != DISCOVERY_STARTING) mgmt_discovering(hdev, 0); break; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bad23d5fdd35..a62e22ca73a1 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3439,12 +3439,12 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, goto failed; } - if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) { - err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, - MGMT_STATUS_BUSY); - mgmt_pending_remove(cmd); - goto failed; - } + /* If controller is scanning, it means the background scanning + * is running. Thus, we should temporarily stop it in order to + * set the discovery scanning parameters. + */ + if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) + hci_req_add_le_scan_disable(&req); memset(¶m_cp, 0, sizeof(param_cp)); From 6046dc3e0602256b9941241dfd6b2e4824999b01 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 26 Feb 2014 20:21:51 -0300 Subject: [PATCH 281/414] Bluetooth: Auto connection and power on When hdev is closed (e.g. Mgmt power off command, RFKILL or controller is reset), the ongoing active connections are silently dropped by the controller (no Disconnection Complete Event is sent to host). For that reason, the devices that require HCI_AUTO_CONN_ALWAYS are not added to hdev->pend_le_conns list and they won't auto connect. So to fix this issue, during hdev closing, we remove all pending LE connections. After adapter is powered on, we add a pending LE connection for each HCI_AUTO_CONN_ALWAYS address. This way, the auto connection mechanism works propely after a power off and power on sequence as well as RFKILL block/unblock. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 1 + net/bluetooth/mgmt.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 507a137a584b..9470a9c14324 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2266,6 +2266,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) hci_dev_lock(hdev); hci_inquiry_cache_flush(hdev); hci_conn_hash_flush(hdev); + hci_pend_le_conns_clear(hdev); hci_dev_unlock(hdev); hci_notify(hdev, HCI_DEV_DOWN); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a62e22ca73a1..f878267ba6ab 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4669,6 +4669,17 @@ void mgmt_index_removed(struct hci_dev *hdev) mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL); } +/* This function requires the caller holds hdev->lock */ +static void restart_le_auto_conns(struct hci_dev *hdev) +{ + struct hci_conn_params *p; + + list_for_each_entry(p, &hdev->le_conn_params, list) { + if (p->auto_connect == HCI_AUTO_CONN_ALWAYS) + hci_pend_le_conn_add(hdev, &p->addr, p->addr_type); + } +} + static void powered_complete(struct hci_dev *hdev, u8 status) { struct cmd_lookup match = { NULL, hdev }; @@ -4677,6 +4688,8 @@ static void powered_complete(struct hci_dev *hdev, u8 status) hci_dev_lock(hdev); + restart_le_auto_conns(hdev); + mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); new_settings(hdev, match.sk); From a9b0a04c2aac1e6e41e254221926bdce75321f55 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 26 Feb 2014 20:21:52 -0300 Subject: [PATCH 282/414] Bluetooth: Connection parameters and resolvable address We should only accept connection parameters from identity addresses (public or random static). Thus, we should check the address type in hci_conn_params_add(). Additionally, since the IRK is removed during unpair, we should also remove the connection parameters from that device. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 6 +++--- net/bluetooth/hci_core.c | 25 +++++++++++++++++++++---- net/bluetooth/mgmt.c | 2 ++ 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b159810f67a6..4b192d0fa76e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -801,9 +801,9 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); -void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, - u8 auto_connect, u16 conn_min_interval, - u16 conn_max_interval); +int hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, + u8 auto_connect, u16 conn_min_interval, + u16 conn_max_interval); void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); void hci_conn_params_clear(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9470a9c14324..6d83ca040970 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3220,13 +3220,28 @@ static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type) return true; } +static bool is_identity_address(bdaddr_t *addr, u8 addr_type) +{ + if (addr_type == ADDR_LE_DEV_PUBLIC) + return true; + + /* Check for Random Static address type */ + if ((addr->b[5] & 0xc0) == 0xc0) + return true; + + return false; +} + /* This function requires the caller holds hdev->lock */ -void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, - u8 auto_connect, u16 conn_min_interval, - u16 conn_max_interval) +int hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, + u8 auto_connect, u16 conn_min_interval, + u16 conn_max_interval) { struct hci_conn_params *params; + if (!is_identity_address(addr, addr_type)) + return -EINVAL; + params = hci_conn_params_lookup(hdev, addr, addr_type); if (params) goto update; @@ -3234,7 +3249,7 @@ void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, params = kzalloc(sizeof(*params), GFP_KERNEL); if (!params) { BT_ERR("Out of memory"); - return; + return -ENOMEM; } bacpy(¶ms->addr, addr); @@ -3261,6 +3276,8 @@ update: BT_DBG("addr %pMR (type %u) auto_connect %u conn_min_interval 0x%.4x " "conn_max_interval 0x%.4x", addr, addr_type, auto_connect, conn_min_interval, conn_max_interval); + + return 0; } /* This function requires the caller holds hdev->lock */ diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f878267ba6ab..2e6564e47ded 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2416,6 +2416,8 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type); + hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type); + err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type); } From 5b906a84a5b3458d810a9faab74783525f4a84d7 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 26 Feb 2014 20:21:53 -0300 Subject: [PATCH 283/414] Bluetooth: Support resolvable private addresses Only identity addresses are inserted into hdev->pend_le_conns. So, in order to support resolvable private addresses in auto connection mechanism, we should resolve the address before checking for pending connections. Thus, this patch adds an extra check in check_pending_le_conn() and updates 'addr' and 'addr_type' variables before hci_pend_le_conn_ lookup(). Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 46da8b6f4368..cda92db2a9fc 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3706,6 +3706,16 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) { struct hci_conn *conn; + struct smp_irk *irk; + + /* If this is a resolvable address, we should resolve it and then + * update address and address type variables. + */ + irk = hci_get_irk(hdev, addr, addr_type); + if (irk) { + addr = &irk->bdaddr; + addr_type = irk->addr_type; + } if (!hci_pend_le_conn_lookup(hdev, addr, addr_type)) return; From 7d474e06ef8ee3941a4a0dcb824b8e3006f25d3e Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 26 Feb 2014 20:21:54 -0300 Subject: [PATCH 284/414] Bluetooth: Add le_auto_conn file on debugfs This patch adds to debugfs the le_auto_conn file. This file will be used to test LE auto connection infrastructure. This file accept writes in the following format: "add
[auto_connect]" "del
" "clr" The
values are: * 0 for public address * 1 for random address The [auto_connect] values are (for more details see struct hci_ conn_params): * 0 for disabled (default) * 1 for always * 2 for link loss So for instance, if you want the kernel autonomously establishes connections with device AA:BB:CC:DD:EE:FF (public address) every time the device enters in connectable mode (starts advertising), you should run the command: $ echo "add AA:BB:CC:DD:EE:FF 0 1" > /sys/kernel/debug/bluetooth/hci0/le_auto_conn To delete the connection parameters for that device, run the command: $ echo "del AA:BB:CC:DD:EE:FF 0" > /sys/kernel/debug/bluetooth/hci0/le_auto_conn To clear the connection parameters list, run the command: $ echo "clr" > /sys/kernel/debug/bluetooth/hci0/le_auto_conn Finally. to get the list of connection parameters configured in kernel, read the le_auto_conn file: $ cat /sys/kernel/debug/bluetooth/hci0/le_auto_conn This file is created only if LE is enabled. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 111 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 6d83ca040970..0b96f20238d8 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -896,6 +896,115 @@ static const struct file_operations lowpan_debugfs_fops = { .llseek = default_llseek, }; +static int le_auto_conn_show(struct seq_file *sf, void *ptr) +{ + struct hci_dev *hdev = sf->private; + struct hci_conn_params *p; + + hci_dev_lock(hdev); + + list_for_each_entry(p, &hdev->le_conn_params, list) { + seq_printf(sf, "%pMR %u %u\n", &p->addr, p->addr_type, + p->auto_connect); + } + + hci_dev_unlock(hdev); + + return 0; +} + +static int le_auto_conn_open(struct inode *inode, struct file *file) +{ + return single_open(file, le_auto_conn_show, inode->i_private); +} + +static ssize_t le_auto_conn_write(struct file *file, const char __user *data, + size_t count, loff_t *offset) +{ + struct seq_file *sf = file->private_data; + struct hci_dev *hdev = sf->private; + u8 auto_connect = 0; + bdaddr_t addr; + u8 addr_type; + char *buf; + int err = 0; + int n; + + /* Don't allow partial write */ + if (*offset != 0) + return -EINVAL; + + if (count < 3) + return -EINVAL; + + buf = kzalloc(count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, data, count)) { + err = -EFAULT; + goto done; + } + + if (memcmp(buf, "add", 3) == 0) { + n = sscanf(&buf[4], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu %hhu", + &addr.b[5], &addr.b[4], &addr.b[3], &addr.b[2], + &addr.b[1], &addr.b[0], &addr_type, + &auto_connect); + + if (n < 7) { + err = -EINVAL; + goto done; + } + + hci_dev_lock(hdev); + err = hci_conn_params_add(hdev, &addr, addr_type, auto_connect, + hdev->le_conn_min_interval, + hdev->le_conn_max_interval); + hci_dev_unlock(hdev); + + if (err) + goto done; + } else if (memcmp(buf, "del", 3) == 0) { + n = sscanf(&buf[4], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu", + &addr.b[5], &addr.b[4], &addr.b[3], &addr.b[2], + &addr.b[1], &addr.b[0], &addr_type); + + if (n < 7) { + err = -EINVAL; + goto done; + } + + hci_dev_lock(hdev); + hci_conn_params_del(hdev, &addr, addr_type); + hci_dev_unlock(hdev); + } else if (memcmp(buf, "clr", 3) == 0) { + hci_dev_lock(hdev); + hci_conn_params_clear(hdev); + hci_pend_le_conns_clear(hdev); + hci_update_background_scan(hdev); + hci_dev_unlock(hdev); + } else { + err = -EINVAL; + } + +done: + kfree(buf); + + if (err) + return err; + else + return count; +} + +static const struct file_operations le_auto_conn_fops = { + .open = le_auto_conn_open, + .read = seq_read, + .write = le_auto_conn_write, + .llseek = seq_lseek, + .release = single_release, +}; + /* ---- HCI requests ---- */ static void hci_req_sync_complete(struct hci_dev *hdev, u8 result) @@ -1694,6 +1803,8 @@ static int __hci_init(struct hci_dev *hdev) hdev, &adv_channel_map_fops); debugfs_create_file("6lowpan", 0644, hdev->debugfs, hdev, &lowpan_debugfs_fops); + debugfs_create_file("le_auto_conn", 0644, hdev->debugfs, hdev, + &le_auto_conn_fops); } return 0; From 8ef30fd3d1f08f9ffdf2495907f50f44f2101cd3 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 26 Feb 2014 20:21:55 -0300 Subject: [PATCH 285/414] Bluetooth: Create hci_req_add_le_passive_scan helper This patches creates the public hci_req_add_le_passive_scan helper so it can be re-used outside hci_core.c in the next patch. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 56 ++++++++++++++++++-------------- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4b192d0fa76e..79a75edc62d0 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1150,6 +1150,7 @@ void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen, void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status); void hci_req_add_le_scan_disable(struct hci_request *req); +void hci_req_add_le_passive_scan(struct hci_request *req); struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen, const void *param, u32 timeout); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 0b96f20238d8..bbd085d32d78 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -5115,6 +5115,36 @@ void hci_req_add_le_scan_disable(struct hci_request *req) hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); } +void hci_req_add_le_passive_scan(struct hci_request *req) +{ + struct hci_cp_le_set_scan_param param_cp; + struct hci_cp_le_set_scan_enable enable_cp; + struct hci_dev *hdev = req->hdev; + u8 own_addr_type; + + /* Set require_privacy to true to avoid identification from + * unknown peer devices. Since this is passive scanning, no + * SCAN_REQ using the local identity should be sent. Mandating + * privacy is just an extra precaution. + */ + if (hci_update_random_address(req, true, &own_addr_type)) + return; + + memset(¶m_cp, 0, sizeof(param_cp)); + param_cp.type = LE_SCAN_PASSIVE; + param_cp.interval = cpu_to_le16(hdev->le_scan_interval); + param_cp.window = cpu_to_le16(hdev->le_scan_window); + param_cp.own_address_type = own_addr_type; + hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp), + ¶m_cp); + + memset(&enable_cp, 0, sizeof(enable_cp)); + enable_cp.enable = LE_SCAN_ENABLE; + enable_cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE; + hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp), + &enable_cp); +} + static void update_background_scan_complete(struct hci_dev *hdev, u8 status) { if (status) @@ -5130,8 +5160,6 @@ static void update_background_scan_complete(struct hci_dev *hdev, u8 status) */ void hci_update_background_scan(struct hci_dev *hdev) { - struct hci_cp_le_set_scan_param param_cp; - struct hci_cp_le_set_scan_enable enable_cp; struct hci_request req; struct hci_conn *conn; int err; @@ -5151,8 +5179,6 @@ void hci_update_background_scan(struct hci_dev *hdev) BT_DBG("%s stopping background scanning", hdev->name); } else { - u8 own_addr_type; - /* If there is at least one pending LE connection, we should * keep the background scan running. */ @@ -5169,27 +5195,7 @@ void hci_update_background_scan(struct hci_dev *hdev) if (conn) return; - /* Set require_privacy to true to avoid identification from - * unknown peer devices. Since this is passive scanning, no - * SCAN_REQ using the local identity should be sent. Mandating - * privacy is just an extra precaution. - */ - if (hci_update_random_address(&req, true, &own_addr_type)) - return; - - memset(¶m_cp, 0, sizeof(param_cp)); - param_cp.type = LE_SCAN_PASSIVE; - param_cp.interval = cpu_to_le16(hdev->le_scan_interval); - param_cp.window = cpu_to_le16(hdev->le_scan_window); - param_cp.own_address_type = own_addr_type; - hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp), - ¶m_cp); - - memset(&enable_cp, 0, sizeof(enable_cp)); - enable_cp.enable = LE_SCAN_ENABLE; - enable_cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE; - hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp), - &enable_cp); + hci_req_add_le_passive_scan(&req); BT_DBG("%s starting background scanning", hdev->name); } From dd2ef8e274b265a0af1cc0d3ddafd361fc3a00a6 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 26 Feb 2014 20:21:56 -0300 Subject: [PATCH 286/414] Bluetooth: Update background scan parameters If new scanning parameters are set while background scan is running, we should restart background scanning so these parameters are updated. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 2e6564e47ded..4c4912e9a7c4 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3924,6 +3924,21 @@ static int set_scan_params(struct sock *sk, struct hci_dev *hdev, err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0); + /* If background scan is running, restart it so new parameters are + * loaded. + */ + if (test_bit(HCI_LE_SCAN, &hdev->dev_flags) && + hdev->discovery.state == DISCOVERY_STOPPED) { + struct hci_request req; + + hci_req_init(&req, hdev); + + hci_req_add_le_scan_disable(&req); + hci_req_add_le_passive_scan(&req); + + hci_req_run(&req, NULL); + } + hci_dev_unlock(hdev); return err; From d3a2541d83dbdb4dd35eb34ac45b036acde278c6 Mon Sep 17 00:00:00 2001 From: Lukasz Rymanowski Date: Thu, 27 Feb 2014 16:47:28 +0100 Subject: [PATCH 287/414] Bluetooth: Fix response on confirm_name According to mgmt-api.txt, in case of confirm name command, cmd_complete should be always use as a response. Not command status as it is now for failures. Using command complete on failure is actually better as client might be interested in device address for which confirm name failed. Signed-off-by: Lukasz Rymanowski Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4c4912e9a7c4..78ac7c864044 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3627,15 +3627,17 @@ static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data, hci_dev_lock(hdev); if (!hci_discovery_active(hdev)) { - err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME, - MGMT_STATUS_FAILED); + err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, + MGMT_STATUS_FAILED, &cp->addr, + sizeof(cp->addr)); goto failed; } e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr); if (!e) { - err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME, - MGMT_STATUS_INVALID_PARAMS); + err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, + MGMT_STATUS_INVALID_PARAMS, &cp->addr, + sizeof(cp->addr)); goto failed; } From 56ed2cb88c7370d5aa88c92a2a0b1cb92c0979b9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 27 Feb 2014 14:05:40 +0200 Subject: [PATCH 288/414] Bluetooth: Add tracking of advertising address type To know the real source address for incoming connections (needed e.g. for SMP) we should store the own_address_type parameter that was used for the last HCI_LE_Write_Advertising_Parameters command. This patch adds a proper command complete handler for the command and stores the address type in a new adv_addr_type variable in the hci_dev struct. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_event.c | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 79a75edc62d0..853376df4f99 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -156,6 +156,7 @@ struct hci_dev { bdaddr_t bdaddr; bdaddr_t random_addr; bdaddr_t static_addr; + __u8 adv_addr_type; __u8 dev_name[HCI_MAX_NAME_LENGTH]; __u8 short_name[HCI_MAX_SHORT_NAME_LENGTH]; __u8 eir[HCI_MAX_EIR_LENGTH]; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index cda92db2a9fc..f26e91f72930 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1078,6 +1078,25 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev, } } +static void hci_cc_set_adv_param(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_cp_le_set_adv_param *cp; + u8 status = *((u8 *) skb->data); + + BT_DBG("%s status 0x%2.2x", hdev->name, status); + + if (status) + return; + + cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_PARAM); + if (!cp) + return; + + hci_dev_lock(hdev); + hdev->adv_addr_type = cp->own_address_type; + hci_dev_unlock(hdev); +} + static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev, struct sk_buff *skb) { @@ -2367,6 +2386,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_cc_write_le_host_supported(hdev, skb); break; + case HCI_OP_LE_SET_ADV_PARAM: + hci_cc_set_adv_param(hdev, skb); + break; + case HCI_OP_WRITE_REMOTE_AMP_ASSOC: hci_cc_write_remote_amp_assoc(hdev, skb); break; From a1f4c3188bb4d51a41d2026ee08a578f56c61e47 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 27 Feb 2014 14:05:41 +0200 Subject: [PATCH 289/414] Bluetooth: Add hci_copy_identity_address convenience function The number of places needing the local Identity Address are starting to grow so it's better to have a single place for the logic of determining it. This patch adds a convenience function for getting the Identity Address and updates the two current places needing this to use it. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_core.c | 35 +++++++++++++++++++++++--------- net/bluetooth/hci_event.c | 17 +--------------- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 853376df4f99..093d05eeb3fa 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1292,6 +1292,8 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], int hci_update_random_address(struct hci_request *req, bool require_privacy, u8 *own_addr_type); +void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 *bdaddr_type); #define SCO_AIRMODE_MASK 0x0003 #define SCO_AIRMODE_CVSD 0x0000 diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index bbd085d32d78..7113d4cc085f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -582,21 +582,14 @@ DEFINE_SIMPLE_ATTRIBUTE(sniff_max_interval_fops, sniff_max_interval_get, static int identity_show(struct seq_file *f, void *p) { struct hci_dev *hdev = f->private; - bdaddr_t *addr; + bdaddr_t addr; u8 addr_type; hci_dev_lock(hdev); - if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags) || - !bacmp(&hdev->bdaddr, BDADDR_ANY)) { - addr = &hdev->static_addr; - addr_type = ADDR_LE_DEV_RANDOM; - } else { - addr = &hdev->bdaddr; - addr_type = ADDR_LE_DEV_PUBLIC; - } + hci_copy_identity_address(hdev, &addr, &addr_type); - seq_printf(f, "%pMR (type %u) %*phN %pMR\n", addr, addr_type, + seq_printf(f, "%pMR (type %u) %*phN %pMR\n", &addr, addr_type, 16, hdev->irk, &hdev->rpa); hci_dev_unlock(hdev); @@ -3636,6 +3629,28 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy, return 0; } +/* Copy the Identity Address of the controller. + * + * If the controller has a public BD_ADDR, then by default use that one. + * If this is a LE only controller without a public address, default to + * the static random address. + * + * For debugging purposes it is possible to force controllers with a + * public address to use the static random address instead. + */ +void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 *bdaddr_type) +{ + if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags) || + !bacmp(&hdev->bdaddr, BDADDR_ANY)) { + bacpy(bdaddr, &hdev->static_addr); + *bdaddr_type = ADDR_LE_DEV_RANDOM; + } else { + bacpy(bdaddr, &hdev->bdaddr); + *bdaddr_type = ADDR_LE_DEV_PUBLIC; + } +} + /* Alloc HCI device */ struct hci_dev *hci_alloc_dev(void) { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f26e91f72930..162235633bf5 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3665,23 +3665,8 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) /* Ensure that the hci_conn contains the identity address type * regardless of which address the connection was made with. - * - * If the controller has a public BD_ADDR, then by default - * use that one. If this is a LE only controller without - * a public address, default to the static random address. - * - * For debugging purposes it is possible to force - * controllers with a public address to use the static - * random address instead. */ - if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags) || - !bacmp(&hdev->bdaddr, BDADDR_ANY)) { - bacpy(&conn->src, &hdev->static_addr); - conn->src_type = ADDR_LE_DEV_RANDOM; - } else { - bacpy(&conn->src, &hdev->bdaddr); - conn->src_type = ADDR_LE_DEV_PUBLIC; - } + hci_copy_identity_address(hdev, &conn->src, &conn->src_type); /* Lookup the identity address from the stored connection * address and address type. From c9507490ab1769a808fcb4af1a27bd738f4b0407 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 27 Feb 2014 19:35:54 -0800 Subject: [PATCH 290/414] Bluetooth: Make hci_blacklist_clear function static The hci_blacklist_clear function is not used outside of hci_core.c and can be made static. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_core.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 093d05eeb3fa..9493da8f7d83 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -796,7 +796,6 @@ int hci_inquiry(void __user *arg); struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); -void hci_blacklist_clear(struct hci_dev *hdev); int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 7113d4cc085f..75cf447ca000 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3238,7 +3238,7 @@ struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, return NULL; } -void hci_blacklist_clear(struct hci_dev *hdev) +static void hci_blacklist_clear(struct hci_dev *hdev) { struct list_head *p, *n; From d9a7b0a53f898176b31f6a560e487880a2353136 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 27 Feb 2014 20:37:28 -0800 Subject: [PATCH 291/414] Bluetooth: Add definitions for LE white list HCI commands Add the definitions for clearing the LE white list, adding entries to the LE white list and removing entries from the LE white list. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index c3834d3aecbb..bb3f4926d4e3 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1205,6 +1205,20 @@ struct hci_rp_le_read_white_list_size { __u8 size; } __packed; +#define HCI_OP_LE_CLEAR_WHITE_LIST 0x2010 + +#define HCI_OP_LE_ADD_TO_WHITE_LIST 0x2011 +struct hci_cp_le_add_to_white_list { + __u8 bdaddr_type; + bdaddr_t bdaddr; +} __packed; + +#define HCI_OP_LE_DEL_FROM_WHITE_LIST 0x2012 +struct hci_cp_le_del_from_white_list { + __u8 bdaddr_type; + bdaddr_t bdaddr; +} __packed; + #define HCI_OP_LE_CONN_UPDATE 0x2013 struct hci_cp_le_conn_update { __le16 handle; From 747d3f030190e58373849839c7757d3d58208b03 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 27 Feb 2014 20:37:29 -0800 Subject: [PATCH 292/414] Bluetooth: Clear all LE white list entries when powering controller When starting up a controller make sure that all LE white list entries are cleared. Normally the HCI Reset takes care of this. This is just in case no HCI Reset has been executed. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 75cf447ca000..ab547277f909 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1346,14 +1346,17 @@ static void le_setup(struct hci_request *req) /* Read LE Local Supported Features */ hci_req_add(req, HCI_OP_LE_READ_LOCAL_FEATURES, 0, NULL); + /* Read LE Supported States */ + hci_req_add(req, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL); + /* Read LE Advertising Channel TX Power */ hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL); /* Read LE White List Size */ hci_req_add(req, HCI_OP_LE_READ_WHITE_LIST_SIZE, 0, NULL); - /* Read LE Supported States */ - hci_req_add(req, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL); + /* Clear LE White List */ + hci_req_add(req, HCI_OP_LE_CLEAR_WHITE_LIST, 0, NULL); /* LE-only controllers have LE implicitly enabled */ if (!lmp_bredr_capable(hdev)) From d2ab0ac18df8735fb1431e63446e803dcd2e7326 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 27 Feb 2014 20:37:30 -0800 Subject: [PATCH 293/414] Bluetooth: Add support for storing LE white list entries The current LE white list entries require storing in the HCI controller structure. So provide a storage and access functions for it. In addition export the current list via debugfs. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 7 +++ net/bluetooth/hci_core.c | 90 ++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9493da8f7d83..571168811ecd 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -284,6 +284,7 @@ struct hci_dev { struct list_head long_term_keys; struct list_head identity_resolving_keys; struct list_head remote_oob_data; + struct list_head le_white_list; struct list_head le_conn_params; struct list_head pend_le_conns; @@ -799,6 +800,12 @@ struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); +struct bdaddr_list *hci_white_list_lookup(struct hci_dev *hdev, + bdaddr_t *bdaddr, u8 type); +void hci_white_list_clear(struct hci_dev *hdev); +int hci_white_list_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); +int hci_white_list_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); + struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); int hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index ab547277f909..a9ff1cbe2c41 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -702,6 +702,31 @@ static const struct file_operations force_static_address_fops = { .llseek = default_llseek, }; +static int white_list_show(struct seq_file *f, void *ptr) +{ + struct hci_dev *hdev = f->private; + struct bdaddr_list *b; + + hci_dev_lock(hdev); + list_for_each_entry(b, &hdev->le_white_list, list) + seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type); + hci_dev_unlock(hdev); + + return 0; +} + +static int white_list_open(struct inode *inode, struct file *file) +{ + return single_open(file, white_list_show, inode->i_private); +} + +static const struct file_operations white_list_fops = { + .open = white_list_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int identity_resolving_keys_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; @@ -1786,6 +1811,8 @@ static int __hci_init(struct hci_dev *hdev) debugfs_create_u8("white_list_size", 0444, hdev->debugfs, &hdev->le_white_list_size); + debugfs_create_file("white_list", 0444, hdev->debugfs, hdev, + &white_list_fops); debugfs_create_file("identity_resolving_keys", 0400, hdev->debugfs, hdev, &identity_resolving_keys_fops); @@ -3294,6 +3321,67 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) return mgmt_device_unblocked(hdev, bdaddr, type); } +struct bdaddr_list *hci_white_list_lookup(struct hci_dev *hdev, + bdaddr_t *bdaddr, u8 type) +{ + struct bdaddr_list *b; + + list_for_each_entry(b, &hdev->le_white_list, list) { + if (!bacmp(&b->bdaddr, bdaddr) && b->bdaddr_type == type) + return b; + } + + return NULL; +} + +void hci_white_list_clear(struct hci_dev *hdev) +{ + struct list_head *p, *n; + + list_for_each_safe(p, n, &hdev->le_white_list) { + struct bdaddr_list *b = list_entry(p, struct bdaddr_list, list); + + list_del(p); + kfree(b); + } +} + +int hci_white_list_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) +{ + struct bdaddr_list *entry; + + if (!bacmp(bdaddr, BDADDR_ANY)) + return -EBADF; + + entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + bacpy(&entry->bdaddr, bdaddr); + entry->bdaddr_type = type; + + list_add(&entry->list, &hdev->le_white_list); + + return 0; +} + +int hci_white_list_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) +{ + struct bdaddr_list *entry; + + if (!bacmp(bdaddr, BDADDR_ANY)) + return -EBADF; + + entry = hci_white_list_lookup(hdev, bdaddr, type); + if (!entry) + return -ENOENT; + + list_del(&entry->list); + kfree(entry); + + return 0; +} + /* This function requires the caller holds hdev->lock */ struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) @@ -3692,6 +3780,7 @@ struct hci_dev *hci_alloc_dev(void) INIT_LIST_HEAD(&hdev->long_term_keys); INIT_LIST_HEAD(&hdev->identity_resolving_keys); INIT_LIST_HEAD(&hdev->remote_oob_data); + INIT_LIST_HEAD(&hdev->le_white_list); INIT_LIST_HEAD(&hdev->le_conn_params); INIT_LIST_HEAD(&hdev->pend_le_conns); INIT_LIST_HEAD(&hdev->conn_hash.list); @@ -3894,6 +3983,7 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_smp_ltks_clear(hdev); hci_smp_irks_clear(hdev); hci_remote_oob_data_clear(hdev); + hci_white_list_clear(hdev); hci_conn_params_clear(hdev); hci_pend_le_conns_clear(hdev); hci_dev_unlock(hdev); From 0f36b589e4eea0a0a27349992def2ea7beb45182 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 27 Feb 2014 20:37:31 -0800 Subject: [PATCH 294/414] Bluetooth: Track LE white list modification via HCI commands When the LE white list gets changed via HCI commands make sure that the internal storage of the white list entries gets updated. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 55 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 162235633bf5..674bfdc3ecc3 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1038,6 +1038,49 @@ static void hci_cc_le_read_white_list_size(struct hci_dev *hdev, hdev->le_white_list_size = rp->size; } +static void hci_cc_le_clear_white_list(struct hci_dev *hdev, + struct sk_buff *skb) +{ + __u8 status = *((__u8 *) skb->data); + + BT_DBG("%s status 0x%2.2x", hdev->name, status); + + if (!status) + hci_white_list_clear(hdev); +} + +static void hci_cc_le_add_to_white_list(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_cp_le_add_to_white_list *sent; + __u8 status = *((__u8 *) skb->data); + + BT_DBG("%s status 0x%2.2x", hdev->name, status); + + sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_WHITE_LIST); + if (!sent) + return; + + if (!status) + hci_white_list_add(hdev, &sent->bdaddr, sent->bdaddr_type); +} + +static void hci_cc_le_del_from_white_list(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_cp_le_del_from_white_list *sent; + __u8 status = *((__u8 *) skb->data); + + BT_DBG("%s status 0x%2.2x", hdev->name, status); + + sent = hci_sent_cmd_data(hdev, HCI_OP_LE_DEL_FROM_WHITE_LIST); + if (!sent) + return; + + if (!status) + hci_white_list_del(hdev, &sent->bdaddr, sent->bdaddr_type); +} + static void hci_cc_le_read_supported_states(struct hci_dev *hdev, struct sk_buff *skb) { @@ -2378,6 +2421,18 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_cc_le_read_white_list_size(hdev, skb); break; + case HCI_OP_LE_CLEAR_WHITE_LIST: + hci_cc_le_clear_white_list(hdev, skb); + break; + + case HCI_OP_LE_ADD_TO_WHITE_LIST: + hci_cc_le_add_to_white_list(hdev, skb); + break; + + case HCI_OP_LE_DEL_FROM_WHITE_LIST: + hci_cc_le_del_from_white_list(hdev, skb); + break; + case HCI_OP_LE_READ_SUPPORTED_STATES: hci_cc_le_read_supported_states(hdev, skb); break; From c9910d0fb4fc2ede468b26d45a1d50c309897770 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 27 Feb 2014 14:35:12 +0200 Subject: [PATCH 295/414] Bluetooth: Fix disconnecting connections in non-connected states When powering off and disconnecting devices we should also consider connections which have not yet reached the BT_CONNECTED state. They may not have a valid handle yet and simply sending a HCI_Disconnect will not work. This patch updates the code to either disconnect, cancel connection creation or reject incoming connection creation based on the current conn->state value as well as the link type in question. When the power off procedure results in canceling connection attempts instead of disconnecting connections we get a connection failed event instead of a disconnection event. Therefore, we also need to have extra code in the mgmt_connect_failed function to check if we should proceed with the power off or not. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 78ac7c864044..73b6ff817796 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1057,10 +1057,34 @@ static int clean_up_hci_state(struct hci_dev *hdev) list_for_each_entry(conn, &hdev->conn_hash.list, list) { struct hci_cp_disconnect dc; + struct hci_cp_reject_conn_req rej; - dc.handle = cpu_to_le16(conn->handle); - dc.reason = 0x15; /* Terminated due to Power Off */ - hci_req_add(&req, HCI_OP_DISCONNECT, sizeof(dc), &dc); + switch (conn->state) { + case BT_CONNECTED: + case BT_CONFIG: + dc.handle = cpu_to_le16(conn->handle); + dc.reason = 0x15; /* Terminated due to Power Off */ + hci_req_add(&req, HCI_OP_DISCONNECT, sizeof(dc), &dc); + break; + case BT_CONNECT: + if (conn->type == LE_LINK) + hci_req_add(&req, HCI_OP_LE_CREATE_CONN_CANCEL, + 0, NULL); + else if (conn->type == ACL_LINK) + hci_req_add(&req, HCI_OP_CREATE_CONN_CANCEL, + 6, &conn->dst); + break; + case BT_CONNECT2: + bacpy(&rej.bdaddr, &conn->dst); + rej.reason = 0x15; /* Terminated due to Power Off */ + if (conn->type == ACL_LINK) + hci_req_add(&req, HCI_OP_REJECT_CONN_REQ, + sizeof(rej), &rej); + else if (conn->type == SCO_LINK) + hci_req_add(&req, HCI_OP_REJECT_SYNC_CONN_REQ, + sizeof(rej), &rej); + break; + } } return hci_req_run(&req, clean_up_hci_complete); @@ -5184,6 +5208,18 @@ void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status) { struct mgmt_ev_connect_failed ev; + struct pending_cmd *power_off; + + power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev); + if (power_off) { + struct mgmt_mode *cp = power_off->param; + + /* The connection is still in hci_conn_hash so test for 1 + * instead of 0 to know if this is the last one. + */ + if (!cp->val && hci_conn_count(hdev) == 1) + queue_work(hdev->req_workqueue, &hdev->power_off.work); + } bacpy(&ev.addr.bdaddr, bdaddr); ev.addr.type = link_to_bdaddr(link_type, addr_type); From a3172b7eb4a2719711187cfca12097d2326e85a7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 28 Feb 2014 09:33:44 +0200 Subject: [PATCH 296/414] Bluetooth: Add timer to force power off If some of the cleanup commands caused by mgmt_set_powered(off) never complete we should still force the adapter to be powered down. This is rather easy to do since hdev->power_off is already a delayed work struct. This patch schedules this delayed work if at least one HCI command was sent by the cleanup procedure. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + net/bluetooth/mgmt.c | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index bb3f4926d4e3..35ef60febd57 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -182,6 +182,7 @@ enum { #define HCI_CMD_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ #define HCI_ACL_TX_TIMEOUT msecs_to_jiffies(45000) /* 45 seconds */ #define HCI_AUTO_OFF_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ +#define HCI_POWER_OFF_TIMEOUT msecs_to_jiffies(5000) /* 5 seconds */ /* HCI data types */ #define HCI_COMMAND_PKT 0x01 diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 73b6ff817796..e7c87231b9ea 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1031,8 +1031,10 @@ static void clean_up_hci_complete(struct hci_dev *hdev, u8 status) { BT_DBG("%s status 0x%02x", hdev->name, status); - if (hci_conn_count(hdev) == 0) + if (hci_conn_count(hdev) == 0) { + cancel_delayed_work(&hdev->power_off); queue_work(hdev->req_workqueue, &hdev->power_off.work); + } } static int clean_up_hci_state(struct hci_dev *hdev) @@ -1139,9 +1141,13 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, } else { /* Disconnect connections, stop scans, etc */ err = clean_up_hci_state(hdev); + if (!err) + queue_delayed_work(hdev->req_workqueue, &hdev->power_off, + HCI_POWER_OFF_TIMEOUT); /* ENODATA means there were no HCI commands queued */ if (err == -ENODATA) { + cancel_delayed_work(&hdev->power_off); queue_work(hdev->req_workqueue, &hdev->power_off.work); err = 0; } @@ -5147,8 +5153,10 @@ void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, /* The connection is still in hci_conn_hash so test for 1 * instead of 0 to know if this is the last one. */ - if (!cp->val && hci_conn_count(hdev) == 1) + if (!cp->val && hci_conn_count(hdev) == 1) { + cancel_delayed_work(&hdev->power_off); queue_work(hdev->req_workqueue, &hdev->power_off.work); + } } if (!mgmt_connected) @@ -5217,8 +5225,10 @@ void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, /* The connection is still in hci_conn_hash so test for 1 * instead of 0 to know if this is the last one. */ - if (!cp->val && hci_conn_count(hdev) == 1) + if (!cp->val && hci_conn_count(hdev) == 1) { + cancel_delayed_work(&hdev->power_off); queue_work(hdev->req_workqueue, &hdev->power_off.work); + } } bacpy(&ev.addr.bdaddr, bdaddr); From fe39c7b2dacf7fd4dcddc26704d01315ab92b7cb Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 27 Feb 2014 16:00:28 -0800 Subject: [PATCH 297/414] Bluetooth: Use __le64 type for LE random numbers The random numbers in Bluetooth Low Energy are 64-bit numbers and should also be little endian since the HCI specification is little endian. Change the whole Low Energy pairing to use __le64 instead of a byte array. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 4 ++-- include/net/bluetooth/hci_core.h | 8 ++++---- include/net/bluetooth/mgmt.h | 2 +- net/bluetooth/hci_conn.c | 6 +++--- net/bluetooth/hci_core.c | 13 ++++++------- net/bluetooth/hci_event.c | 2 +- net/bluetooth/mgmt.c | 2 +- net/bluetooth/smp.c | 22 ++++++++++------------ net/bluetooth/smp.h | 2 +- 9 files changed, 29 insertions(+), 32 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 35ef60febd57..0740fee39c73 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1234,7 +1234,7 @@ struct hci_cp_le_conn_update { #define HCI_OP_LE_START_ENC 0x2019 struct hci_cp_le_start_enc { __le16 handle; - __u8 rand[8]; + __le64 rand; __le16 ediv; __u8 ltk[16]; } __packed; @@ -1646,7 +1646,7 @@ struct hci_ev_le_conn_complete { #define HCI_EV_LE_LTK_REQ 0x05 struct hci_ev_le_ltk_req { __le16 handle; - __u8 random[8]; + __le64 rand; __le16 ediv; } __packed; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 571168811ecd..0c63a7e12d90 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -99,7 +99,7 @@ struct smp_ltk { u8 type; u8 enc_size; __le16 ediv; - u8 rand[8]; + __le64 rand; u8 val[16]; }; @@ -828,11 +828,11 @@ void hci_link_keys_clear(struct hci_dev *hdev); struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); -struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8], +struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand, bool master); struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, u8 authenticated, - u8 tk[16], u8 enc_size, __le16 ediv, u8 rand[8]); + u8 tk[16], u8 enc_size, __le16 ediv, __le64 rand); struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, bool master); int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type); @@ -1293,7 +1293,7 @@ struct hci_sec_filter { void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, u16 to_multiplier); -void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], +void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand, __u8 ltk[16]); int hci_update_random_address(struct hci_request *req, bool require_privacy, diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 62d560624e3d..0326648fd799 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -187,7 +187,7 @@ struct mgmt_ltk_info { __u8 master; __u8 enc_size; __le16 ediv; - __u8 rand[8]; + __le64 rand; __u8 val[16]; } __packed; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7d6f05e3cae8..5b0802994cbb 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -231,7 +231,7 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp); } -void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], +void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand, __u8 ltk[16]) { struct hci_dev *hdev = conn->hdev; @@ -242,9 +242,9 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], memset(&cp, 0, sizeof(cp)); cp.handle = cpu_to_le16(conn->handle); - memcpy(cp.ltk, ltk, sizeof(cp.ltk)); + cp.rand = rand; cp.ediv = ediv; - memcpy(cp.rand, rand, sizeof(cp.rand)); + memcpy(cp.ltk, ltk, sizeof(cp.ltk)); hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp); } diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a9ff1cbe2c41..32c0c2c58f66 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -765,10 +765,10 @@ static int long_term_keys_show(struct seq_file *f, void *ptr) hci_dev_lock(hdev); list_for_each_safe(p, n, &hdev->long_term_keys) { struct smp_ltk *ltk = list_entry(p, struct smp_ltk, list); - seq_printf(f, "%pMR (type %u) %u 0x%02x %u %.4x %*phN %*phN\n", + seq_printf(f, "%pMR (type %u) %u 0x%02x %u %.4x %.16llx %*phN\n", <k->bdaddr, ltk->bdaddr_type, ltk->authenticated, ltk->type, ltk->enc_size, __le16_to_cpu(ltk->ediv), - 8, ltk->rand, 16, ltk->val); + __le64_to_cpu(ltk->rand), 16, ltk->val); } hci_dev_unlock(hdev); @@ -2921,14 +2921,13 @@ static bool ltk_type_master(u8 type) return false; } -struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8], +struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand, bool master) { struct smp_ltk *k; list_for_each_entry(k, &hdev->long_term_keys, list) { - if (k->ediv != ediv || - memcmp(rand, k->rand, sizeof(k->rand))) + if (k->ediv != ediv || k->rand != rand) continue; if (ltk_type_master(k->type) != master) @@ -3046,7 +3045,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, u8 authenticated, - u8 tk[16], u8 enc_size, __le16 ediv, u8 rand[8]) + u8 tk[16], u8 enc_size, __le16 ediv, __le64 rand) { struct smp_ltk *key, *old_key; bool master = ltk_type_master(type); @@ -3066,9 +3065,9 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, memcpy(key->val, tk, sizeof(key->val)); key->authenticated = authenticated; key->ediv = ediv; + key->rand = rand; key->enc_size = enc_size; key->type = type; - memcpy(key->rand, rand, sizeof(key->rand)); return key; } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 674bfdc3ecc3..e3d7151e808e 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3843,7 +3843,7 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) if (conn == NULL) goto not_found; - ltk = hci_find_ltk(hdev, ev->ediv, ev->random, conn->out); + ltk = hci_find_ltk(hdev, ev->ediv, ev->rand, conn->out); if (ltk == NULL) goto not_found; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e7c87231b9ea..2d11c817d082 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5025,11 +5025,11 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key) ev.key.type = key->authenticated; ev.key.enc_size = key->enc_size; ev.key.ediv = key->ediv; + ev.key.rand = key->rand; if (key->type == HCI_SMP_LTK) ev.key.master = 1; - memcpy(ev.key.rand, key->rand, sizeof(key->rand)); memcpy(ev.key.val, key->val, sizeof(key->val)); mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 0de98fe23330..99abffcaf16b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -517,11 +517,9 @@ static void random_work(struct work_struct *work) } if (hcon->out) { - u8 stk[16], rand[8]; - __le16 ediv; - - memset(rand, 0, sizeof(rand)); - ediv = 0; + u8 stk[16]; + __le64 rand = 0; + __le16 ediv = 0; smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key); swap128(key, stk); @@ -537,11 +535,9 @@ static void random_work(struct work_struct *work) hci_le_start_enc(hcon, ediv, rand, stk); hcon->enc_key_size = smp->enc_key_size; } else { - u8 stk[16], r[16], rand[8]; - __le16 ediv; - - memset(rand, 0, sizeof(rand)); - ediv = 0; + u8 stk[16], r[16]; + __le64 rand = 0; + __le16 ediv = 0; swap128(smp->prnd, r); smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r); @@ -1205,20 +1201,22 @@ int smp_distribute_keys(struct l2cap_conn *conn) struct smp_ltk *ltk; u8 authenticated; __le16 ediv; + __le64 rand; get_random_bytes(enc.ltk, sizeof(enc.ltk)); get_random_bytes(&ediv, sizeof(ediv)); - get_random_bytes(ident.rand, sizeof(ident.rand)); + get_random_bytes(&rand, sizeof(rand)); smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc); authenticated = hcon->sec_level == BT_SECURITY_HIGH; ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK_SLAVE, authenticated, enc.ltk, - smp->enc_key_size, ediv, ident.rand); + smp->enc_key_size, ediv, rand); smp->slave_ltk = ltk; ident.ediv = ediv; + ident.rand = rand; smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident); diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 1b8af35b292c..a11d4281542c 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -78,7 +78,7 @@ struct smp_cmd_encrypt_info { #define SMP_CMD_MASTER_IDENT 0x07 struct smp_cmd_master_ident { __le16 ediv; - __u8 rand[8]; + __le64 rand; } __packed; #define SMP_CMD_IDENT_INFO 0x08 From 759331d7cc660be17bcdc5df53f196135f9dfaf6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 28 Feb 2014 10:10:16 +0200 Subject: [PATCH 298/414] Bluetooth: Fix clearing SMP keys if pairing fails If SMP fails we should not leave any keys (LTKs or IRKs) hanging around the internal lists. This patch adds the necessary code to smp_chan_destroy to remove any keys we may have in case of pairing failure. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 99abffcaf16b..f1cb6a32e93f 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -589,6 +589,24 @@ void smp_chan_destroy(struct l2cap_conn *conn) complete = test_bit(SMP_FLAG_COMPLETE, &smp->smp_flags); mgmt_smp_complete(conn->hcon, complete); + /* If pairing failed clean up any keys we might have */ + if (!complete) { + if (smp->ltk) { + list_del(&smp->ltk->list); + kfree(smp->ltk); + } + + if (smp->slave_ltk) { + list_del(&smp->slave_ltk->list); + kfree(smp->slave_ltk); + } + + if (smp->remote_irk) { + list_del(&smp->remote_irk->list); + kfree(smp->remote_irk); + } + } + kfree(smp); conn->smp_chan = NULL; conn->hcon->smp_conn = NULL; From 8d97250ea2231736225f2e99a91adb266eedfcbe Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 28 Feb 2014 12:54:14 +0200 Subject: [PATCH 299/414] Bluetooth: Add protections for updating local random address Different controllers behave differently when HCI_Set_Random_Address is called while they are advertising or have a HCI_LE_Create_Connection in progress. Some take the newly written address into use for the pending operation while others use the random address that we had at the time that the operation started. Due to this undefined behavior and for the fact that we want to reliably determine the initiator address of all connections for the sake of SMP it's best to simply prevent the random address update if we have these problematic operations in progress. This patch adds a set_random_addr() helper function for the use of hci_update_random_address which contains the necessary checks for advertising and ongoing LE connections. One extra thing we need to do is to clear the HCI_ADVERTISING flag in the enable_advertising() function before sending any commands. Since re-enabling advertising happens by calling first disable_advertising() and then enable_advertising() all while having the HCI_ADVERTISING flag set. Clearing the flag lets the set_random_addr() function know that it's safe to write a new address at least as far as advertising is concerned. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 27 +++++++++++++++++++++++++-- net/bluetooth/mgmt.c | 7 +++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 32c0c2c58f66..8bbfdea9cbec 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3649,6 +3649,29 @@ static void le_scan_disable_work(struct work_struct *work) BT_ERR("Disable LE scanning request failed: err %d", err); } +static void set_random_addr(struct hci_request *req, bdaddr_t *rpa) +{ + struct hci_dev *hdev = req->hdev; + + /* If we're advertising or initiating an LE connection we can't + * go ahead and change the random address at this time. This is + * because the eventual initiator address used for the + * subsequently created connection will be undefined (some + * controllers use the new address and others the one we had + * when the operation started). + * + * In this kind of scenario skip the update and let the random + * address be updated at the next cycle. + */ + if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) || + hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT)) { + BT_DBG("Deferring random address update"); + return; + } + + hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, rpa); +} + int hci_update_random_address(struct hci_request *req, bool require_privacy, u8 *own_addr_type) { @@ -3674,7 +3697,7 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy, return err; } - hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, &hdev->rpa); + set_random_addr(req, &hdev->rpa); to = msecs_to_jiffies(hdev->rpa_timeout * 1000); queue_delayed_work(hdev->workqueue, &hdev->rpa_expired, to); @@ -3693,7 +3716,7 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy, urpa.b[5] &= 0x3f; /* Clear two most significant bits */ *own_addr_type = ADDR_LE_DEV_RANDOM; - hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, &urpa); + set_random_addr(req, &urpa); return 0; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 2d11c817d082..98e9df3556e7 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -840,6 +840,13 @@ static void enable_advertising(struct hci_request *req) u8 own_addr_type, enable = 0x01; bool connectable; + /* Clear the HCI_ADVERTISING bit temporarily so that the + * hci_update_random_address knows that it's safe to go ahead + * and write a new random address. The flag will be set back on + * as soon as the SET_ADV_ENABLE HCI command completes. + */ + clear_bit(HCI_ADVERTISING, &hdev->dev_flags); + connectable = get_connectable(hdev); /* Set require_privacy to true only when non-connectable From b46e00308929cc0317a021a7ac050790f023b1ca Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 28 Feb 2014 12:54:15 +0200 Subject: [PATCH 300/414] Bluetooth: Fix updating connection state to BT_CONNECT too early We shouldn't update the hci_conn state to BT_CONNECT until the moment that we're ready to send the initiating HCI command for it. If the connection has the BT_CONNECT state too early the code responsible for updating the local random address may incorrectly think there's a pending connection in progress and refuse to update the address. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 5b0802994cbb..818330c1b2a2 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -588,6 +588,8 @@ static void hci_req_add_le_create_conn(struct hci_request *req, cp.max_ce_len = __constant_cpu_to_le16(0x0000); hci_req_add(req, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp); + + conn->state = BT_CONNECT; } static void stop_scan_complete(struct hci_dev *hdev, u8 status) @@ -689,7 +691,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, conn->dst_type = dst_type; - conn->state = BT_CONNECT; conn->out = true; conn->link_mode |= HCI_LM_MASTER; conn->sec_level = BT_SECURITY_LOW; From cb1d68f7a337142e283ef7fc78793a57ffb4cdc3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 28 Feb 2014 12:54:16 +0200 Subject: [PATCH 301/414] Bluetooth: Track LE initiator and responder address information For SMP we need the local and remote addresses (and their types) that were used to establish the connection. These may be different from the Identity Addresses or even the current RPA. To guarantee that we have this information available and it is correct track these values separately from the very beginning of the connection. For outgoing connections we set the values as soon as we get a successful command status for HCI_LE_Create_Connection (for which the patch adds a command status handler function) and for incoming connections as soon as we get a LE Connection Complete HCI event. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 4 ++ net/bluetooth/hci_event.c | 78 ++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 0c63a7e12d90..edf194679b7d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -332,6 +332,10 @@ struct hci_conn { __u8 dst_type; bdaddr_t src; __u8 src_type; + bdaddr_t init_addr; + __u8 init_addr_type; + bdaddr_t resp_addr; + __u8 resp_addr_type; __u16 handle; __u16 state; __u8 mode; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e3d7151e808e..3ae8ae1a029c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1641,6 +1641,47 @@ static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status) amp_write_remote_assoc(hdev, cp->phy_handle); } +static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status) +{ + struct hci_cp_le_create_conn *cp; + struct hci_conn *conn; + + BT_DBG("%s status 0x%2.2x", hdev->name, status); + + /* All connection failure handling is taken care of by the + * hci_le_conn_failed function which is triggered by the HCI + * request completion callbacks used for connecting. + */ + if (status) + return; + + cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CONN); + if (!cp) + return; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr); + if (!conn) + goto unlock; + + /* Store the initiator and responder address information which + * is needed for SMP. These values will not change during the + * lifetime of the connection. + */ + conn->init_addr_type = cp->own_address_type; + if (cp->own_address_type == ADDR_LE_DEV_RANDOM) + bacpy(&conn->init_addr, &hdev->random_addr); + else + bacpy(&conn->init_addr, &hdev->bdaddr); + + conn->resp_addr_type = cp->peer_addr_type; + bacpy(&conn->resp_addr, &cp->peer_addr); + +unlock: + hci_dev_unlock(hdev); +} + static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); @@ -2532,6 +2573,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_cs_accept_phylink(hdev, ev->status); break; + case HCI_OP_LE_CREATE_CONN: + hci_cs_le_create_conn(hdev, ev->status); + break; + default: BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode); break; @@ -3716,6 +3761,39 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->out = true; conn->link_mode |= HCI_LM_MASTER; } + + /* If we didn't have a hci_conn object previously + * but we're in master role this must be something + * initiated using a white list. Since white list based + * connections are not "first class citizens" we don't + * have full tracking of them. Therefore, we go ahead + * with a "best effort" approach of determining the + * initiator address based on the HCI_PRIVACY flag. + */ + if (conn->out) { + conn->resp_addr_type = ev->bdaddr_type; + bacpy(&conn->resp_addr, &ev->bdaddr); + if (test_bit(HCI_PRIVACY, &hdev->dev_flags)) { + conn->init_addr_type = ADDR_LE_DEV_RANDOM; + bacpy(&conn->init_addr, &hdev->rpa); + } else { + hci_copy_identity_address(hdev, + &conn->init_addr, + &conn->init_addr_type); + } + } else { + /* Set the responder (our side) address type based on + * the advertising address type. + */ + conn->resp_addr_type = hdev->adv_addr_type; + if (hdev->adv_addr_type == ADDR_LE_DEV_RANDOM) + bacpy(&conn->resp_addr, &hdev->random_addr); + else + bacpy(&conn->resp_addr, &hdev->bdaddr); + + conn->init_addr_type = ev->bdaddr_type; + bacpy(&conn->init_addr, &ev->bdaddr); + } } /* Ensure that the hci_conn contains the identity address type From b1cd5fd937e692276ac6c085684afb16a4e6e798 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 28 Feb 2014 12:54:17 +0200 Subject: [PATCH 302/414] Bluetooth: Use hdev->init/resp_addr values for smp_c1 function Now that we have nicely tracked values of the initiator and responder address information we can pass that directly to the smp_c1 function without worrying e.g. about who initiated the connection. This patch updates the two places in smp.c to use the new variables. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index f1cb6a32e93f..4f4ff36f5f34 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -445,14 +445,9 @@ static void confirm_work(struct work_struct *work) /* Prevent mutual access to hdev->tfm_aes */ hci_dev_lock(hdev); - if (conn->hcon->out) - ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, - conn->hcon->src_type, &conn->hcon->src, - conn->hcon->dst_type, &conn->hcon->dst, res); - else - ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, - conn->hcon->dst_type, &conn->hcon->dst, - conn->hcon->src_type, &conn->hcon->src, res); + ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, + conn->hcon->init_addr_type, &conn->hcon->init_addr, + conn->hcon->resp_addr_type, &conn->hcon->resp_addr, res); hci_dev_unlock(hdev); @@ -492,14 +487,9 @@ static void random_work(struct work_struct *work) /* Prevent mutual access to hdev->tfm_aes */ hci_dev_lock(hdev); - if (hcon->out) - ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, - hcon->src_type, &hcon->src, - hcon->dst_type, &hcon->dst, res); - else - ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, - hcon->dst_type, &hcon->dst, - hcon->src_type, &hcon->src, res); + ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, + hcon->init_addr_type, &hcon->init_addr, + hcon->resp_addr_type, &hcon->resp_addr, res); hci_dev_unlock(hdev); From a7139edd28215623e80c998edd34b3f750c5efc6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 28 Feb 2014 17:45:45 +0200 Subject: [PATCH 303/414] Bluetooth: Add defines for LE initiator filter policy This patch adds defines for the initiator filter policy parameter values of the HCI_LE_Create_Connection command. They will be used in a subsequent patch to check whether we should have a timeout for the connection attempt or not. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 0740fee39c73..439b4ebf9644 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1182,6 +1182,9 @@ struct hci_cp_le_set_scan_enable { __u8 filter_dup; } __packed; +#define HCI_LE_USE_PEER_ADDR 0x00 +#define HCI_LE_USE_WHITELIST 0x01 + #define HCI_OP_LE_CREATE_CONN 0x200d struct hci_cp_le_create_conn { __le16 scan_interval; From 9489eca4ab2fd5d9bbf3bab992168cc8107fc3e9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 28 Feb 2014 17:45:46 +0200 Subject: [PATCH 304/414] Bluetooth: Add timeout for LE connection attempts LE connection attempts do not have a controller side timeout in the same way as BR/EDR has (in form of the page timeout). Since we always do scanning before initiating connections the attempts are always expected to succeed in some reasonable time. This patch adds a timer which forces a cancellation of the connection attempt within 20 seconds if it has not been successful by then. This way we e.g. ensure that mgmt_pair_device times out eventually and gives an error response. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_conn.c | 13 +++++++++++++ net/bluetooth/hci_event.c | 12 ++++++++++++ 4 files changed, 27 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 439b4ebf9644..0409f0119d2b 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -183,6 +183,7 @@ enum { #define HCI_ACL_TX_TIMEOUT msecs_to_jiffies(45000) /* 45 seconds */ #define HCI_AUTO_OFF_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ #define HCI_POWER_OFF_TIMEOUT msecs_to_jiffies(5000) /* 5 seconds */ +#define HCI_LE_CONN_TIMEOUT msecs_to_jiffies(20000) /* 20 seconds */ /* HCI data types */ #define HCI_COMMAND_PKT 0x01 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index edf194679b7d..dbb788e4f265 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -375,6 +375,7 @@ struct hci_conn { struct delayed_work disc_work; struct delayed_work auto_accept_work; struct delayed_work idle_work; + struct delayed_work le_conn_timeout; struct device dev; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 818330c1b2a2..7e47e4240c95 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -363,6 +363,16 @@ static void hci_conn_auto_accept(struct work_struct *work) &conn->dst); } +static void le_conn_timeout(struct work_struct *work) +{ + struct hci_conn *conn = container_of(work, struct hci_conn, + le_conn_timeout.work); + + BT_DBG(""); + + hci_le_create_connection_cancel(conn); +} + struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) { struct hci_conn *conn; @@ -410,6 +420,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout); INIT_DELAYED_WORK(&conn->auto_accept_work, hci_conn_auto_accept); INIT_DELAYED_WORK(&conn->idle_work, hci_conn_idle); + INIT_DELAYED_WORK(&conn->le_conn_timeout, le_conn_timeout); atomic_set(&conn->refcnt, 0); @@ -442,6 +453,8 @@ int hci_conn_del(struct hci_conn *conn) /* Unacked frames */ hdev->acl_cnt += conn->sent; } else if (conn->type == LE_LINK) { + cancel_delayed_work_sync(&conn->le_conn_timeout); + if (hdev->le_pkts) hdev->le_cnt += conn->sent; else diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3ae8ae1a029c..a1075c713a9d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1678,6 +1678,16 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status) conn->resp_addr_type = cp->peer_addr_type; bacpy(&conn->resp_addr, &cp->peer_addr); + /* We don't want the connection attempt to stick around + * indefinitely since LE doesn't have a page timeout concept + * like BR/EDR. Set a timer for any connection that doesn't use + * the white list for connecting. + */ + if (cp->filter_policy == HCI_LE_USE_PEER_ADDR) + queue_delayed_work(conn->hdev->workqueue, + &conn->le_conn_timeout, + HCI_LE_CONN_TIMEOUT); + unlock: hci_dev_unlock(hdev); } @@ -3794,6 +3804,8 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->init_addr_type = ev->bdaddr_type; bacpy(&conn->init_addr, &ev->bdaddr); } + } else { + cancel_delayed_work(&conn->le_conn_timeout); } /* Ensure that the hci_conn contains the identity address type From 38ccdc93326f61b84734028e586ed522a53b733a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 28 Feb 2014 18:10:02 +0200 Subject: [PATCH 305/414] Bluetooth: Re-encrypt link after receiving an LTK It's not strictly speaking required to re-encrypt a link once we receive an LTK since the connection is already encrypted with the STK. However, re-encrypting with the LTK allows us to verify that we've received an LTK that actually works. This patch updates the SMP code to request encrypting with the LTK in case we're in master role and waits until the key refresh complete event before notifying user space of the distributed keys. A new flag is also added for the SMP context to ensure that we re-encryption only once in case of multiple calls to smp_distribute_keys. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 32 +++++++++++++++++++++++++++----- net/bluetooth/smp.h | 3 ++- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 4f4ff36f5f34..e119d76f87a7 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1178,6 +1178,7 @@ int smp_distribute_keys(struct l2cap_conn *conn) struct smp_chan *smp = conn->smp_chan; struct hci_conn *hcon = conn->hcon; struct hci_dev *hdev = hcon->hdev; + bool ltk_encrypt; __u8 *keydist; BT_DBG("conn %p", conn); @@ -1269,12 +1270,33 @@ int smp_distribute_keys(struct l2cap_conn *conn) if ((smp->remote_key_dist & 0x07)) return 0; - clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags); - cancel_delayed_work_sync(&conn->security_timer); - set_bit(SMP_FLAG_COMPLETE, &smp->smp_flags); - smp_notify_keys(conn); + /* Check if we should try to re-encrypt the link with the LTK. + * SMP_FLAG_LTK_ENCRYPT flag is used to track whether we've + * already tried this (in which case we shouldn't try again). + * + * The request will trigger an encryption key refresh event + * which will cause a call to auth_cfm and eventually lead to + * l2cap_core.c calling this smp_distribute_keys function again + * and thereby completing the process. + */ + if (smp->ltk) + ltk_encrypt = !test_and_set_bit(SMP_FLAG_LTK_ENCRYPT, + &smp->smp_flags); + else + ltk_encrypt = false; - smp_chan_destroy(conn); + /* Re-encrypt the link with LTK if possible */ + if (ltk_encrypt && hcon->out) { + struct smp_ltk *ltk = smp->ltk; + hci_le_start_enc(hcon, ltk->ediv, ltk->rand, ltk->val); + hcon->enc_key_size = ltk->enc_size; + } else { + clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags); + cancel_delayed_work_sync(&conn->security_timer); + set_bit(SMP_FLAG_COMPLETE, &smp->smp_flags); + smp_notify_keys(conn); + smp_chan_destroy(conn); + } return 0; } diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index a11d4281542c..676395f93702 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -118,7 +118,8 @@ struct smp_cmd_security_req { #define SMP_FLAG_TK_VALID 1 #define SMP_FLAG_CFM_PENDING 2 #define SMP_FLAG_MITM_AUTH 3 -#define SMP_FLAG_COMPLETE 4 +#define SMP_FLAG_LTK_ENCRYPT 4 +#define SMP_FLAG_COMPLETE 5 struct smp_chan { struct l2cap_conn *conn; From e3098be40bbde0fdd5fcfa6bf28491db421d333a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 28 Feb 2014 18:10:03 +0200 Subject: [PATCH 306/414] Bluetooth: Delay LTK encryption to let remote receive all keys Some devices may refuse to re-encrypt with the LTK if they haven't received all our keys yet. This patch adds a 250ms delay before attempting re-encryption with the LTK. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 22 +++++++++++++++++++--- net/bluetooth/smp.h | 3 +++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index e119d76f87a7..f886bcae1b7e 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -549,6 +549,20 @@ error: smp_failure(conn, reason); } +static void smp_reencrypt(struct work_struct *work) +{ + struct smp_chan *smp = container_of(work, struct smp_chan, + reencrypt.work); + struct l2cap_conn *conn = smp->conn; + struct hci_conn *hcon = conn->hcon; + struct smp_ltk *ltk = smp->ltk; + + BT_DBG(""); + + hci_le_start_enc(hcon, ltk->ediv, ltk->rand, ltk->val); + hcon->enc_key_size = ltk->enc_size; +} + static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) { struct smp_chan *smp; @@ -559,6 +573,7 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) INIT_WORK(&smp->confirm, confirm_work); INIT_WORK(&smp->random, random_work); + INIT_DELAYED_WORK(&smp->reencrypt, smp_reencrypt); smp->conn = conn; conn->smp_chan = smp; @@ -576,6 +591,8 @@ void smp_chan_destroy(struct l2cap_conn *conn) BUG_ON(!smp); + cancel_delayed_work_sync(&smp->reencrypt); + complete = test_bit(SMP_FLAG_COMPLETE, &smp->smp_flags); mgmt_smp_complete(conn->hcon, complete); @@ -1287,9 +1304,8 @@ int smp_distribute_keys(struct l2cap_conn *conn) /* Re-encrypt the link with LTK if possible */ if (ltk_encrypt && hcon->out) { - struct smp_ltk *ltk = smp->ltk; - hci_le_start_enc(hcon, ltk->ediv, ltk->rand, ltk->val); - hcon->enc_key_size = ltk->enc_size; + queue_delayed_work(hdev->req_workqueue, &smp->reencrypt, + SMP_REENCRYPT_TIMEOUT); } else { clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags); cancel_delayed_work_sync(&conn->security_timer); diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 676395f93702..f55d83617218 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -121,6 +121,8 @@ struct smp_cmd_security_req { #define SMP_FLAG_LTK_ENCRYPT 4 #define SMP_FLAG_COMPLETE 5 +#define SMP_REENCRYPT_TIMEOUT msecs_to_jiffies(250) + struct smp_chan { struct l2cap_conn *conn; u8 preq[7]; /* SMP Pairing Request */ @@ -140,6 +142,7 @@ struct smp_chan { unsigned long smp_flags; struct work_struct confirm; struct work_struct random; + struct delayed_work reencrypt; }; /* SMP Commands */ From 317ac8cb3f9fb58b9ec5764b766a449004ab2a62 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 28 Feb 2014 20:26:12 +0200 Subject: [PATCH 307/414] Bluetooth: Fix trying to disable scanning twice The discovery process has a timer for disabling scanning, however scanning might be disabled through other means too like the auto-connect process. We should therefore ensure that the timer is never active after sending a HCI command to disable scanning. There was some existing code in stop_scan_complete trying to avoid the timer when a connect request interrupts a discovery procedure, but the other way around was not covered. This patch covers both scenarios by canceling the timer as soon as we get a successful command complete for the disabling HCI command. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 1 - net/bluetooth/hci_event.c | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7e47e4240c95..5330fcfde93d 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -628,7 +628,6 @@ static void stop_scan_complete(struct hci_dev *hdev, u8 status) /* Since we may have prematurely stopped discovery procedure, we should * update discovery state. */ - cancel_delayed_work(&hdev->le_scan_disable); hci_discovery_set_state(hdev, DISCOVERY_STOPPED); hci_req_init(&req, hdev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index a1075c713a9d..e3335b03c992 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1018,6 +1018,11 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, break; case LE_SCAN_DISABLE: + /* Cancel this timer so that we don't try to disable scanning + * when it's already disabled. + */ + cancel_delayed_work(&hdev->le_scan_disable); + clear_bit(HCI_LE_SCAN, &hdev->dev_flags); break; From 81ad6fd9698f659dbabdc6cd3e1667a98eb2be3b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 28 Feb 2014 20:26:13 +0200 Subject: [PATCH 308/414] Bluetooth: Remove unnecessary stop_scan_complete function The stop_scan_complete function was used as an intermediate step before doing the actual connection creation. Since we're using hci_request there's no reason to have this extra function around, i.e. we can simply put both HCI commands into the same request. The single task that the intermediate function had, i.e. indicating discovery as stopped is now taken care of by a new HCI_LE_SCAN_INTERRUPTED flag which allows us to do the discovery state update when the stop scan command completes. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_conn.c | 51 ++++++------------------------------- net/bluetooth/hci_event.c | 7 +++++ 3 files changed, 16 insertions(+), 43 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 0409f0119d2b..be150cf8cd43 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -140,6 +140,7 @@ enum { HCI_FAST_CONNECTABLE, HCI_BREDR_ENABLED, HCI_6LOWPAN_ENABLED, + HCI_LE_SCAN_INTERRUPTED, }; /* A mask for the flags that are supposed to remain when a reset happens diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 5330fcfde93d..7c713c4675ba 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -605,44 +605,6 @@ static void hci_req_add_le_create_conn(struct hci_request *req, conn->state = BT_CONNECT; } -static void stop_scan_complete(struct hci_dev *hdev, u8 status) -{ - struct hci_request req; - struct hci_conn *conn; - int err; - - conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); - if (!conn) - return; - - if (status) { - BT_DBG("HCI request failed to stop scanning: status 0x%2.2x", - status); - - hci_dev_lock(hdev); - hci_le_conn_failed(conn, status); - hci_dev_unlock(hdev); - return; - } - - /* Since we may have prematurely stopped discovery procedure, we should - * update discovery state. - */ - hci_discovery_set_state(hdev, DISCOVERY_STOPPED); - - hci_req_init(&req, hdev); - - hci_req_add_le_create_conn(&req, conn); - - err = hci_req_run(&req, create_le_conn_complete); - if (err) { - hci_dev_lock(hdev); - hci_le_conn_failed(conn, HCI_ERROR_MEMORY_EXCEEDED); - hci_dev_unlock(hdev); - return; - } -} - struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, u8 dst_type, u8 sec_level, u8 auth_type) { @@ -721,16 +683,19 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, hci_req_init(&req, hdev); /* If controller is scanning, we stop it since some controllers are - * not able to scan and connect at the same time. + * not able to scan and connect at the same time. Also set the + * HCI_LE_SCAN_INTERRUPTED flag so that the command complete + * handler for scan disabling knows to set the correct discovery + * state. */ if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) { hci_req_add_le_scan_disable(&req); - err = hci_req_run(&req, stop_scan_complete); - } else { - hci_req_add_le_create_conn(&req, conn); - err = hci_req_run(&req, create_le_conn_complete); + set_bit(HCI_LE_SCAN_INTERRUPTED, &hdev->dev_flags); } + hci_req_add_le_create_conn(&req, conn); + + err = hci_req_run(&req, create_le_conn_complete); if (err) { hci_conn_del(conn); return ERR_PTR(err); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e3335b03c992..c3b0a08f5ab4 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1024,6 +1024,13 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, cancel_delayed_work(&hdev->le_scan_disable); clear_bit(HCI_LE_SCAN, &hdev->dev_flags); + /* The HCI_LE_SCAN_INTERRUPTED flag indicates that we + * interrupted scanning due to a connect request. Mark + * therefore discovery as stopped. + */ + if (test_and_clear_bit(HCI_LE_SCAN_INTERRUPTED, + &hdev->dev_flags)) + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); break; default: From 946651cba26779864bcdbd7e12502f5a36c2de37 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Sat, 15 Feb 2014 00:05:52 +0100 Subject: [PATCH 309/414] wl1251: split wl251 platform data to a separate structure Move the wl1251 part of the wl12xx platform data structure into a new structure specifically for wl1251. Change the platform data built-in block and board files accordingly. Signed-off-by: Luciano Coelho Acked-by: Tony Lindgren Reviewed-by: Felipe Balbi Reviewed-by: Sebastian Reichel Reviewed-by: Pavel Machek Signed-off-by: John W. Linville --- arch/arm/mach-omap2/board-omap3pandora.c | 4 +- arch/arm/mach-omap2/board-rx51-peripherals.c | 2 +- .../net/wireless/ti/wilink_platform_data.c | 37 ++++++++++++++++--- drivers/net/wireless/ti/wl1251/sdio.c | 12 +++--- drivers/net/wireless/ti/wl1251/spi.c | 2 +- include/linux/wl12xx.h | 22 ++++++++++- 6 files changed, 62 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c index de1bc6bbe585..24f3c1be69a5 100644 --- a/arch/arm/mach-omap2/board-omap3pandora.c +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -536,7 +536,7 @@ static struct spi_board_info omap3pandora_spi_board_info[] __initdata = { static void __init pandora_wl1251_init(void) { - struct wl12xx_platform_data pandora_wl1251_pdata; + struct wl1251_platform_data pandora_wl1251_pdata; int ret; memset(&pandora_wl1251_pdata, 0, sizeof(pandora_wl1251_pdata)); @@ -550,7 +550,7 @@ static void __init pandora_wl1251_init(void) goto fail_irq; pandora_wl1251_pdata.use_eeprom = true; - ret = wl12xx_set_platform_data(&pandora_wl1251_pdata); + ret = wl1251_set_platform_data(&pandora_wl1251_pdata); if (ret < 0) goto fail_irq; diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index 8760bbe3baab..e05e740a4426 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -84,7 +84,7 @@ enum { RX51_SPI_MIPID, /* LCD panel */ }; -static struct wl12xx_platform_data wl1251_pdata; +static struct wl1251_platform_data wl1251_pdata; static struct tsc2005_platform_data tsc2005_pdata; #if defined(CONFIG_SENSORS_LIS3_I2C) || defined(CONFIG_SENSORS_LIS3_I2C_MODULE) diff --git a/drivers/net/wireless/ti/wilink_platform_data.c b/drivers/net/wireless/ti/wilink_platform_data.c index 998e95895f9d..a92bd3e89796 100644 --- a/drivers/net/wireless/ti/wilink_platform_data.c +++ b/drivers/net/wireless/ti/wilink_platform_data.c @@ -23,17 +23,17 @@ #include #include -static struct wl12xx_platform_data *platform_data; +static struct wl12xx_platform_data *wl12xx_platform_data; int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data) { - if (platform_data) + if (wl12xx_platform_data) return -EBUSY; if (!data) return -EINVAL; - platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL); - if (!platform_data) + wl12xx_platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL); + if (!wl12xx_platform_data) return -ENOMEM; return 0; @@ -41,9 +41,34 @@ int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data) struct wl12xx_platform_data *wl12xx_get_platform_data(void) { - if (!platform_data) + if (!wl12xx_platform_data) return ERR_PTR(-ENODEV); - return platform_data; + return wl12xx_platform_data; } EXPORT_SYMBOL(wl12xx_get_platform_data); + +static struct wl1251_platform_data *wl1251_platform_data; + +int __init wl1251_set_platform_data(const struct wl1251_platform_data *data) +{ + if (wl1251_platform_data) + return -EBUSY; + if (!data) + return -EINVAL; + + wl1251_platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL); + if (!wl1251_platform_data) + return -ENOMEM; + + return 0; +} + +struct wl1251_platform_data *wl1251_get_platform_data(void) +{ + if (!wl1251_platform_data) + return ERR_PTR(-ENODEV); + + return wl1251_platform_data; +} +EXPORT_SYMBOL(wl1251_get_platform_data); diff --git a/drivers/net/wireless/ti/wl1251/sdio.c b/drivers/net/wireless/ti/wl1251/sdio.c index e2b3d9c541e8..b75a37a58313 100644 --- a/drivers/net/wireless/ti/wl1251/sdio.c +++ b/drivers/net/wireless/ti/wl1251/sdio.c @@ -227,7 +227,7 @@ static int wl1251_sdio_probe(struct sdio_func *func, struct wl1251 *wl; struct ieee80211_hw *hw; struct wl1251_sdio *wl_sdio; - const struct wl12xx_platform_data *wl12xx_board_data; + const struct wl1251_platform_data *wl1251_board_data; hw = wl1251_alloc_hw(); if (IS_ERR(hw)) @@ -254,11 +254,11 @@ static int wl1251_sdio_probe(struct sdio_func *func, wl->if_priv = wl_sdio; wl->if_ops = &wl1251_sdio_ops; - wl12xx_board_data = wl12xx_get_platform_data(); - if (!IS_ERR(wl12xx_board_data)) { - wl->set_power = wl12xx_board_data->set_power; - wl->irq = wl12xx_board_data->irq; - wl->use_eeprom = wl12xx_board_data->use_eeprom; + wl1251_board_data = wl1251_get_platform_data(); + if (!IS_ERR(wl1251_board_data)) { + wl->set_power = wl1251_board_data->set_power; + wl->irq = wl1251_board_data->irq; + wl->use_eeprom = wl1251_board_data->use_eeprom; } if (wl->irq) { diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c index 1342f81e683d..62403a147592 100644 --- a/drivers/net/wireless/ti/wl1251/spi.c +++ b/drivers/net/wireless/ti/wl1251/spi.c @@ -238,7 +238,7 @@ static const struct wl1251_if_operations wl1251_spi_ops = { static int wl1251_spi_probe(struct spi_device *spi) { - struct wl12xx_platform_data *pdata; + struct wl1251_platform_data *pdata; struct ieee80211_hw *hw; struct wl1251 *wl; int ret; diff --git a/include/linux/wl12xx.h b/include/linux/wl12xx.h index a54fe82e704b..b516b4fa22de 100644 --- a/include/linux/wl12xx.h +++ b/include/linux/wl12xx.h @@ -48,11 +48,15 @@ enum { WL12XX_TCXOCLOCK_33_6 = 7, /* 33.6 MHz */ }; -struct wl12xx_platform_data { +struct wl1251_platform_data { void (*set_power)(bool enable); /* SDIO only: IRQ number if WLAN_IRQ line is used, 0 for SDIO IRQs */ int irq; bool use_eeprom; +}; + +struct wl12xx_platform_data { + int irq; int board_ref_clock; int board_tcxo_clock; unsigned long platform_quirks; @@ -68,6 +72,10 @@ int wl12xx_set_platform_data(const struct wl12xx_platform_data *data); struct wl12xx_platform_data *wl12xx_get_platform_data(void); +int wl1251_set_platform_data(const struct wl1251_platform_data *data); + +struct wl1251_platform_data *wl1251_get_platform_data(void); + #else static inline @@ -82,6 +90,18 @@ struct wl12xx_platform_data *wl12xx_get_platform_data(void) return ERR_PTR(-ENODATA); } +static inline +int wl1251_set_platform_data(const struct wl1251_platform_data *data) +{ + return -ENOSYS; +} + +static inline +struct wl1251_platform_data *wl1251_get_platform_data(void) +{ + return ERR_PTR(-ENODATA); +} + #endif #endif From 1d207cd30b65fdd60d952cb9e100b6f776564f06 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sat, 15 Feb 2014 00:05:53 +0100 Subject: [PATCH 310/414] wl1251: move power GPIO handling into the driver Move the power GPIO handling from the board code into the driver. This is a dependency for device tree support. Signed-off-by: Sebastian Reichel Reviewed-by: Pavel Machek Acked-by: Tony Lindgren Signed-off-by: John W. Linville --- arch/arm/mach-omap2/board-omap3pandora.c | 2 ++ arch/arm/mach-omap2/board-rx51-peripherals.c | 11 ++----- drivers/net/wireless/ti/wl1251/sdio.c | 21 ++++++++++--- drivers/net/wireless/ti/wl1251/spi.c | 33 +++++++++++++------- drivers/net/wireless/ti/wl1251/wl1251.h | 2 +- include/linux/wl12xx.h | 2 +- 6 files changed, 43 insertions(+), 28 deletions(-) diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c index 24f3c1be69a5..cf18340eb3bb 100644 --- a/arch/arm/mach-omap2/board-omap3pandora.c +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -541,6 +541,8 @@ static void __init pandora_wl1251_init(void) memset(&pandora_wl1251_pdata, 0, sizeof(pandora_wl1251_pdata)); + pandora_wl1251_pdata.power_gpio = -1; + ret = gpio_request_one(PANDORA_WIFI_IRQ_GPIO, GPIOF_IN, "wl1251 irq"); if (ret < 0) goto fail; diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index e05e740a4426..ddfc8df83c6a 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -1173,13 +1173,7 @@ static inline void board_smc91x_init(void) #endif -static void rx51_wl1251_set_power(bool enable) -{ - gpio_set_value(RX51_WL1251_POWER_GPIO, enable); -} - static struct gpio rx51_wl1251_gpios[] __initdata = { - { RX51_WL1251_POWER_GPIO, GPIOF_OUT_INIT_LOW, "wl1251 power" }, { RX51_WL1251_IRQ_GPIO, GPIOF_IN, "wl1251 irq" }, }; @@ -1196,17 +1190,16 @@ static void __init rx51_init_wl1251(void) if (irq < 0) goto err_irq; - wl1251_pdata.set_power = rx51_wl1251_set_power; + wl1251_pdata.power_gpio = RX51_WL1251_POWER_GPIO; rx51_peripherals_spi_board_info[RX51_SPI_WL1251].irq = irq; return; err_irq: gpio_free(RX51_WL1251_IRQ_GPIO); - gpio_free(RX51_WL1251_POWER_GPIO); error: printk(KERN_ERR "wl1251 board initialisation failed\n"); - wl1251_pdata.set_power = NULL; + wl1251_pdata.power_gpio = -1; /* * Now rx51_peripherals_spi_board_info[1].irq is zero and diff --git a/drivers/net/wireless/ti/wl1251/sdio.c b/drivers/net/wireless/ti/wl1251/sdio.c index b75a37a58313..b661f896e9fe 100644 --- a/drivers/net/wireless/ti/wl1251/sdio.c +++ b/drivers/net/wireless/ti/wl1251/sdio.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "wl1251.h" @@ -182,8 +183,9 @@ static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable) * callback in case it wants to do any additional setup, * for example enabling clock buffer for the module. */ - if (wl->set_power) - wl->set_power(true); + if (gpio_is_valid(wl->power_gpio)) + gpio_set_value(wl->power_gpio, true); + ret = pm_runtime_get_sync(&func->dev); if (ret < 0) { @@ -203,8 +205,8 @@ static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable) if (ret < 0) goto out; - if (wl->set_power) - wl->set_power(false); + if (gpio_is_valid(wl->power_gpio)) + gpio_set_value(wl->power_gpio, false); } out: @@ -256,11 +258,20 @@ static int wl1251_sdio_probe(struct sdio_func *func, wl1251_board_data = wl1251_get_platform_data(); if (!IS_ERR(wl1251_board_data)) { - wl->set_power = wl1251_board_data->set_power; + wl->power_gpio = wl1251_board_data->power_gpio; wl->irq = wl1251_board_data->irq; wl->use_eeprom = wl1251_board_data->use_eeprom; } + if (gpio_is_valid(wl->power_gpio)) { + ret = devm_gpio_request(&func->dev, wl->power_gpio, + "wl1251 power"); + if (ret) { + wl1251_error("Failed to request gpio: %d\n", ret); + goto disable; + } + } + if (wl->irq) { irq_set_status_flags(wl->irq, IRQ_NOAUTOEN); ret = request_irq(wl->irq, wl1251_line_irq, 0, "wl1251", wl); diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c index 62403a147592..6abcbc3f7fc7 100644 --- a/drivers/net/wireless/ti/wl1251/spi.c +++ b/drivers/net/wireless/ti/wl1251/spi.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "wl1251.h" #include "reg.h" @@ -221,8 +222,8 @@ static void wl1251_spi_disable_irq(struct wl1251 *wl) static int wl1251_spi_set_power(struct wl1251 *wl, bool enable) { - if (wl->set_power) - wl->set_power(enable); + if (gpio_is_valid(wl->power_gpio)) + gpio_set_value(wl->power_gpio, enable); return 0; } @@ -271,22 +272,33 @@ static int wl1251_spi_probe(struct spi_device *spi) goto out_free; } - wl->set_power = pdata->set_power; - if (!wl->set_power) { - wl1251_error("set power function missing in platform data"); - return -ENODEV; + wl->power_gpio = pdata->power_gpio; + + if (gpio_is_valid(wl->power_gpio)) { + ret = devm_gpio_request_one(&spi->dev, wl->power_gpio, + GPIOF_OUT_INIT_LOW, "wl1251 power"); + if (ret) { + wl1251_error("Failed to request gpio: %d\n", ret); + goto out_free; + } + } else { + wl1251_error("set power gpio missing in platform data"); + ret = -ENODEV; + goto out_free; } wl->irq = spi->irq; if (wl->irq < 0) { wl1251_error("irq missing in platform data"); - return -ENODEV; + ret = -ENODEV; + goto out_free; } wl->use_eeprom = pdata->use_eeprom; irq_set_status_flags(wl->irq, IRQ_NOAUTOEN); - ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); + ret = devm_request_irq(&spi->dev, wl->irq, wl1251_irq, 0, + DRIVER_NAME, wl); if (ret < 0) { wl1251_error("request_irq() failed: %d", ret); goto out_free; @@ -296,13 +308,10 @@ static int wl1251_spi_probe(struct spi_device *spi) ret = wl1251_init_ieee80211(wl); if (ret) - goto out_irq; + goto out_free; return 0; - out_irq: - free_irq(wl->irq, wl); - out_free: ieee80211_free_hw(hw); diff --git a/drivers/net/wireless/ti/wl1251/wl1251.h b/drivers/net/wireless/ti/wl1251/wl1251.h index 235617a7716d..389fe25af1b6 100644 --- a/drivers/net/wireless/ti/wl1251/wl1251.h +++ b/drivers/net/wireless/ti/wl1251/wl1251.h @@ -276,7 +276,7 @@ struct wl1251 { void *if_priv; const struct wl1251_if_operations *if_ops; - void (*set_power)(bool enable); + int power_gpio; int irq; bool use_eeprom; diff --git a/include/linux/wl12xx.h b/include/linux/wl12xx.h index b516b4fa22de..a9c723be1acf 100644 --- a/include/linux/wl12xx.h +++ b/include/linux/wl12xx.h @@ -49,7 +49,7 @@ enum { }; struct wl1251_platform_data { - void (*set_power)(bool enable); + int power_gpio; /* SDIO only: IRQ number if WLAN_IRQ line is used, 0 for SDIO IRQs */ int irq; bool use_eeprom; From e4c2e09e1534835c749de362b9b38e2d8b286236 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sat, 15 Feb 2014 00:05:54 +0100 Subject: [PATCH 311/414] wl1251: spi: add vio regulator support This patch adds support for requesting the regulator powering the vio pin. Signed-off-by: Sebastian Reichel Reviewed-by: Pavel Machek Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wl1251/spi.c | 19 +++++++++++++++++-- drivers/net/wireless/ti/wl1251/wl1251.h | 2 ++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c index 6abcbc3f7fc7..0a8aacceedd1 100644 --- a/drivers/net/wireless/ti/wl1251/spi.c +++ b/drivers/net/wireless/ti/wl1251/spi.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "wl1251.h" #include "reg.h" @@ -306,13 +307,26 @@ static int wl1251_spi_probe(struct spi_device *spi) irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); - ret = wl1251_init_ieee80211(wl); + wl->vio = devm_regulator_get(&spi->dev, "vio"); + if (IS_ERR(wl->vio)) { + ret = PTR_ERR(wl->vio); + wl1251_error("vio regulator missing: %d", ret); + goto out_free; + } + + ret = regulator_enable(wl->vio); if (ret) goto out_free; + ret = wl1251_init_ieee80211(wl); + if (ret) + goto disable_regulator; + return 0; - out_free: +disable_regulator: + regulator_disable(wl->vio); +out_free: ieee80211_free_hw(hw); return ret; @@ -324,6 +338,7 @@ static int wl1251_spi_remove(struct spi_device *spi) free_irq(wl->irq, wl); wl1251_free_hw(wl); + regulator_disable(wl->vio); return 0; } diff --git a/drivers/net/wireless/ti/wl1251/wl1251.h b/drivers/net/wireless/ti/wl1251/wl1251.h index 389fe25af1b6..16dae5269175 100644 --- a/drivers/net/wireless/ti/wl1251/wl1251.h +++ b/drivers/net/wireless/ti/wl1251/wl1251.h @@ -280,6 +280,8 @@ struct wl1251 { int irq; bool use_eeprom; + struct regulator *vio; + spinlock_t wl_lock; enum wl1251_state state; From 07bbca6f142d02b4b09d66ed3c2cde36c77057ad Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sat, 15 Feb 2014 00:05:55 +0100 Subject: [PATCH 312/414] wl1251: spi: add device tree support Add device tree support for the spi variant of wl1251. Signed-off-by: Sebastian Reichel Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wl1251/spi.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c index 0a8aacceedd1..b06d36d99362 100644 --- a/drivers/net/wireless/ti/wl1251/spi.c +++ b/drivers/net/wireless/ti/wl1251/spi.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include "wl1251.h" @@ -240,13 +242,13 @@ static const struct wl1251_if_operations wl1251_spi_ops = { static int wl1251_spi_probe(struct spi_device *spi) { - struct wl1251_platform_data *pdata; + struct wl1251_platform_data *pdata = dev_get_platdata(&spi->dev); + struct device_node *np = spi->dev.of_node; struct ieee80211_hw *hw; struct wl1251 *wl; int ret; - pdata = dev_get_platdata(&spi->dev); - if (!pdata) { + if (!np && !pdata) { wl1251_error("no platform data"); return -ENODEV; } @@ -273,7 +275,18 @@ static int wl1251_spi_probe(struct spi_device *spi) goto out_free; } - wl->power_gpio = pdata->power_gpio; + if (np) { + wl->use_eeprom = of_property_read_bool(np, "ti,wl1251-has-eeprom"); + wl->power_gpio = of_get_named_gpio(np, "ti,power-gpio", 0); + } else if (pdata) { + wl->power_gpio = pdata->power_gpio; + wl->use_eeprom = pdata->use_eeprom; + } + + if (wl->power_gpio == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto out_free; + } if (gpio_is_valid(wl->power_gpio)) { ret = devm_gpio_request_one(&spi->dev, wl->power_gpio, @@ -295,8 +308,6 @@ static int wl1251_spi_probe(struct spi_device *spi) goto out_free; } - wl->use_eeprom = pdata->use_eeprom; - irq_set_status_flags(wl->irq, IRQ_NOAUTOEN); ret = devm_request_irq(&spi->dev, wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); From edb6e3ec374d5630dfc7a93ddd5c0f4864e98a9d Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sat, 15 Feb 2014 00:05:56 +0100 Subject: [PATCH 313/414] Documentation: dt: wireless: Add wl1251 Add device tree binding documentation for Texas Instrument's wl1251 wireless lan chip. For now only the SPI binding is documented. Signed-off-by: Sebastian Reichel Signed-off-by: John W. Linville --- .../bindings/net/wireless/ti,wl1251.txt | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt diff --git a/Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt b/Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt new file mode 100644 index 000000000000..189ae5cad8f7 --- /dev/null +++ b/Documentation/devicetree/bindings/net/wireless/ti,wl1251.txt @@ -0,0 +1,39 @@ +* Texas Instruments wl1251 wireless lan controller + +The wl1251 chip can be connected via SPI or via SDIO. This +document describes the binding for the SPI connected chip. + +Required properties: +- compatible : Should be "ti,wl1251" +- reg : Chip select address of device +- spi-max-frequency : Maximum SPI clocking speed of device in Hz +- interrupts : Should contain interrupt line +- interrupt-parent : Should be the phandle for the interrupt controller + that services interrupts for this device +- vio-supply : phandle to regulator providing VIO +- ti,power-gpio : GPIO connected to chip's PMEN pin + +Optional properties: +- ti,wl1251-has-eeprom : boolean, the wl1251 has an eeprom connected, which + provides configuration data (calibration, MAC, ...) +- Please consult Documentation/devicetree/bindings/spi/spi-bus.txt + for optional SPI connection related properties, + +Examples: + +&spi1 { + wl1251@0 { + compatible = "ti,wl1251"; + + reg = <0>; + spi-max-frequency = <48000000>; + spi-cpol; + spi-cpha; + + interrupt-parent = <&gpio2>; + interrupts = <10 IRQ_TYPE_NONE>; /* gpio line 42 */ + + vio-supply = <&vio>; + ti,power-gpio = <&gpio3 23 GPIO_ACTIVE_HIGH>; /* 87 */ + }; +}; From e74075a936a894b85ddf25b882ac813323aae4ef Mon Sep 17 00:00:00 2001 From: andrea merello Date: Tue, 18 Feb 2014 02:10:40 +0100 Subject: [PATCH 314/414] rtl818x: Explicitly enable contetion window Currently the contention window enable/disable HW flag is not touched by the driver. This patch explicitly set it to the correct value to make sure contention window is enabled (AFAIK contention window must be enabled in most (if not all) cases. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 7980ab1f9eca..470a1e32aa4e 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -642,6 +642,8 @@ static int rtl8180_start(struct ieee80211_hw *dev) else reg &= ~RTL818X_TX_CONF_HW_SEQNUM; + reg &= ~RTL818X_TX_CONF_DISCW; + /* different meaning, same value on both rtl8185 and rtl8180 */ reg &= ~RTL818X_TX_CONF_SAT_HWPLCP; From 0269da281599fba2bc8bed30953d5a3ff3b083e5 Mon Sep 17 00:00:00 2001 From: andrea merello Date: Tue, 18 Feb 2014 02:10:41 +0100 Subject: [PATCH 315/414] rtl818x: pci_iomap() should pair with pci_iounmap() Currently the driver uses pci_iomap() but iounmap() is called in the error path Change to use pci_iounmap() instead. Reported-by: Huqiu Liu Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 470a1e32aa4e..bf59ff988952 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -1137,7 +1137,7 @@ static int rtl8180_probe(struct pci_dev *pdev, return 0; err_iounmap: - iounmap(priv->map); + pci_iounmap(pdev, priv->map); err_free_dev: ieee80211_free_hw(dev); From ec1da08dd721f53b97e792c749d236907c764932 Mon Sep 17 00:00:00 2001 From: andrea merello Date: Sat, 22 Feb 2014 17:57:23 +0100 Subject: [PATCH 316/414] rtl818x: check for pci_map_single() success when initializing RX ring During initialization a number of RX skbs are allocated and mapped for DMA. Currently if pci_map_single() fails, it will result in passing to the HW a wrong DMA address (to write to!). This patch adds check for this condition and eventually causes the driver not to initialize, avoiding at least dangerous DMAs. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index bf59ff988952..0102da2f145a 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -483,6 +483,13 @@ static int rtl8180_init_rx_ring(struct ieee80211_hw *dev) mapping = (dma_addr_t *)skb->cb; *mapping = pci_map_single(priv->pdev, skb_tail_pointer(skb), MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + + if (pci_dma_mapping_error(priv->pdev, *mapping)) { + kfree_skb(skb); + wiphy_err(dev->wiphy, "Cannot map DMA for RX skb\n"); + return -ENOMEM; + } + entry->rx_buf = cpu_to_le32(*mapping); entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN | MAX_RX_SIZE); From 4da18bb4fb53537a279fe899620de9af4bf4695c Mon Sep 17 00:00:00 2001 From: andrea merello Date: Tue, 18 Feb 2014 02:10:43 +0100 Subject: [PATCH 317/414] rtl818x: make dev_alloc_skb() null pointer check to really work During driver initialization, some skbs are preallocated for RX. Currenly if the allocation fails, the driver's allocation routine exits immediatly but it will return zero (success) anyway. In this way the driver will continue initialization with buggy pointers around. This patch makes the driver's allocation routine to return an error value and to print a complaint message when skb allocation fails. In this way its caller will not go further, avoinding the driver to successfully load, and preventing dereferencing buggy pointers. An hint is thus printed about why the driver failed. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 0102da2f145a..a9af83ef24ad 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -476,9 +476,10 @@ static int rtl8180_init_rx_ring(struct ieee80211_hw *dev) struct sk_buff *skb = dev_alloc_skb(MAX_RX_SIZE); dma_addr_t *mapping; entry = &priv->rx_ring[i]; - if (!skb) - return 0; - + if (!skb) { + wiphy_err(dev->wiphy, "Cannot allocate RX skb\n"); + return -ENOMEM; + } priv->rx_buf[i] = skb; mapping = (dma_addr_t *)skb->cb; *mapping = pci_map_single(priv->pdev, skb_tail_pointer(skb), From 14c76150f7cc07c4662bd8e6622e5e38df985315 Mon Sep 17 00:00:00 2001 From: andrea merello Date: Tue, 18 Feb 2014 02:10:44 +0100 Subject: [PATCH 318/414] rtl818x: add comments to explain few not obvious HW configs. Certain HW options (TX packet retry count, CW configuration and TX power configuration) can be specified in both the TX packet descriptor and also into HW "global" registers. The HW is thus configured to honour the global register or the TX descriptor field depending by the case. This patch adds few comments that hopefully clarify in which cases the driver uses one method and in which cases it uses the other. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index a9af83ef24ad..1f2462e92528 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -627,11 +627,23 @@ static int rtl8180_start(struct ieee80211_hw *dev) if (priv->r8185) { reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); + + /* CW is not on per-packet basis. + * in rtl8185 the CW_VALUE reg is used. + */ reg &= ~RTL818X_CW_CONF_PERPACKET_CW; + /* retry limit IS on per-packet basis. + * the short and long retry limit in TX_CONF + * reg are ignored + */ reg |= RTL818X_CW_CONF_PERPACKET_RETRY; rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); + /* TX antenna and TX gain are not on per-packet basis. + * TX Antenna is selected by ANTSEL reg (RX in BB regs). + * TX gain is selected with CCK_TX_AGC and OFDM_TX_AGC regs + */ reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN; reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL; reg |= RTL818X_TX_AGC_CTL_FEEDBACK_ANT; From e0febf14888b450225405d05beb4ae1c9e131594 Mon Sep 17 00:00:00 2001 From: "Zhao, Gang" Date: Tue, 18 Feb 2014 21:35:57 +0800 Subject: [PATCH 319/414] airo: replace function ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan} Replace ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan} with more generic ieee80211_{channel_to_frequency, frequency_to_channel}. Include for the defination of IEEE80211_BAND_2GHZ. Because includes , so we can replace with . This change is a preparation for the removal of function ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan}. Signed-off-by: Zhao, Gang Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 79c4a7692d50..64747d457bb3 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -49,7 +49,7 @@ #include #include -#include +#include #include #include "airo.h" @@ -5797,7 +5797,7 @@ static int airo_set_freq(struct net_device *dev, /* Hack to fall through... */ fwrq->e = 0; - fwrq->m = ieee80211_freq_to_dsss_chan(f); + fwrq->m = ieee80211_frequency_to_channel(f); } /* Setting by channel number */ if((fwrq->m > 1000) || (fwrq->e > 0)) @@ -5841,7 +5841,8 @@ static int airo_get_freq(struct net_device *dev, ch = le16_to_cpu(status_rid.channel); if((ch > 0) && (ch < 15)) { - fwrq->m = ieee80211_dsss_chan_to_freq(ch) * 100000; + fwrq->m = 100000 * + ieee80211_channel_to_frequency(ch, IEEE80211_BAND_2GHZ); fwrq->e = 1; } else { fwrq->m = ch; @@ -6898,7 +6899,8 @@ static int airo_get_range(struct net_device *dev, k = 0; for(i = 0; i < 14; i++) { range->freq[k].i = i + 1; /* List index */ - range->freq[k].m = ieee80211_dsss_chan_to_freq(i + 1) * 100000; + range->freq[k].m = 100000 * + ieee80211_channel_to_frequency(i + 1, IEEE80211_BAND_2GHZ); range->freq[k++].e = 1; /* Values in MHz -> * 10^5 * 10 */ } range->num_frequency = k; @@ -7297,7 +7299,8 @@ static inline char *airo_translate_scan(struct net_device *dev, /* Add frequency */ iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = le16_to_cpu(bss->dsChannel); - iwe.u.freq.m = ieee80211_dsss_chan_to_freq(iwe.u.freq.m) * 100000; + iwe.u.freq.m = 100000 * + ieee80211_channel_to_frequency(iwe.u.freq.m, IEEE80211_BAND_2GHZ); iwe.u.freq.e = 1; current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); From 61e5487b34d3831fcc0db1308643f4a5dc465ae1 Mon Sep 17 00:00:00 2001 From: "Zhao, Gang" Date: Tue, 18 Feb 2014 21:35:58 +0800 Subject: [PATCH 320/414] atmel: replace function ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan} Replace ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan} with more generic ieee80211_{channel_to_frequency, frequency_to_channel}. Include for the defination of IEEE80211_BAND_2GHZ. Because includes , so we can replace with . This change is a preparation for the removal of function ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan}. Cc: Simon Kelley Signed-off-by: Zhao, Gang Signed-off-by: John W. Linville --- drivers/net/wireless/atmel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index bf93ea859f2d..1fe41af81a59 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -67,7 +67,7 @@ #include #include #include -#include +#include #include "atmel.h" #define DRIVER_MAJOR 0 @@ -2273,7 +2273,7 @@ static int atmel_set_freq(struct net_device *dev, /* Hack to fall through... */ fwrq->e = 0; - fwrq->m = ieee80211_freq_to_dsss_chan(f); + fwrq->m = ieee80211_frequency_to_channel(f); } /* Setting by channel number */ if ((fwrq->m > 1000) || (fwrq->e > 0)) @@ -2434,8 +2434,8 @@ static int atmel_get_range(struct net_device *dev, range->freq[k].i = i; /* List index */ /* Values in MHz -> * 10^5 * 10 */ - range->freq[k].m = (ieee80211_dsss_chan_to_freq(i) * - 100000); + range->freq[k].m = 100000 * + ieee80211_channel_to_frequency(i, IEEE80211_BAND_2GHZ); range->freq[k++].e = 1; } range->num_frequency = k; From de5356e6aad65405952f7057802c576c1268fb4b Mon Sep 17 00:00:00 2001 From: "Zhao, Gang" Date: Tue, 18 Feb 2014 21:35:59 +0800 Subject: [PATCH 321/414] wl3501_cs: replace function ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan} Replace ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan} with more generic ieee80211_{channel_to_frequency, frequency_to_channel}. Include for the defination of IEEE80211_BAND_2GHZ. Because includes , so we can replace with . This change is a preparation for the removal of function ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan}. Cc: Arnaldo Carvalho de Melo Signed-off-by: Zhao, Gang Signed-off-by: John W. Linville --- drivers/net/wireless/wl3501_cs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 66bca677c4fa..d5c371d77ddf 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include @@ -1453,7 +1453,8 @@ static int wl3501_get_freq(struct net_device *dev, struct iw_request_info *info, { struct wl3501_card *this = netdev_priv(dev); - wrqu->freq.m = ieee80211_dsss_chan_to_freq(this->chan) * 100000; + wrqu->freq.m = 100000 * + ieee80211_channel_to_frequency(this->chan, IEEE80211_BAND_2GHZ); wrqu->freq.e = 1; return 0; } From 3a11af8aadc5a7bf9b4cdec6424869b1017b452e Mon Sep 17 00:00:00 2001 From: "Zhao, Gang" Date: Tue, 18 Feb 2014 21:36:00 +0800 Subject: [PATCH 322/414] rndis_wlan: replace function ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan} Replace ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan} with more generic ieee80211_{channel_to_frequency, frequency_to_channel}. File has already been included. It's safe to use IEEE80211_BAND_2GHZ here. This change is a preparation for the removal of function ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan}. Cc: Jussi Kivilinna Signed-off-by: Zhao, Gang Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 2e89a865a67d..39d22a154341 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1290,7 +1290,8 @@ static int set_channel(struct usbnet *usbdev, int channel) if (is_associated(usbdev)) return 0; - dsconfig = ieee80211_dsss_chan_to_freq(channel) * 1000; + dsconfig = 1000 * + ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); len = sizeof(config); ret = rndis_query_oid(usbdev, From 3d54b9052c08a473f56cbed6a0bb4c900c948474 Mon Sep 17 00:00:00 2001 From: "Zhao, Gang" Date: Tue, 18 Feb 2014 21:36:01 +0800 Subject: [PATCH 323/414] zd1201: replace function ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan} Replace ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan} with more generic ieee80211_{channel_to_frequency, frequency_to_channel}. Function ieee80211_frequency_to_channel() will return 0 if frequency is not correctly provided, so no need to set channel to 0 explicitly. Include for the defination of IEEE80211_BAND_2GHZ. Because includes , so we can replace with . This change is a preparation for the removal of function ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan}. Signed-off-by: Zhao, Gang Signed-off-by: John W. Linville --- drivers/net/wireless/zd1201.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index d39c4178c33a..6f5c793a7855 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -914,11 +914,8 @@ static int zd1201_set_freq(struct net_device *dev, if (freq->e == 0) channel = freq->m; - else { - channel = ieee80211_freq_to_dsss_chan(freq->m); - if (channel < 0) - channel = 0; - } + else + channel = ieee80211_frequency_to_channel(freq->m); err = zd1201_setconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, channel); if (err) From 13c1ac5703d5507da9422377819d5d1e4e550173 Mon Sep 17 00:00:00 2001 From: "Zhao, Gang" Date: Wed, 19 Feb 2014 16:58:43 +0800 Subject: [PATCH 324/414] orinoco: replace function ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan} Replace ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan} with more generic ieee80211_{channel_to_frequency, frequency_to_channel}. File has already been included. It's safe to use IEEE80211_BAND_2GHZ here. This change is a preparation for the removal of function ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan}. Signed-off-by: Zhao, Gang Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/cfg.c | 5 +++-- drivers/net/wireless/orinoco/hw.c | 2 +- drivers/net/wireless/orinoco/scan.c | 5 +++-- drivers/net/wireless/orinoco/wext.c | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c index d01edd2c50c5..a9e94b6db5b7 100644 --- a/drivers/net/wireless/orinoco/cfg.c +++ b/drivers/net/wireless/orinoco/cfg.c @@ -59,7 +59,8 @@ int orinoco_wiphy_register(struct wiphy *wiphy) for (i = 0; i < NUM_CHANNELS; i++) { if (priv->channel_mask & (1 << i)) { priv->channels[i].center_freq = - ieee80211_dsss_chan_to_freq(i + 1); + ieee80211_channel_to_frequency(i + 1, + IEEE80211_BAND_2GHZ); channels++; } } @@ -177,7 +178,7 @@ static int orinoco_set_monitor_channel(struct wiphy *wiphy, if (chandef->chan->band != IEEE80211_BAND_2GHZ) return -EINVAL; - channel = ieee80211_freq_to_dsss_chan(chandef->chan->center_freq); + channel = ieee80211_frequency_to_channel(chandef->chan->center_freq); if ((channel < 1) || (channel > NUM_CHANNELS) || !(priv->channel_mask & (1 << (channel - 1)))) diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index c09c8437c0b8..49300d04efdf 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -1193,7 +1193,7 @@ int orinoco_hw_get_freq(struct orinoco_private *priv) goto out; } - freq = ieee80211_dsss_chan_to_freq(channel); + freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); out: orinoco_unlock(priv, &flags); diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c index e8c5714bfd11..e175b9b8561b 100644 --- a/drivers/net/wireless/orinoco/scan.c +++ b/drivers/net/wireless/orinoco/scan.c @@ -110,7 +110,8 @@ static void orinoco_add_hostscan_result(struct orinoco_private *priv, break; } - freq = ieee80211_dsss_chan_to_freq(le16_to_cpu(bss->a.channel)); + freq = ieee80211_channel_to_frequency( + le16_to_cpu(bss->a.channel), IEEE80211_BAND_2GHZ); channel = ieee80211_get_channel(wiphy, freq); if (!channel) { printk(KERN_DEBUG "Invalid channel designation %04X(%04X)", @@ -146,7 +147,7 @@ void orinoco_add_extscan_result(struct orinoco_private *priv, ie_len = len - sizeof(*bss); ie = cfg80211_find_ie(WLAN_EID_DS_PARAMS, bss->data, ie_len); chan = ie ? ie[2] : 0; - freq = ieee80211_dsss_chan_to_freq(chan); + freq = ieee80211_channel_to_frequency(chan, IEEE80211_BAND_2GHZ); channel = ieee80211_get_channel(wiphy, freq); timestamp = le64_to_cpu(bss->timestamp); diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 3b5508f982e8..b7a867b50b94 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -444,7 +444,7 @@ static int orinoco_ioctl_setfreq(struct net_device *dev, for (i = 0; i < (6 - frq->e); i++) denom *= 10; - chan = ieee80211_freq_to_dsss_chan(frq->m / denom); + chan = ieee80211_frequency_to_channel(frq->m / denom); } if ((chan < 1) || (chan > NUM_CHANNELS) || From 3ebe8e257307a87c33460aa7d2b75dadd374ed9c Mon Sep 17 00:00:00 2001 From: "Zhao, Gang" Date: Tue, 18 Feb 2014 21:36:03 +0800 Subject: [PATCH 325/414] ieee80211: remove function ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan} Function ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan} have been replaced with ieee80211_{channel_to_frequency, frequency_to_channel}. There should be no users of the two functions now. So remove them. Cc: Johannes Berg Signed-off-by: Zhao, Gang Signed-off-by: John W. Linville --- include/linux/ieee80211.h | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 5f349355ee54..06299048c4f4 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -2307,42 +2307,6 @@ static inline bool ieee80211_is_public_action(struct ieee80211_hdr *hdr, return mgmt->u.action.category == WLAN_CATEGORY_PUBLIC; } -/** - * ieee80211_dsss_chan_to_freq - get channel center frequency - * @channel: the DSSS channel - * - * Convert IEEE802.11 DSSS channel to the center frequency (MHz). - * Ref IEEE 802.11-2007 section 15.6 - */ -static inline int ieee80211_dsss_chan_to_freq(int channel) -{ - if ((channel > 0) && (channel < 14)) - return 2407 + (channel * 5); - else if (channel == 14) - return 2484; - else - return -1; -} - -/** - * ieee80211_freq_to_dsss_chan - get channel - * @freq: the frequency - * - * Convert frequency (MHz) to IEEE802.11 DSSS channel - * Ref IEEE 802.11-2007 section 15.6 - * - * This routine selects the channel with the closest center frequency. - */ -static inline int ieee80211_freq_to_dsss_chan(int freq) -{ - if ((freq >= 2410) && (freq < 2475)) - return (freq - 2405) / 5; - else if ((freq >= 2482) && (freq < 2487)) - return 14; - else - return -1; -} - /** * ieee80211_tu_to_usec - convert time units (TU) to microseconds * @tu: the TUs From c3015313aea0f765dbe743f95087a5994db082f2 Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Tue, 25 Feb 2014 17:41:58 +0530 Subject: [PATCH 326/414] mwl8k: Adding support to access BBP registers Adding AP firmware command to access BBP regs. This will be used for retrieving different counters CCA/RX needed for ACS Signed-off-by: Yogesh Ashok Powar Signed-off-by: Nishant Sarmukadam Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 42 ++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 4987c3f942ce..6c002f3d91cd 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -396,6 +396,7 @@ static const struct ieee80211_rate mwl8k_rates_50[] = { #define MWL8K_CMD_SET_HW_SPEC 0x0004 #define MWL8K_CMD_MAC_MULTICAST_ADR 0x0010 #define MWL8K_CMD_GET_STAT 0x0014 +#define MWL8K_CMD_BBP_REG_ACCESS 0x001a #define MWL8K_CMD_RADIO_CONTROL 0x001c #define MWL8K_CMD_RF_TX_POWER 0x001e #define MWL8K_CMD_TX_POWER 0x001f @@ -2986,6 +2987,47 @@ static int mwl8k_cmd_set_pre_scan(struct ieee80211_hw *hw) return rc; } +/* + * CMD_BBP_REG_ACCESS. + */ +struct mwl8k_cmd_bbp_reg_access { + struct mwl8k_cmd_pkt header; + __le16 action; + __le16 offset; + u8 value; + u8 rsrv[3]; +} __packed; + +static int +mwl8k_cmd_bbp_reg_access(struct ieee80211_hw *hw, + u16 action, + u16 offset, + u8 *value) +{ + struct mwl8k_cmd_bbp_reg_access *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_BBP_REG_ACCESS); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + cmd->action = cpu_to_le16(action); + cmd->offset = cpu_to_le16(offset); + + rc = mwl8k_post_cmd(hw, &cmd->header); + + if (!rc) + *value = cmd->value; + else + *value = 0; + + kfree(cmd); + + return rc; +} + /* * CMD_SET_POST_SCAN. */ From 4c924f42c9c9f60ca861a8c4a52825778e9e09a0 Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Tue, 25 Feb 2014 17:42:09 +0530 Subject: [PATCH 327/414] mwl8k: Implement sw_scan start/stop cbs Implement sw_scan start and stop callbacks. Reset BBP registers for channel, RX busy and average noise stats which clear on read. Signed-off-by: Yogesh Ashok Powar Signed-off-by: Nishant Sarmukadam Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 6c002f3d91cd..61d5bea9a9d7 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -81,6 +81,9 @@ MODULE_PARM_DESC(ap_mode_default, */ #define MWL8K_HW_TIMER_REGISTER 0x0000a600 +#define BBU_RXRDY_CNT_REG 0x0000a860 +#define NOK_CCA_CNT_REG 0x0000a6a0 +#define BBU_AVG_NOISE_VAL 0x67 #define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \ MWL8K_A2H_INT_CHNL_SWITCHED | \ @@ -289,6 +292,9 @@ struct mwl8k_priv { /* bitmap of running BSSes */ u32 running_bsses; + + /* ACS related */ + bool sw_scan_start; }; #define MAX_WEP_KEY_LEN 13 @@ -5448,6 +5454,38 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return rc; } +static void mwl8k_sw_scan_start(struct ieee80211_hw *hw) +{ + struct mwl8k_priv *priv = hw->priv; + u8 tmp; + + if (!priv->ap_fw) + return; + + /* clear all stats */ + ioread32(priv->regs + BBU_RXRDY_CNT_REG); + ioread32(priv->regs + NOK_CCA_CNT_REG); + mwl8k_cmd_bbp_reg_access(priv->hw, 0, BBU_AVG_NOISE_VAL, &tmp); + + priv->sw_scan_start = true; +} + +static void mwl8k_sw_scan_complete(struct ieee80211_hw *hw) +{ + struct mwl8k_priv *priv = hw->priv; + u8 tmp; + + if (!priv->ap_fw) + return; + + priv->sw_scan_start = false; + + /* clear all stats */ + ioread32(priv->regs + BBU_RXRDY_CNT_REG); + ioread32(priv->regs + NOK_CCA_CNT_REG); + mwl8k_cmd_bbp_reg_access(priv->hw, 0, BBU_AVG_NOISE_VAL, &tmp); +} + static const struct ieee80211_ops mwl8k_ops = { .tx = mwl8k_tx, .start = mwl8k_start, @@ -5466,6 +5504,8 @@ static const struct ieee80211_ops mwl8k_ops = { .get_stats = mwl8k_get_stats, .get_survey = mwl8k_get_survey, .ampdu_action = mwl8k_ampdu_action, + .sw_scan_start = mwl8k_sw_scan_start, + .sw_scan_complete = mwl8k_sw_scan_complete, }; static void mwl8k_finalize_join_worker(struct work_struct *work) From 031eb464fb4b7e475c4e8ca59502f017ae328704 Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Tue, 25 Feb 2014 17:42:18 +0530 Subject: [PATCH 328/414] mwl8k: Adding support to gather survey per channel Survey stats such as channel busy time, rx busy time and noise are collected when sw_scan starts for every switched new channel. This happens till sw_scan stops. All the collected stats are shared up when get_survey() is called. This implements support for ACS feature from Hostapd. Signed-off-by: Yogesh Ashok Powar Signed-off-by: Nishant Sarmukadam Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 115 +++++++++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 61d5bea9a9d7..b6d83f6888fa 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -115,6 +115,8 @@ MODULE_PARM_DESC(ap_mode_default, */ #define MWL8K_NUM_AMPDU_STREAMS (TOTAL_HW_TX_QUEUES - 1) +#define MWL8K_NUM_CHANS 18 + struct rxd_ops { int rxd_size; void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr); @@ -295,6 +297,9 @@ struct mwl8k_priv { /* ACS related */ bool sw_scan_start; + struct ieee80211_channel *acs_chan; + unsigned long channel_time; + struct survey_info survey[MWL8K_NUM_CHANS]; }; #define MAX_WEP_KEY_LEN 13 @@ -3064,6 +3069,64 @@ mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, const __u8 *mac) return rc; } +static int freq_to_idx(struct mwl8k_priv *priv, int freq) +{ + struct ieee80211_supported_band *sband; + int band, ch, idx = 0; + + for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { + sband = priv->hw->wiphy->bands[band]; + if (!sband) + continue; + + for (ch = 0; ch < sband->n_channels; ch++, idx++) + if (sband->channels[ch].center_freq == freq) + goto exit; + } + +exit: + return idx; +} + +void mwl8k_update_survey(struct mwl8k_priv *priv, + struct ieee80211_channel *channel) +{ + u32 cca_cnt, rx_rdy; + s8 nf = 0, idx; + struct survey_info *survey; + + idx = freq_to_idx(priv, priv->acs_chan->center_freq); + if (idx >= MWL8K_NUM_CHANS) { + wiphy_err(priv->hw->wiphy, "Failed to update survey\n"); + return; + } + + survey = &priv->survey[idx]; + + cca_cnt = le32_to_cpu(ioread32(priv->regs + NOK_CCA_CNT_REG)); + cca_cnt /= 1000; /* uSecs to mSecs */ + survey->channel_time_busy = (u64) cca_cnt; + + rx_rdy = le32_to_cpu(ioread32(priv->regs + BBU_RXRDY_CNT_REG)); + rx_rdy /= 1000; /* uSecs to mSecs */ + survey->channel_time_rx = (u64) rx_rdy; + + priv->channel_time = jiffies - priv->channel_time; + survey->channel_time = jiffies_to_msecs(priv->channel_time); + + survey->channel = channel; + + mwl8k_cmd_bbp_reg_access(priv->hw, 0, BBU_AVG_NOISE_VAL, &nf); + + /* Make sure sign is negative else ACS at hostapd fails */ + survey->noise = nf * -1; + + survey->filled = SURVEY_INFO_NOISE_DBM | + SURVEY_INFO_CHANNEL_TIME | + SURVEY_INFO_CHANNEL_TIME_BUSY | + SURVEY_INFO_CHANNEL_TIME_RX; +} + /* * CMD_SET_RF_CHANNEL. */ @@ -3081,6 +3144,7 @@ static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw, enum nl80211_channel_type channel_type = cfg80211_get_chandef_type(&conf->chandef); struct mwl8k_cmd_set_rf_channel *cmd; + struct mwl8k_priv *priv = hw->priv; int rc; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -3097,13 +3161,29 @@ static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw, else if (channel->band == IEEE80211_BAND_5GHZ) cmd->channel_flags |= cpu_to_le32(0x00000004); - if (channel_type == NL80211_CHAN_NO_HT || - channel_type == NL80211_CHAN_HT20) + if (!priv->sw_scan_start) { + if (channel_type == NL80211_CHAN_NO_HT || + channel_type == NL80211_CHAN_HT20) + cmd->channel_flags |= cpu_to_le32(0x00000080); + else if (channel_type == NL80211_CHAN_HT40MINUS) + cmd->channel_flags |= cpu_to_le32(0x000001900); + else if (channel_type == NL80211_CHAN_HT40PLUS) + cmd->channel_flags |= cpu_to_le32(0x000000900); + } else { cmd->channel_flags |= cpu_to_le32(0x00000080); - else if (channel_type == NL80211_CHAN_HT40MINUS) - cmd->channel_flags |= cpu_to_le32(0x000001900); - else if (channel_type == NL80211_CHAN_HT40PLUS) - cmd->channel_flags |= cpu_to_le32(0x000000900); + } + + if (priv->sw_scan_start) { + /* Store current channel stats + * before switching to newer one. + * This will be processed only for AP fw. + */ + if (priv->channel_time != 0) + mwl8k_update_survey(priv, priv->acs_chan); + + priv->channel_time = jiffies; + priv->acs_chan = channel; + } rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); @@ -5311,6 +5391,27 @@ static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx, { struct mwl8k_priv *priv = hw->priv; struct ieee80211_conf *conf = &hw->conf; + struct ieee80211_supported_band *sband; + + if (priv->ap_fw) { + sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ]; + + if (sband && idx >= sband->n_channels) { + idx -= sband->n_channels; + sband = NULL; + } + + if (!sband) + sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ]; + + if (!sband || idx >= sband->n_channels) + return -ENOENT; + + memcpy(survey, &priv->survey[idx], sizeof(*survey)); + survey->channel = &sband->channels[idx]; + + return 0; + } if (idx != 0) return -ENOENT; @@ -5463,6 +5564,7 @@ static void mwl8k_sw_scan_start(struct ieee80211_hw *hw) return; /* clear all stats */ + priv->channel_time = 0; ioread32(priv->regs + BBU_RXRDY_CNT_REG); ioread32(priv->regs + NOK_CCA_CNT_REG); mwl8k_cmd_bbp_reg_access(priv->hw, 0, BBU_AVG_NOISE_VAL, &tmp); @@ -5481,6 +5583,7 @@ static void mwl8k_sw_scan_complete(struct ieee80211_hw *hw) priv->sw_scan_start = false; /* clear all stats */ + priv->channel_time = 0; ioread32(priv->regs + BBU_RXRDY_CNT_REG); ioread32(priv->regs + NOK_CCA_CNT_REG); mwl8k_cmd_bbp_reg_access(priv->hw, 0, BBU_AVG_NOISE_VAL, &tmp); From 13f71050c10df77c1b9f2808c410d68dfcdb26b4 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 25 Feb 2014 14:48:50 +0100 Subject: [PATCH 329/414] ath9k: move ath9k_init_channels_rates to common-init and rename it to ath9k_cmn_init_channels_rates. sbands are move to ath_common as well. Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 1 + drivers/net/wireless/ath/ath9k/Makefile | 3 +- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/beacon.c | 2 +- drivers/net/wireless/ath/ath9k/common-init.c | 170 ++++++++++++++++++ drivers/net/wireless/ath/ath9k/common-init.h | 17 ++ drivers/net/wireless/ath/ath9k/common.h | 2 + drivers/net/wireless/ath/ath9k/init.c | 172 ++----------------- drivers/net/wireless/ath/ath9k/xmit.c | 3 +- 9 files changed, 208 insertions(+), 163 deletions(-) create mode 100644 drivers/net/wireless/ath/ath9k/common-init.c create mode 100644 drivers/net/wireless/ath/ath9k/common-init.h diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 56d559939cfc..d239acc26125 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -163,6 +163,7 @@ struct ath_common { bool bt_ant_diversity; int last_rssi; + struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; }; struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 747975e1860a..b58fe99ef745 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -51,7 +51,8 @@ ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \ obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o -ath9k_common-y:= common.o +ath9k_common-y:= common.o \ + common-init.o ath9k_htc-y += htc_hst.o \ hif_usb.o \ diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 21d13bc99c5a..e703ddad7ecf 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -753,7 +753,6 @@ struct ath_softc { struct ath_rx rx; struct ath_tx tx; struct ath_beacon beacon; - struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; #ifdef CONFIG_MAC80211_LEDS bool led_registered; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 32d00e8cfd0c..6569528753af 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -80,7 +80,7 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, u8 chainmask = ah->txchainmask; u8 rate = 0; - sband = &sc->sbands[common->hw->conf.chandef.chan->band]; + sband = &common->sbands[common->hw->conf.chandef.chan->band]; rate = sband->bitrates[rateidx].hw_value; if (vif->bss_conf.use_short_preamble) rate |= sband->bitrates[rateidx].hw_value_short; diff --git a/drivers/net/wireless/ath/ath9k/common-init.c b/drivers/net/wireless/ath/ath9k/common-init.c new file mode 100644 index 000000000000..1fa30c3b7d53 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-init.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* We use the hw_value as an index into our private channel structure */ + +#include "common.h" + +#define CHAN2G(_freq, _idx) { \ + .band = IEEE80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 20, \ +} + +#define CHAN5G(_freq, _idx) { \ + .band = IEEE80211_BAND_5GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 20, \ +} + +/* Some 2 GHz radios are actually tunable on 2312-2732 + * on 5 MHz steps, we support the channels which we know + * we have calibration data for all cards though to make + * this static */ +static const struct ieee80211_channel ath9k_2ghz_chantable[] = { + CHAN2G(2412, 0), /* Channel 1 */ + CHAN2G(2417, 1), /* Channel 2 */ + CHAN2G(2422, 2), /* Channel 3 */ + CHAN2G(2427, 3), /* Channel 4 */ + CHAN2G(2432, 4), /* Channel 5 */ + CHAN2G(2437, 5), /* Channel 6 */ + CHAN2G(2442, 6), /* Channel 7 */ + CHAN2G(2447, 7), /* Channel 8 */ + CHAN2G(2452, 8), /* Channel 9 */ + CHAN2G(2457, 9), /* Channel 10 */ + CHAN2G(2462, 10), /* Channel 11 */ + CHAN2G(2467, 11), /* Channel 12 */ + CHAN2G(2472, 12), /* Channel 13 */ + CHAN2G(2484, 13), /* Channel 14 */ +}; + +/* Some 5 GHz radios are actually tunable on XXXX-YYYY + * on 5 MHz steps, we support the channels which we know + * we have calibration data for all cards though to make + * this static */ +static const struct ieee80211_channel ath9k_5ghz_chantable[] = { + /* _We_ call this UNII 1 */ + CHAN5G(5180, 14), /* Channel 36 */ + CHAN5G(5200, 15), /* Channel 40 */ + CHAN5G(5220, 16), /* Channel 44 */ + CHAN5G(5240, 17), /* Channel 48 */ + /* _We_ call this UNII 2 */ + CHAN5G(5260, 18), /* Channel 52 */ + CHAN5G(5280, 19), /* Channel 56 */ + CHAN5G(5300, 20), /* Channel 60 */ + CHAN5G(5320, 21), /* Channel 64 */ + /* _We_ call this "Middle band" */ + CHAN5G(5500, 22), /* Channel 100 */ + CHAN5G(5520, 23), /* Channel 104 */ + CHAN5G(5540, 24), /* Channel 108 */ + CHAN5G(5560, 25), /* Channel 112 */ + CHAN5G(5580, 26), /* Channel 116 */ + CHAN5G(5600, 27), /* Channel 120 */ + CHAN5G(5620, 28), /* Channel 124 */ + CHAN5G(5640, 29), /* Channel 128 */ + CHAN5G(5660, 30), /* Channel 132 */ + CHAN5G(5680, 31), /* Channel 136 */ + CHAN5G(5700, 32), /* Channel 140 */ + /* _We_ call this UNII 3 */ + CHAN5G(5745, 33), /* Channel 149 */ + CHAN5G(5765, 34), /* Channel 153 */ + CHAN5G(5785, 35), /* Channel 157 */ + CHAN5G(5805, 36), /* Channel 161 */ + CHAN5G(5825, 37), /* Channel 165 */ +}; + +/* Atheros hardware rate code addition for short premble */ +#define SHPCHECK(__hw_rate, __flags) \ + ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) + +#define RATE(_bitrate, _hw_rate, _flags) { \ + .bitrate = (_bitrate), \ + .flags = (_flags), \ + .hw_value = (_hw_rate), \ + .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ +} + +static struct ieee80211_rate ath9k_legacy_rates[] = { + RATE(10, 0x1b, 0), + RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(60, 0x0b, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(90, 0x0f, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(120, 0x0a, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(180, 0x0e, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(240, 0x09, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(360, 0x0d, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(480, 0x08, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(540, 0x0c, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), +}; + +int ath9k_cmn_init_channels_rates(struct ath_common *common) +{ + struct ath_hw *ah = (struct ath_hw *)common->ah; + void *channels; + + BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) + + ARRAY_SIZE(ath9k_5ghz_chantable) != + ATH9K_NUM_CHANNELS); + + if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { + channels = devm_kzalloc(ah->dev, + sizeof(ath9k_2ghz_chantable), GFP_KERNEL); + if (!channels) + return -ENOMEM; + + memcpy(channels, ath9k_2ghz_chantable, + sizeof(ath9k_2ghz_chantable)); + common->sbands[IEEE80211_BAND_2GHZ].channels = channels; + common->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; + common->sbands[IEEE80211_BAND_2GHZ].n_channels = + ARRAY_SIZE(ath9k_2ghz_chantable); + common->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; + common->sbands[IEEE80211_BAND_2GHZ].n_bitrates = + ARRAY_SIZE(ath9k_legacy_rates); + } + + if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { + channels = devm_kzalloc(ah->dev, + sizeof(ath9k_5ghz_chantable), GFP_KERNEL); + if (!channels) + return -ENOMEM; + + memcpy(channels, ath9k_5ghz_chantable, + sizeof(ath9k_5ghz_chantable)); + common->sbands[IEEE80211_BAND_5GHZ].channels = channels; + common->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; + common->sbands[IEEE80211_BAND_5GHZ].n_channels = + ARRAY_SIZE(ath9k_5ghz_chantable); + common->sbands[IEEE80211_BAND_5GHZ].bitrates = + ath9k_legacy_rates + 4; + common->sbands[IEEE80211_BAND_5GHZ].n_bitrates = + ARRAY_SIZE(ath9k_legacy_rates) - 4; + } + return 0; +} +EXPORT_SYMBOL(ath9k_cmn_init_channels_rates); diff --git a/drivers/net/wireless/ath/ath9k/common-init.h b/drivers/net/wireless/ath/ath9k/common-init.h new file mode 100644 index 000000000000..8fc9049ad8b0 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-init.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2009-2011 Atheros Communications 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +int ath9k_cmn_init_channels_rates(struct ath_common *common); diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 38b5609a4018..4c449e35bd65 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -21,6 +21,8 @@ #include "hw.h" #include "hw-ops.h" +#include "common-init.h" + /* Common header for Atheros 802.11n base driver cores */ #define WME_BA_BMP_SIZE 64 diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 4856a1739ade..a6232cf0e998 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -62,111 +62,6 @@ module_param_named(ps_enable, ath9k_ps_enable, int, 0444); MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); bool is_ath9k_unloaded; -/* We use the hw_value as an index into our private channel structure */ - -#define CHAN2G(_freq, _idx) { \ - .band = IEEE80211_BAND_2GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} - -#define CHAN5G(_freq, _idx) { \ - .band = IEEE80211_BAND_5GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} - -/* Some 2 GHz radios are actually tunable on 2312-2732 - * on 5 MHz steps, we support the channels which we know - * we have calibration data for all cards though to make - * this static */ -static const struct ieee80211_channel ath9k_2ghz_chantable[] = { - CHAN2G(2412, 0), /* Channel 1 */ - CHAN2G(2417, 1), /* Channel 2 */ - CHAN2G(2422, 2), /* Channel 3 */ - CHAN2G(2427, 3), /* Channel 4 */ - CHAN2G(2432, 4), /* Channel 5 */ - CHAN2G(2437, 5), /* Channel 6 */ - CHAN2G(2442, 6), /* Channel 7 */ - CHAN2G(2447, 7), /* Channel 8 */ - CHAN2G(2452, 8), /* Channel 9 */ - CHAN2G(2457, 9), /* Channel 10 */ - CHAN2G(2462, 10), /* Channel 11 */ - CHAN2G(2467, 11), /* Channel 12 */ - CHAN2G(2472, 12), /* Channel 13 */ - CHAN2G(2484, 13), /* Channel 14 */ -}; - -/* Some 5 GHz radios are actually tunable on XXXX-YYYY - * on 5 MHz steps, we support the channels which we know - * we have calibration data for all cards though to make - * this static */ -static const struct ieee80211_channel ath9k_5ghz_chantable[] = { - /* _We_ call this UNII 1 */ - CHAN5G(5180, 14), /* Channel 36 */ - CHAN5G(5200, 15), /* Channel 40 */ - CHAN5G(5220, 16), /* Channel 44 */ - CHAN5G(5240, 17), /* Channel 48 */ - /* _We_ call this UNII 2 */ - CHAN5G(5260, 18), /* Channel 52 */ - CHAN5G(5280, 19), /* Channel 56 */ - CHAN5G(5300, 20), /* Channel 60 */ - CHAN5G(5320, 21), /* Channel 64 */ - /* _We_ call this "Middle band" */ - CHAN5G(5500, 22), /* Channel 100 */ - CHAN5G(5520, 23), /* Channel 104 */ - CHAN5G(5540, 24), /* Channel 108 */ - CHAN5G(5560, 25), /* Channel 112 */ - CHAN5G(5580, 26), /* Channel 116 */ - CHAN5G(5600, 27), /* Channel 120 */ - CHAN5G(5620, 28), /* Channel 124 */ - CHAN5G(5640, 29), /* Channel 128 */ - CHAN5G(5660, 30), /* Channel 132 */ - CHAN5G(5680, 31), /* Channel 136 */ - CHAN5G(5700, 32), /* Channel 140 */ - /* _We_ call this UNII 3 */ - CHAN5G(5745, 33), /* Channel 149 */ - CHAN5G(5765, 34), /* Channel 153 */ - CHAN5G(5785, 35), /* Channel 157 */ - CHAN5G(5805, 36), /* Channel 161 */ - CHAN5G(5825, 37), /* Channel 165 */ -}; - -/* Atheros hardware rate code addition for short premble */ -#define SHPCHECK(__hw_rate, __flags) \ - ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) - -#define RATE(_bitrate, _hw_rate, _flags) { \ - .bitrate = (_bitrate), \ - .flags = (_flags), \ - .hw_value = (_hw_rate), \ - .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ -} - -static struct ieee80211_rate ath9k_legacy_rates[] = { - RATE(10, 0x1b, 0), - RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(60, 0x0b, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(90, 0x0f, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(120, 0x0a, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(180, 0x0e, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(240, 0x09, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(360, 0x0d, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(480, 0x08, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), - RATE(540, 0x0c, (IEEE80211_RATE_SUPPORTS_5MHZ | - IEEE80211_RATE_SUPPORTS_10MHZ)), -}; #ifdef CONFIG_MAC80211_LEDS static const struct ieee80211_tpt_blink ath9k_tpt_blink[] = { @@ -486,51 +381,6 @@ static int ath9k_init_queues(struct ath_softc *sc) return 0; } -static int ath9k_init_channels_rates(struct ath_softc *sc) -{ - void *channels; - - BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) + - ARRAY_SIZE(ath9k_5ghz_chantable) != - ATH9K_NUM_CHANNELS); - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { - channels = devm_kzalloc(sc->dev, - sizeof(ath9k_2ghz_chantable), GFP_KERNEL); - if (!channels) - return -ENOMEM; - - memcpy(channels, ath9k_2ghz_chantable, - sizeof(ath9k_2ghz_chantable)); - sc->sbands[IEEE80211_BAND_2GHZ].channels = channels; - sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; - sc->sbands[IEEE80211_BAND_2GHZ].n_channels = - ARRAY_SIZE(ath9k_2ghz_chantable); - sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; - sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates); - } - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { - channels = devm_kzalloc(sc->dev, - sizeof(ath9k_5ghz_chantable), GFP_KERNEL); - if (!channels) - return -ENOMEM; - - memcpy(channels, ath9k_5ghz_chantable, - sizeof(ath9k_5ghz_chantable)); - sc->sbands[IEEE80211_BAND_5GHZ].channels = channels; - sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; - sc->sbands[IEEE80211_BAND_5GHZ].n_channels = - ARRAY_SIZE(ath9k_5ghz_chantable); - sc->sbands[IEEE80211_BAND_5GHZ].bitrates = - ath9k_legacy_rates + 4; - sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates) - 4; - } - return 0; -} - static void ath9k_init_misc(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -793,7 +643,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, if (ret) goto err_btcoex; - ret = ath9k_init_channels_rates(sc); + ret = ath9k_cmn_init_channels_rates(common); if (ret) goto err_btcoex; @@ -823,10 +673,11 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band) struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct cfg80211_chan_def chandef; int i; - sband = &sc->sbands[band]; + sband = &common->sbands[band]; for (i = 0; i < sband->n_channels; i++) { chan = &sband->channels[i]; ah->curchan = &ah->channels[chan->hw_value]; @@ -851,13 +702,16 @@ static void ath9k_init_txpower_limits(struct ath_softc *sc) void ath9k_reload_chainmask_settings(struct ath_softc *sc) { - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)) + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_HT)) return; - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) - setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) - setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); + if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) + setup_ht_cap(sc, &common->sbands[IEEE80211_BAND_2GHZ].ht_cap); + if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) + setup_ht_cap(sc, &common->sbands[IEEE80211_BAND_5GHZ].ht_cap); } static const struct ieee80211_iface_limit if_limits[] = { @@ -970,10 +824,10 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &sc->sbands[IEEE80211_BAND_2GHZ]; + &common->sbands[IEEE80211_BAND_2GHZ]; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &sc->sbands[IEEE80211_BAND_5GHZ]; + &common->sbands[IEEE80211_BAND_5GHZ]; ath9k_init_wow(hw); ath9k_reload_chainmask_settings(sc); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index a6507046dfe8..8f28711cfd4e 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1076,6 +1076,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_info *info, int len, bool rts) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct sk_buff *skb; struct ieee80211_tx_info *tx_info; struct ieee80211_tx_rate *rates; @@ -1145,7 +1146,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, } /* legacy rates */ - rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx]; + rate = &common->sbands[tx_info->band].bitrates[rates[i].idx]; if ((tx_info->band == IEEE80211_BAND_2GHZ) && !(rate->flags & IEEE80211_RATE_ERP_G)) phy = WLAN_RC_PHY_CCK; From 31f023a1cb92678604d5a1427623348f5b896eab Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 25 Feb 2014 14:48:51 +0100 Subject: [PATCH 330/414] ath9k_htc: use ath9k_cmn_init_channels_rates and ath_common sbands. Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc.h | 1 - drivers/net/wireless/ath/ath9k/htc_drv_init.c | 123 +----------------- 2 files changed, 6 insertions(+), 118 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index ba83f582bf4a..3baf9ceae601 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -487,7 +487,6 @@ struct ath9k_htc_priv { unsigned long op_flags; struct ath9k_hw_cal_data caldata; - struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; spinlock_t beacon_lock; struct htc_beacon_config cur_beacon_conf; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 8d0b9bcb47b4..752586d8c3ba 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -38,93 +38,6 @@ static int ath9k_ps_enable; module_param_named(ps_enable, ath9k_ps_enable, int, 0444); MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); -#define CHAN2G(_freq, _idx) { \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} - -#define CHAN5G(_freq, _idx) { \ - .band = IEEE80211_BAND_5GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} - -static struct ieee80211_channel ath9k_2ghz_channels[] = { - CHAN2G(2412, 0), /* Channel 1 */ - CHAN2G(2417, 1), /* Channel 2 */ - CHAN2G(2422, 2), /* Channel 3 */ - CHAN2G(2427, 3), /* Channel 4 */ - CHAN2G(2432, 4), /* Channel 5 */ - CHAN2G(2437, 5), /* Channel 6 */ - CHAN2G(2442, 6), /* Channel 7 */ - CHAN2G(2447, 7), /* Channel 8 */ - CHAN2G(2452, 8), /* Channel 9 */ - CHAN2G(2457, 9), /* Channel 10 */ - CHAN2G(2462, 10), /* Channel 11 */ - CHAN2G(2467, 11), /* Channel 12 */ - CHAN2G(2472, 12), /* Channel 13 */ - CHAN2G(2484, 13), /* Channel 14 */ -}; - -static struct ieee80211_channel ath9k_5ghz_channels[] = { - /* _We_ call this UNII 1 */ - CHAN5G(5180, 14), /* Channel 36 */ - CHAN5G(5200, 15), /* Channel 40 */ - CHAN5G(5220, 16), /* Channel 44 */ - CHAN5G(5240, 17), /* Channel 48 */ - /* _We_ call this UNII 2 */ - CHAN5G(5260, 18), /* Channel 52 */ - CHAN5G(5280, 19), /* Channel 56 */ - CHAN5G(5300, 20), /* Channel 60 */ - CHAN5G(5320, 21), /* Channel 64 */ - /* _We_ call this "Middle band" */ - CHAN5G(5500, 22), /* Channel 100 */ - CHAN5G(5520, 23), /* Channel 104 */ - CHAN5G(5540, 24), /* Channel 108 */ - CHAN5G(5560, 25), /* Channel 112 */ - CHAN5G(5580, 26), /* Channel 116 */ - CHAN5G(5600, 27), /* Channel 120 */ - CHAN5G(5620, 28), /* Channel 124 */ - CHAN5G(5640, 29), /* Channel 128 */ - CHAN5G(5660, 30), /* Channel 132 */ - CHAN5G(5680, 31), /* Channel 136 */ - CHAN5G(5700, 32), /* Channel 140 */ - /* _We_ call this UNII 3 */ - CHAN5G(5745, 33), /* Channel 149 */ - CHAN5G(5765, 34), /* Channel 153 */ - CHAN5G(5785, 35), /* Channel 157 */ - CHAN5G(5805, 36), /* Channel 161 */ - CHAN5G(5825, 37), /* Channel 165 */ -}; - -/* Atheros hardware rate code addition for short premble */ -#define SHPCHECK(__hw_rate, __flags) \ - ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0) - -#define RATE(_bitrate, _hw_rate, _flags) { \ - .bitrate = (_bitrate), \ - .flags = (_flags), \ - .hw_value = (_hw_rate), \ - .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ -} - -static struct ieee80211_rate ath9k_legacy_rates[] = { - RATE(10, 0x1b, 0), - RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp : 0x1e */ - RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp: 0x1d */ - RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), /* short: 0x1c */ - RATE(60, 0x0b, 0), - RATE(90, 0x0f, 0), - RATE(120, 0x0a, 0), - RATE(180, 0x0e, 0), - RATE(240, 0x09, 0), - RATE(360, 0x0d, 0), - RATE(480, 0x08, 0), - RATE(540, 0x0c, 0), -}; - #ifdef CONFIG_MAC80211_LEDS static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = { { .throughput = 0 * 1024, .blink_time = 334 }, @@ -580,31 +493,6 @@ err: return -EINVAL; } -static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv) -{ - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { - priv->sbands[IEEE80211_BAND_2GHZ].channels = - ath9k_2ghz_channels; - priv->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; - priv->sbands[IEEE80211_BAND_2GHZ].n_channels = - ARRAY_SIZE(ath9k_2ghz_channels); - priv->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; - priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates); - } - - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { - priv->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_channels; - priv->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; - priv->sbands[IEEE80211_BAND_5GHZ].n_channels = - ARRAY_SIZE(ath9k_5ghz_channels); - priv->sbands[IEEE80211_BAND_5GHZ].bitrates = - ath9k_legacy_rates + 4; - priv->sbands[IEEE80211_BAND_5GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates) - 4; - } -} - static void ath9k_init_misc(struct ath9k_htc_priv *priv) { struct ath_common *common = ath9k_hw_common(priv->ah); @@ -629,6 +517,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, if (!ah) return -ENOMEM; + ah->dev = priv->dev; ah->hw_version.devid = devid; ah->hw_version.usbdev = drv_info; ah->ah_flags |= AH_USE_EEPROM; @@ -685,8 +574,8 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) priv->cur_beacon_conf.bslot[i] = NULL; + ath9k_cmn_init_channels_rates(common); ath9k_cmn_init_crypto(ah); - ath9k_init_channels_rates(priv); ath9k_init_misc(priv); ath9k_htc_init_btcoex(priv, product); @@ -766,18 +655,18 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &priv->sbands[IEEE80211_BAND_2GHZ]; + &common->sbands[IEEE80211_BAND_2GHZ]; if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &priv->sbands[IEEE80211_BAND_5GHZ]; + &common->sbands[IEEE80211_BAND_5GHZ]; if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) { if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) setup_ht_cap(priv, - &priv->sbands[IEEE80211_BAND_2GHZ].ht_cap); + &common->sbands[IEEE80211_BAND_2GHZ].ht_cap); if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) setup_ht_cap(priv, - &priv->sbands[IEEE80211_BAND_5GHZ].ht_cap); + &common->sbands[IEEE80211_BAND_5GHZ].ht_cap); } pBase = ath9k_htc_get_eeprom_base(priv); From b60d105242ac457dab057f676c8aaa20d1821b10 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 25 Feb 2014 14:48:52 +0100 Subject: [PATCH 331/414] ath9k: move setup_ht_cap to common-init and rename it to ath9k_cmn_setup_ht_cap Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/common-init.c | 58 ++++++++++++++++++ drivers/net/wireless/ath/ath9k/common-init.h | 2 + drivers/net/wireless/ath/ath9k/init.c | 62 +------------------- 3 files changed, 62 insertions(+), 60 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/common-init.c b/drivers/net/wireless/ath/ath9k/common-init.c index 1fa30c3b7d53..8e2fa0385c58 100644 --- a/drivers/net/wireless/ath/ath9k/common-init.c +++ b/drivers/net/wireless/ath/ath9k/common-init.c @@ -168,3 +168,61 @@ int ath9k_cmn_init_channels_rates(struct ath_common *common) return 0; } EXPORT_SYMBOL(ath9k_cmn_init_channels_rates); + +void ath9k_cmn_setup_ht_cap(struct ath_hw *ah, + struct ieee80211_sta_ht_cap *ht_info) +{ + struct ath_common *common = ath9k_hw_common(ah); + u8 tx_streams, rx_streams; + int i, max_streams; + + ht_info->ht_supported = true; + ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_SM_PS | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_LDPC) + ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) + ht_info->cap |= IEEE80211_HT_CAP_SGI_20; + + ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; + + if (AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) + max_streams = 1; + else if (AR_SREV_9462(ah)) + max_streams = 2; + else if (AR_SREV_9300_20_OR_LATER(ah)) + max_streams = 3; + else + max_streams = 2; + + if (AR_SREV_9280_20_OR_LATER(ah)) { + if (max_streams >= 2) + ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; + ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); + } + + /* set up supported mcs set */ + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams); + rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams); + + ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n", + tx_streams, rx_streams); + + if (tx_streams != rx_streams) { + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; + ht_info->mcs.tx_params |= ((tx_streams - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); + } + + for (i = 0; i < rx_streams; i++) + ht_info->mcs.rx_mask[i] = 0xff; + + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; +} +EXPORT_SYMBOL(ath9k_cmn_setup_ht_cap); diff --git a/drivers/net/wireless/ath/ath9k/common-init.h b/drivers/net/wireless/ath/ath9k/common-init.h index 8fc9049ad8b0..6e678ca8149b 100644 --- a/drivers/net/wireless/ath/ath9k/common-init.h +++ b/drivers/net/wireless/ath/ath9k/common-init.h @@ -15,3 +15,5 @@ */ int ath9k_cmn_init_channels_rates(struct ath_common *common); +void ath9k_cmn_setup_ht_cap(struct ath_hw *ah, + struct ieee80211_sta_ht_cap *ht_info); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index a6232cf0e998..88be85274b40 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -153,64 +153,6 @@ static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 cl /* Initialization */ /**************************/ -static void setup_ht_cap(struct ath_softc *sc, - struct ieee80211_sta_ht_cap *ht_info) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - u8 tx_streams, rx_streams; - int i, max_streams; - - ht_info->ht_supported = true; - ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_SM_PS | - IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_DSSSCCK40; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_LDPC) - ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) - ht_info->cap |= IEEE80211_HT_CAP_SGI_20; - - ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; - - if (AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) - max_streams = 1; - else if (AR_SREV_9462(ah)) - max_streams = 2; - else if (AR_SREV_9300_20_OR_LATER(ah)) - max_streams = 3; - else - max_streams = 2; - - if (AR_SREV_9280_20_OR_LATER(ah)) { - if (max_streams >= 2) - ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; - ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); - } - - /* set up supported mcs set */ - memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams); - rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams); - - ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n", - tx_streams, rx_streams); - - if (tx_streams != rx_streams) { - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; - ht_info->mcs.tx_params |= ((tx_streams - 1) << - IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); - } - - for (i = 0; i < rx_streams; i++) - ht_info->mcs.rx_mask[i] = 0xff; - - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; -} - static void ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { @@ -709,9 +651,9 @@ void ath9k_reload_chainmask_settings(struct ath_softc *sc) return; if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) - setup_ht_cap(sc, &common->sbands[IEEE80211_BAND_2GHZ].ht_cap); + ath9k_cmn_setup_ht_cap(ah, &common->sbands[IEEE80211_BAND_2GHZ].ht_cap); if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) - setup_ht_cap(sc, &common->sbands[IEEE80211_BAND_5GHZ].ht_cap); + ath9k_cmn_setup_ht_cap(ah, &common->sbands[IEEE80211_BAND_5GHZ].ht_cap); } static const struct ieee80211_iface_limit if_limits[] = { From e9fb588867091b25d413d6e70b4cfb8886edec89 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 25 Feb 2014 14:48:53 +0100 Subject: [PATCH 332/414] ath9k_htc: use ath9k_cmn_setup_ht_cap Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 50 ++----------------- 1 file changed, 3 insertions(+), 47 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 752586d8c3ba..5220f4644b1d 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -404,51 +404,6 @@ static const struct ath_bus_ops ath9k_usb_bus_ops = { .eeprom_read = ath_usb_eeprom_read, }; -static void setup_ht_cap(struct ath9k_htc_priv *priv, - struct ieee80211_sta_ht_cap *ht_info) -{ - struct ath_common *common = ath9k_hw_common(priv->ah); - u8 tx_streams, rx_streams; - int i; - - ht_info->ht_supported = true; - ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_SM_PS | - IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_DSSSCCK40; - - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) - ht_info->cap |= IEEE80211_HT_CAP_SGI_20; - - ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); - - ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; - - memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - - /* ath9k_htc supports only 1 or 2 stream devices */ - tx_streams = ath9k_cmn_count_streams(priv->ah->txchainmask, 2); - rx_streams = ath9k_cmn_count_streams(priv->ah->rxchainmask, 2); - - ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n", - tx_streams, rx_streams); - - if (tx_streams >= 2) - ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; - - if (tx_streams != rx_streams) { - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; - ht_info->mcs.tx_params |= ((tx_streams - 1) << - IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); - } - - for (i = 0; i < rx_streams; i++) - ht_info->mcs.rx_mask[i] = 0xff; - - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; -} - static int ath9k_init_queues(struct ath9k_htc_priv *priv) { struct ath_common *common = ath9k_hw_common(priv->ah); @@ -611,6 +566,7 @@ static const struct ieee80211_iface_combination if_comb = { static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, struct ieee80211_hw *hw) { + struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(priv->ah); struct base_eep_header *pBase; @@ -662,10 +618,10 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) { if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) - setup_ht_cap(priv, + ath9k_cmn_setup_ht_cap(ah, &common->sbands[IEEE80211_BAND_2GHZ].ht_cap); if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) - setup_ht_cap(priv, + ath9k_cmn_setup_ht_cap(ah, &common->sbands[IEEE80211_BAND_5GHZ].ht_cap); } From 91884fad852da4d00b1a5f5d57203e08884a3c1d Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 25 Feb 2014 14:48:54 +0100 Subject: [PATCH 333/414] ath9k-common: set maxstream=1 for ar9271 Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/common-init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/common-init.c b/drivers/net/wireless/ath/ath9k/common-init.c index 8e2fa0385c58..8775ab2db2ef 100644 --- a/drivers/net/wireless/ath/ath9k/common-init.c +++ b/drivers/net/wireless/ath/ath9k/common-init.c @@ -191,7 +191,7 @@ void ath9k_cmn_setup_ht_cap(struct ath_hw *ah, ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; - if (AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) + if (AR_SREV_9271(ah) || AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) max_streams = 1; else if (AR_SREV_9462(ah)) max_streams = 2; From b57ba3b2f7b00e1241c2ebabb0906321a4e64414 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 25 Feb 2014 14:48:55 +0100 Subject: [PATCH 334/414] ath9k: move ath9k_reload_chainmask_settings to common Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/common-init.c | 16 ++++++++++++++++ drivers/net/wireless/ath/ath9k/common-init.h | 1 + drivers/net/wireless/ath/ath9k/init.c | 16 +--------------- drivers/net/wireless/ath/ath9k/main.c | 2 +- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/common-init.c b/drivers/net/wireless/ath/ath9k/common-init.c index 8775ab2db2ef..a006c1499728 100644 --- a/drivers/net/wireless/ath/ath9k/common-init.c +++ b/drivers/net/wireless/ath/ath9k/common-init.c @@ -226,3 +226,19 @@ void ath9k_cmn_setup_ht_cap(struct ath_hw *ah, ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; } EXPORT_SYMBOL(ath9k_cmn_setup_ht_cap); + +void ath9k_cmn_reload_chainmask(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_HT)) + return; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) + ath9k_cmn_setup_ht_cap(ah, + &common->sbands[IEEE80211_BAND_2GHZ].ht_cap); + if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) + ath9k_cmn_setup_ht_cap(ah, + &common->sbands[IEEE80211_BAND_5GHZ].ht_cap); +} +EXPORT_SYMBOL(ath9k_cmn_reload_chainmask); diff --git a/drivers/net/wireless/ath/ath9k/common-init.h b/drivers/net/wireless/ath/ath9k/common-init.h index 6e678ca8149b..ac03fca5ffdd 100644 --- a/drivers/net/wireless/ath/ath9k/common-init.h +++ b/drivers/net/wireless/ath/ath9k/common-init.h @@ -17,3 +17,4 @@ int ath9k_cmn_init_channels_rates(struct ath_common *common); void ath9k_cmn_setup_ht_cap(struct ath_hw *ah, struct ieee80211_sta_ht_cap *ht_info); +void ath9k_cmn_reload_chainmask(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 88be85274b40..c0a4e866edca 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -642,20 +642,6 @@ static void ath9k_init_txpower_limits(struct ath_softc *sc) ah->curchan = curchan; } -void ath9k_reload_chainmask_settings(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - - if (!(ah->caps.hw_caps & ATH9K_HW_CAP_HT)) - return; - - if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) - ath9k_cmn_setup_ht_cap(ah, &common->sbands[IEEE80211_BAND_2GHZ].ht_cap); - if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) - ath9k_cmn_setup_ht_cap(ah, &common->sbands[IEEE80211_BAND_5GHZ].ht_cap); -} - static const struct ieee80211_iface_limit if_limits[] = { { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_P2P_CLIENT) | @@ -772,7 +758,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) &common->sbands[IEEE80211_BAND_5GHZ]; ath9k_init_wow(hw); - ath9k_reload_chainmask_settings(sc); + ath9k_cmn_reload_chainmask(ah); SET_IEEE80211_PERM_ADDR(hw, common->macaddr); } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 14a7524b4b50..42a18037004e 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2053,7 +2053,7 @@ static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant); ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant); - ath9k_reload_chainmask_settings(sc); + ath9k_cmn_reload_chainmask(ah); return 0; } From 6da2f4ad9d125a81ce53af9c522856039f62718b Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 25 Feb 2014 14:48:56 +0100 Subject: [PATCH 335/414] ath9k_htc: use ath9k_cmn_reload_chainmask Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 5220f4644b1d..a8f30dc448bb 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -616,14 +616,7 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &common->sbands[IEEE80211_BAND_5GHZ]; - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) { - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) - ath9k_cmn_setup_ht_cap(ah, - &common->sbands[IEEE80211_BAND_2GHZ].ht_cap); - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) - ath9k_cmn_setup_ht_cap(ah, - &common->sbands[IEEE80211_BAND_5GHZ].ht_cap); - } + ath9k_cmn_reload_chainmask(ah); pBase = ath9k_htc_get_eeprom_base(priv); if (pBase) { From 68ca395f94e932a2d9a775f2c103c5bce257e795 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Tue, 25 Feb 2014 20:30:26 +0100 Subject: [PATCH 336/414] brcmfmac: Make firmeware roaming a module param. Internal firmware roaming is enabled by default. This patch makes it possible to disable internal firmware roaming by specifying roamoff=1 as module param. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../wireless/brcm80211/brcmfmac/wl_cfg80211.c | 38 ++++++++++++------- .../wireless/brcm80211/brcmfmac/wl_cfg80211.h | 1 - 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index a54db9185747..474df2ce6e3b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -251,6 +252,10 @@ struct parsed_vndr_ies { struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT]; }; +static int brcmf_roamoff; +module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR); +MODULE_PARM_DESC(roamoff, "do not use internal roaming engine"); + /* Quarter dBm units to mW * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153 * Table is offset so the last entry is largest mW value that fits in @@ -4444,7 +4449,9 @@ static bool brcmf_is_linkdown(const struct brcmf_event_msg *e) u32 event = e->event_code; u16 flags = e->flags; - if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) { + if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) || + (event == BRCMF_E_DISASSOC_IND) || + ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) { brcmf_dbg(CONN, "Processing link down\n"); return true; } @@ -4688,6 +4695,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; struct ieee80211_channel *chan; s32 err = 0; + u16 reason; if (ifp->vif->mode == WL_MODE_AP) { err = brcmf_notify_connect_status_ap(cfg, ndev, e, data); @@ -4709,9 +4717,15 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, if (!brcmf_is_ibssmode(ifp->vif)) { brcmf_bss_connect_done(cfg, ndev, e, false); if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, - &ifp->vif->sme_state)) - cfg80211_disconnected(ndev, 0, NULL, 0, + &ifp->vif->sme_state)) { + reason = 0; + if (((e->event_code == BRCMF_E_DEAUTH_IND) || + (e->event_code == BRCMF_E_DISASSOC_IND)) && + (e->reason != WLAN_REASON_UNSPECIFIED)) + reason = e->reason; + cfg80211_disconnected(ndev, reason, NULL, 0, GFP_KERNEL); + } } brcmf_link_down(ifp->vif); brcmf_init_prof(ndev_to_prof(ndev)); @@ -4905,11 +4919,8 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg) cfg->scan_request = NULL; cfg->pwr_save = true; - cfg->roam_on = true; /* roam on & off switch. - we enable roam per default */ - cfg->active_scan = true; /* we do active scan for - specific scan per default */ - cfg->dongle_up = false; /* dongle is not up yet */ + cfg->active_scan = true; /* we do active scan per default */ + cfg->dongle_up = false; /* dongle is not up yet */ err = brcmf_init_priv_mem(cfg); if (err) return err; @@ -5029,7 +5040,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) } static s32 -brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout) +brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout) { s32 err = 0; __le32 roamtrigger[2]; @@ -5039,7 +5050,7 @@ brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout) * Setup timeout if Beacons are lost and roam is * off to report link down */ - if (roamvar) { + if (brcmf_roamoff) { err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout); if (err) { brcmf_err("bcn_timeout error (%d)\n", err); @@ -5051,8 +5062,9 @@ brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout) * Enable/Disable built-in roaming to allow supplicant * to take care of roaming */ - brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On"); - err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar); + brcmf_dbg(INFO, "Internal Roaming = %s\n", + brcmf_roamoff ? "Off" : "On"); + err = brcmf_fil_iovar_int_set(ifp, "roam_off", !!(brcmf_roamoff)); if (err) { brcmf_err("roam_off error (%d)\n", err); goto dongle_rom_out; @@ -5408,7 +5420,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) brcmf_dbg(INFO, "power save set to %s\n", (power_mode ? "enabled" : "disabled")); - err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT); + err = brcmf_dongle_roam(ifp, WL_BEACON_TIMEOUT); if (err) goto default_conf_out; err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index 254feed2860e..5715bb0708cf 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h @@ -402,7 +402,6 @@ struct brcmf_cfg80211_info { bool ibss_starter; bool pwr_save; bool dongle_up; - bool roam_on; bool scan_tried; u8 *dcmd_buf; u8 *extra_buf; From 5aa9f0ea18f3d5ec329a619b0bc54e214e02bc33 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 25 Feb 2014 20:30:27 +0100 Subject: [PATCH 337/414] brcmfmac: fix use of skb control buffer in SDIO driver part The SDIO driver has a 16-bit field defined in the skbuff control buffer. However, it is accessed as a u32 overwriting other control info. Another issue is that the field is not initialized for networking packets, but the control buffer content is unspecified as other networking layers can use it. Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Daniel (Deognyoun) Kim Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 631d5dc5b6d5..fa4ec69871c7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -2112,7 +2112,7 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus, memcpy(pkt_pad->data, pkt->data + pkt->len - tail_chop, tail_chop); - *(u32 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop; + *(u16 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop; skb_trim(pkt, pkt->len - tail_chop); __skb_queue_after(pktq, pkt, pkt_pad); } else { @@ -2159,7 +2159,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq, * already properly aligned and does not * need an sdpcm header. */ - if (*(u32 *)(pkt_next->cb) & ALIGN_SKB_FLAG) + if (*(u16 *)(pkt_next->cb) & ALIGN_SKB_FLAG) continue; /* align packet data pointer */ @@ -2223,11 +2223,11 @@ brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq) u8 *hdr; u32 dat_offset; u16 tail_pad; - u32 dummy_flags, chop_len; + u16 dummy_flags, chop_len; struct sk_buff *pkt_next, *tmp, *pkt_prev; skb_queue_walk_safe(pktq, pkt_next, tmp) { - dummy_flags = *(u32 *)(pkt_next->cb); + dummy_flags = *(u16 *)(pkt_next->cb); if (dummy_flags & ALIGN_SKB_FLAG) { chop_len = dummy_flags & ALIGN_SKB_CHOP_LEN_MASK; if (chop_len) { @@ -2709,6 +2709,8 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt) /* Priority based enq */ spin_lock_irqsave(&bus->txqlock, flags); + /* reset bus_flags in packet cb */ + *(u16 *)(pkt->cb) = 0; if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) { skb_pull(pkt, bus->tx_hdrlen); brcmf_err("out of bus->txq !!!\n"); From 44ff5660e5cf5ccb739e77a19d2ecf1144cf9e36 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 25 Feb 2014 20:30:28 +0100 Subject: [PATCH 338/414] brcmfmac: remove unused variable data_len from brcmf_sdio_bus_txdata() The local variable data_len is assigned but never used so get rid of it. Reviewed-by: Daniel (Deognyoun) Kim Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index fa4ec69871c7..ce1ee1e2f229 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -2686,15 +2686,13 @@ static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev) static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt) { int ret = -EBADE; - uint datalen, prec; + uint prec; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiodev->bus; ulong flags; - brcmf_dbg(TRACE, "Enter\n"); - - datalen = pkt->len; + brcmf_dbg(TRACE, "Enter: pkt: data %p len %d\n", pkt->data, pkt->len); /* Add space for the header */ skb_push(pkt, bus->tx_hdrlen); From 47ab4cd893f565a1093f316ec95babfa181e722a Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Tue, 25 Feb 2014 20:30:29 +0100 Subject: [PATCH 339/414] brcmfmac: Correct header debug dump for sdio tx hdrs. Reviewed-by: Arend Van Spriel Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index ce1ee1e2f229..ce997324370b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -2193,10 +2193,10 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq, if (BRCMF_BYTES_ON() && ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) || (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL))) - brcmf_dbg_hex_dump(true, pkt_next, hd_info.len, + brcmf_dbg_hex_dump(true, pkt_next->data, hd_info.len, "Tx Frame:\n"); else if (BRCMF_HDRS_ON()) - brcmf_dbg_hex_dump(true, pkt_next, + brcmf_dbg_hex_dump(true, pkt_next->data, head_pad + bus->tx_hdrlen, "Tx Header:\n"); } From 05c2c7671393edf4fd3870db4de14eb6fff276d5 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Tue, 25 Feb 2014 20:30:30 +0100 Subject: [PATCH 340/414] brcmfmac: de-init driver layers in correct order. First clean up fw signalling, before cleaning up the bus and proto layer. Old order can cause oops in some circumstances. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index d4d966beb840..7d28cd385092 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -1040,12 +1040,12 @@ void brcmf_detach(struct device *dev) brcmf_cfg80211_detach(drvr->config); + brcmf_fws_deinit(drvr); + brcmf_bus_detach(drvr); brcmf_proto_detach(drvr); - brcmf_fws_deinit(drvr); - brcmf_debugfs_detach(drvr); bus_if->drvr = NULL; kfree(drvr); From 71abdc00d54bb48ad2df4f9710ac661cf3aed30d Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Tue, 25 Feb 2014 20:30:31 +0100 Subject: [PATCH 341/414] brcmfmac: Minimize SDIO dpc scheduling. SDIO dpc scheduling is done (repeated) when counter is set. This counter gets decreased when dpc is finished. It is more efficient to set counter to 0 before the dpc is actullay run. This will minimize the frequency with which dpc is executed. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index ce997324370b..cc0f1ad8b42c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -3758,8 +3758,8 @@ static void brcmf_sdio_dataworker(struct work_struct *work) datawork); while (atomic_read(&bus->dpc_tskcnt)) { + atomic_set(&bus->dpc_tskcnt, 0); brcmf_sdio_dpc(bus); - atomic_dec(&bus->dpc_tskcnt); } } From 6f6c195b95136e0b2972b3c5213f6cd876c4fa8f Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Tue, 25 Feb 2014 20:30:32 +0100 Subject: [PATCH 342/414] brcmfmac: Remove immediate sleep support from SDIO. Immediate sleep support is an aggressive power saving option that has not been enabled in brcmfmac and is removed to simplify code. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../wireless/brcm80211/brcmfmac/dhd_sdio.c | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index cc0f1ad8b42c..04f5e32cfb48 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -304,7 +304,6 @@ struct rte_console { /* Flags for SDH calls */ #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) -#define BRCMF_IDLE_IMMEDIATE (-1) /* Enter idle immediately */ #define BRCMF_IDLE_ACTIVE 0 /* Do not request any SD clock change * when idle */ @@ -2662,16 +2661,6 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) data_ok(bus)) || PKT_AVAILABLE()) { atomic_inc(&bus->dpc_tskcnt); } - - /* If we're done for now, turn off clock request. */ - if ((bus->clkstate != CLK_PENDING) - && bus->idletime == BRCMF_IDLE_IMMEDIATE) { - bus->activity = false; - brcmf_dbg(SDIO, "idle state\n"); - sdio_claim_host(bus->sdiodev->func[1]); - brcmf_sdio_bus_sleep(bus, true, false); - sdio_release_host(bus->sdiodev->func[1]); - } } static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev) @@ -2948,15 +2937,6 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) } while (ret < 0 && retries++ < TXRETRIES); } - if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && - atomic_read(&bus->dpc_tskcnt) == 0) { - bus->activity = false; - sdio_claim_host(bus->sdiodev->func[1]); - brcmf_dbg(INFO, "idle\n"); - brcmf_sdio_clkctl(bus, CLK_NONE, true); - sdio_release_host(bus->sdiodev->func[1]); - } - if (ret) bus->sdcnt.tx_ctlerrs++; else From b6a8cf2cd8f1d17c850db0f591e3d349d417b40a Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Tue, 25 Feb 2014 20:30:33 +0100 Subject: [PATCH 343/414] brcmfmac: Small cleanup of redundant code. In time some of the code got redundant, without being noticed. This patch does not change any functionality, just removes redundant code. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 04f5e32cfb48..ac61419dc998 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -770,8 +770,6 @@ brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on) return err; } -#define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND) - #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) /* Turn backplane clock on or off */ @@ -870,7 +868,6 @@ static int brcmf_sdio_htclk(struct brcmf_sdio *bus, bool on, bool pendok) } #endif /* defined (DEBUG) */ - bus->activity = true; } else { clkreq = 0; @@ -2341,7 +2338,7 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes) cnt += i; /* In poll mode, need to check for other events */ - if (!bus->intr && cnt) { + if (!bus->intr) { /* Check device status, signal pending interrupt */ sdio_claim_host(bus->sdiodev->func[1]); ret = r_sdreg32(bus, &intstatus, @@ -2485,9 +2482,8 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) { u32 newstatus = 0; unsigned long intstatus; - uint rxlimit = bus->rxbound; /* Rx frames to read before resched */ uint txlimit = bus->txbound; /* Tx frames to send before resched */ - uint framecnt = 0; /* Temporary counter of tx/rx frames */ + uint framecnt; /* Temporary counter of tx/rx frames */ int err = 0, n; brcmf_dbg(TRACE, "Enter\n"); @@ -2585,11 +2581,10 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) intstatus &= ~I_HMB_FRAME_IND; /* On frame indication, read available frames */ - if (PKT_AVAILABLE() && bus->clkstate == CLK_AVAIL) { - framecnt = brcmf_sdio_readframes(bus, rxlimit); + if ((intstatus & I_HMB_FRAME_IND) && (bus->clkstate == CLK_AVAIL)) { + brcmf_sdio_readframes(bus, bus->rxbound); if (!bus->rxpending) intstatus &= ~I_HMB_FRAME_IND; - rxlimit -= min(framecnt, rxlimit); } /* Keep still-pending events for next scheduling */ @@ -2647,8 +2642,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) && data_ok(bus)) { framecnt = bus->rxpending ? min(txlimit, bus->txminmax) : txlimit; - framecnt = brcmf_sdio_sendfromq(bus, framecnt); - txlimit -= framecnt; + brcmf_sdio_sendfromq(bus, framecnt); } if (!brcmf_bus_ready(bus->sdiodev->bus_if) || (err != 0)) { @@ -2658,7 +2652,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) atomic_read(&bus->ipend) > 0 || (!atomic_read(&bus->fcstate) && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && - data_ok(bus)) || PKT_AVAILABLE()) { + data_ok(bus))) { atomic_inc(&bus->dpc_tskcnt); } } From 8acbea614a75bc2221a84f222dc32be0877861ce Mon Sep 17 00:00:00 2001 From: Paul Stewart Date: Tue, 25 Feb 2014 16:31:37 -0800 Subject: [PATCH 344/414] mwifiex: Track BA sequence number reset Some stations reset the sequence number for traffic-ids (TIDs) as they initiate a block-ACK session. In order to detect such behavior, mwifiex must note the starting sequence number given during the ADDBA request. If the first received sequence number after the ADDBA falls outside the receive window for this TID but after the the ADDBA starting sequence number, we can assume that this AP has reset its sequence number during the ADDBA. In this case we must adjust the input window backward to incorporate this received sequence number instead of ignoring it. Otherwise, we could fail to successfully retrieve an arbitrarily large number of downstream frames at the beginning of the block-ACK session. Signed-off-by: Paul Stewart Acked-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/11n_rxreorder.c | 27 +++++++++++++++----- drivers/net/wireless/mwifiex/11n_rxreorder.h | 3 ++- drivers/net/wireless/mwifiex/main.h | 1 + 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index eb17282b364f..35329cfc9a9b 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -279,6 +279,8 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, new_node->tid = tid; memcpy(new_node->ta, ta, ETH_ALEN); new_node->start_win = seq_num; + new_node->init_win = seq_num; + new_node->flags = 0; if (mwifiex_queuing_ra_based(priv)) { dev_dbg(priv->adapter->dev, @@ -298,11 +300,12 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, } if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM && - last_seq >= new_node->start_win) + last_seq >= new_node->start_win) { new_node->start_win = last_seq + 1; + new_node->flags |= RXREOR_INIT_WINDOW_SHIFT; + } new_node->win_size = win_size; - new_node->flags = 0; new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size, GFP_KERNEL); @@ -452,6 +455,7 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, struct mwifiex_rx_reorder_tbl *tbl; int start_win, end_win, win_size; u16 pkt_index; + bool init_window_shift = false; tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta); if (!tbl) { @@ -466,18 +470,29 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, start_win = tbl->start_win; win_size = tbl->win_size; end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1); + if (tbl->flags & RXREOR_INIT_WINDOW_SHIFT) { + init_window_shift = true; + tbl->flags &= ~RXREOR_INIT_WINDOW_SHIFT; + } mod_timer(&tbl->timer_context.timer, jiffies + msecs_to_jiffies(MIN_FLUSH_TIMER_MS * win_size)); - /* - * If seq_num is less then starting win then ignore and drop the - * packet - */ if (tbl->flags & RXREOR_FORCE_NO_DROP) { dev_dbg(priv->adapter->dev, "RXREOR_FORCE_NO_DROP when HS is activated\n"); tbl->flags &= ~RXREOR_FORCE_NO_DROP; + } else if (init_window_shift && seq_num < start_win && + seq_num >= tbl->init_win) { + dev_dbg(priv->adapter->dev, + "Sender TID sequence number reset %d->%d for SSN %d\n", + start_win, seq_num, tbl->init_win); + tbl->start_win = start_win = seq_num; + end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1); } else { + /* + * If seq_num is less then starting win then ignore and drop + * the packet + */ if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) { if (seq_num >= ((start_win + TWOPOW11) & (MAX_TID_VALUE - 1)) && diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.h b/drivers/net/wireless/mwifiex/11n_rxreorder.h index 4064041ac852..0fc76e4a60f8 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.h +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.h @@ -42,7 +42,8 @@ #define BA_SETUP_PACKET_OFFSET 16 enum mwifiex_rxreor_flags { - RXREOR_FORCE_NO_DROP = 1<<0, + RXREOR_FORCE_NO_DROP = 1<<0, + RXREOR_INIT_WINDOW_SHIFT = 1<<1, }; static inline void mwifiex_reset_11n_rx_seq_num(struct mwifiex_private *priv) diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 407f8eada720..cb1148f0de69 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -575,6 +575,7 @@ struct mwifiex_rx_reorder_tbl { struct list_head list; int tid; u8 ta[ETH_ALEN]; + int init_win; int start_win; int win_size; void **rx_reorder_ptr; From 7fbdaa2a27583664ff700843269bc3ca14e4e1b5 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 26 Feb 2014 10:03:43 +0100 Subject: [PATCH 345/414] ath9k: remove unused listen_interval and sleepduration. this variable never changed. Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/beacon.c | 21 +++++++-------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index e703ddad7ecf..f995c374a9b4 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -410,7 +410,6 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw, struct ath_beacon_config { int beacon_interval; - u16 listen_interval; u16 dtim_period; u16 bmiss_timeout; u8 dtim_count; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 6569528753af..02eb4f10332b 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -519,7 +519,7 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc, struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_beacon_state bs; - int dtim_intval, sleepduration; + int dtim_intval; u32 nexttbtt = 0, intval; u64 tsf; @@ -538,7 +538,6 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc, * last beacon we received (which may be none). */ dtim_intval = intval * conf->dtim_period; - sleepduration = conf->listen_interval * intval; /* * Pull nexttbtt forward to reflect the current @@ -560,16 +559,11 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc, * need calculate based on the beacon interval. Note that we clamp the * result to at most 15 beacons. */ - if (sleepduration > intval) { - bs.bs_bmissthreshold = conf->listen_interval * - ATH_DEFAULT_BMISS_LIMIT / 2; - } else { - bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval); - if (bs.bs_bmissthreshold > 15) - bs.bs_bmissthreshold = 15; - else if (bs.bs_bmissthreshold <= 0) - bs.bs_bmissthreshold = 1; - } + bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval); + if (bs.bs_bmissthreshold > 15) + bs.bs_bmissthreshold = 15; + else if (bs.bs_bmissthreshold <= 0) + bs.bs_bmissthreshold = 1; /* * Calculate sleep duration. The configuration is given in ms. @@ -581,7 +575,7 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc, */ bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100), - sleepduration)); + intval)); if (bs.bs_sleepduration > bs.bs_dtimperiod) bs.bs_sleepduration = bs.bs_dtimperiod; @@ -677,7 +671,6 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc, cur_conf->beacon_interval = bss_conf->beacon_int; cur_conf->dtim_period = bss_conf->dtim_period; - cur_conf->listen_interval = 1; cur_conf->dtim_count = 1; cur_conf->ibss_creator = bss_conf->ibss_creator; cur_conf->bmiss_timeout = From 527492eefcee253e33bbe79bcfef6bedf9935492 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 26 Feb 2014 10:03:44 +0100 Subject: [PATCH 346/414] ath9k_htc: remove unused variable sleepduration sleepduration is always = intval. Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- .../net/wireless/ath/ath9k/htc_drv_beacon.c | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 8b5757734596..a00ddb9e737e 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -69,7 +69,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, struct ath_common *common = ath9k_hw_common(priv->ah); struct ath9k_beacon_state bs; enum ath9k_int imask = 0; - int dtimperiod, dtimcount, sleepduration; + int dtimperiod, dtimcount; int bmiss_timeout; u32 nexttbtt = 0, intval, tsftu; __be32 htc_imask = 0; @@ -94,10 +94,6 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, if (dtimcount >= dtimperiod) /* NB: sanity check */ dtimcount = 0; - sleepduration = intval; - if (sleepduration <= 0) - sleepduration = intval; - /* * Pull nexttbtt forward to reflect the current * TSF and calculate dtim state for the result. @@ -128,15 +124,11 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, * need calculate based on the beacon interval. Note that we clamp the * result to at most 15 beacons. */ - if (sleepduration > intval) { - bs.bs_bmissthreshold = ATH_DEFAULT_BMISS_LIMIT / 2; - } else { - bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval); - if (bs.bs_bmissthreshold > 15) - bs.bs_bmissthreshold = 15; - else if (bs.bs_bmissthreshold <= 0) - bs.bs_bmissthreshold = 1; - } + bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval); + if (bs.bs_bmissthreshold > 15) + bs.bs_bmissthreshold = 15; + else if (bs.bs_bmissthreshold <= 0) + bs.bs_bmissthreshold = 1; /* * Calculate sleep duration. The configuration is given in ms. @@ -148,7 +140,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, */ bs.bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100), - sleepduration)); + intval)); if (bs.bs_sleepduration > bs.bs_dtimperiod) bs.bs_sleepduration = bs.bs_dtimperiod; From 2259ba38a5c545bb54ee0fd9b07cb1828a2849d6 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 26 Feb 2014 10:04:44 +0100 Subject: [PATCH 347/414] ath9k_htc: add function ath9k_regwrite_multi ... to remove duplicate code Signed-off-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 53 ++++++++----------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index a8f30dc448bb..b22fb64403d9 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -256,6 +256,25 @@ static void ath9k_multi_regread(void *hw_priv, u32 *addr, } } +static void ath9k_regwrite_multi(struct ath_common *common) +{ + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + u32 rsp_status; + int r; + + r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, + (u8 *) &priv->wmi->multi_write, + sizeof(struct register_write) * priv->wmi->multi_write_idx, + (u8 *) &rsp_status, sizeof(rsp_status), + 100); + if (unlikely(r)) { + ath_dbg(common, WMI, + "REGISTER WRITE FAILED, multi len: %d\n", + priv->wmi->multi_write_idx); + } + priv->wmi->multi_write_idx = 0; +} + static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset) { struct ath_hw *ah = (struct ath_hw *) hw_priv; @@ -282,8 +301,6 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset) struct ath_hw *ah = (struct ath_hw *) hw_priv; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; - u32 rsp_status; - int r; mutex_lock(&priv->wmi->multi_write_mutex); @@ -296,19 +313,8 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset) priv->wmi->multi_write_idx++; /* If the buffer is full, send it out. */ - if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) { - r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, - (u8 *) &priv->wmi->multi_write, - sizeof(struct register_write) * priv->wmi->multi_write_idx, - (u8 *) &rsp_status, sizeof(rsp_status), - 100); - if (unlikely(r)) { - ath_dbg(common, WMI, - "REGISTER WRITE FAILED, multi len: %d\n", - priv->wmi->multi_write_idx); - } - priv->wmi->multi_write_idx = 0; - } + if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) + ath9k_regwrite_multi(common); mutex_unlock(&priv->wmi->multi_write_mutex); } @@ -339,26 +345,13 @@ static void ath9k_regwrite_flush(void *hw_priv) struct ath_hw *ah = (struct ath_hw *) hw_priv; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; - u32 rsp_status; - int r; atomic_dec(&priv->wmi->mwrite_cnt); mutex_lock(&priv->wmi->multi_write_mutex); - if (priv->wmi->multi_write_idx) { - r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, - (u8 *) &priv->wmi->multi_write, - sizeof(struct register_write) * priv->wmi->multi_write_idx, - (u8 *) &rsp_status, sizeof(rsp_status), - 100); - if (unlikely(r)) { - ath_dbg(common, WMI, - "REGISTER WRITE FAILED, multi len: %d\n", - priv->wmi->multi_write_idx); - } - priv->wmi->multi_write_idx = 0; - } + if (priv->wmi->multi_write_idx) + ath9k_regwrite_multi(common); mutex_unlock(&priv->wmi->multi_write_mutex); } From c98db0bec72ac7ef127119c1ed962d6f56802b12 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 26 Feb 2014 13:32:32 +0100 Subject: [PATCH 348/414] brcmfmac: Use atomic functions for intstatus update. The intstatus in sdio code can be updated from different threads. To protect intstatus access, atomic functions are used. The loop was replaced using atomic_set_mask(). Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../wireless/brcm80211/brcmfmac/dhd_sdio.c | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index ac61419dc998..0ccb7affeb04 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -2449,7 +2449,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) struct brcmf_core *buscore; u32 addr; unsigned long val; - int n, ret; + int ret; buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV); addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus); @@ -2457,7 +2457,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret); bus->sdcnt.f1regdata++; if (ret != 0) - val = 0; + return ret; val &= bus->hostintmask; atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE)); @@ -2466,13 +2466,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) if (val) { brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret); bus->sdcnt.f1regdata++; - } - - if (ret) { - atomic_set(&bus->intstatus, 0); - } else if (val) { - for_each_set_bit(n, &val, 32) - set_bit(n, (unsigned long *)&bus->intstatus.counter); + atomic_set_mask(val, &bus->intstatus); } return ret; @@ -2484,7 +2478,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) unsigned long intstatus; uint txlimit = bus->txbound; /* Tx frames to send before resched */ uint framecnt; /* Temporary counter of tx/rx frames */ - int err = 0, n; + int err = 0; brcmf_dbg(TRACE, "Enter\n"); @@ -2588,10 +2582,8 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) } /* Keep still-pending events for next scheduling */ - if (intstatus) { - for_each_set_bit(n, &intstatus, 32) - set_bit(n, (unsigned long *)&bus->intstatus.counter); - } + if (intstatus) + atomic_set_mask(intstatus, &bus->intstatus); brcmf_sdio_clrintr(bus); From 1647f12f1b511c2629b9b8d23061aa54ad8a9795 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 27 Feb 2014 16:20:40 +0200 Subject: [PATCH 349/414] wil6210: Tx management frame Implement management frame passing. In order to receive frame on the other side, remain_on_channel() should be implemented as well Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 72 +++++++++++++++++++++ drivers/net/wireless/ath/wil6210/wil6210.h | 1 + drivers/net/wireless/ath/wil6210/wmi.c | 32 +++++++++ 3 files changed, 105 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 5b340769d5bb..204c7c82b1b5 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -352,6 +352,40 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy, return rc; } +static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, + u64 *cookie) +{ + const u8 *buf = params->buf; + size_t len = params->len; + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + struct ieee80211_mgmt *mgmt_frame = (void *)buf; + struct wmi_sw_tx_req_cmd *cmd; + struct { + struct wil6210_mbox_hdr_wmi wmi; + struct wmi_sw_tx_complete_event evt; + } __packed evt; + + cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN); + cmd->len = cpu_to_le16(len); + memcpy(cmd->payload, buf, len); + + rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len, + WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); + if (rc == 0) + rc = evt.evt.status; + + kfree(cmd); + + return rc; +} + static int wil_cfg80211_set_channel(struct wiphy *wiphy, struct cfg80211_chan_def *chandef) { @@ -402,6 +436,41 @@ static int wil_cfg80211_set_default_key(struct wiphy *wiphy, return 0; } +static int wil_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, + u64 *cookie) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + + /* TODO: handle duration */ + wil_info(wil, "%s(%d, %d ms)\n", __func__, chan->center_freq, duration); + + rc = wmi_set_channel(wil, chan->hw_value); + if (rc) + return rc; + + rc = wmi_rxon(wil, true); + + return rc; +} + +static int wil_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + + wil_info(wil, "%s()\n", __func__); + + rc = wmi_rxon(wil, false); + + return rc; +} + static int wil_fix_bcon(struct wil6210_priv *wil, struct cfg80211_beacon_data *bcon) { @@ -510,6 +579,9 @@ static struct cfg80211_ops wil_cfg80211_ops = { .disconnect = wil_cfg80211_disconnect, .change_virtual_intf = wil_cfg80211_change_iface, .get_station = wil_cfg80211_get_station, + .remain_on_channel = wil_remain_on_channel, + .cancel_remain_on_channel = wil_cancel_remain_on_channel, + .mgmt_tx = wil_cfg80211_mgmt_tx, .set_monitor_channel = wil_cfg80211_set_channel, .add_key = wil_cfg80211_add_key, .del_key = wil_cfg80211_del_key, diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 1f91eaf95bbe..0d7fba4f09e2 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -357,6 +357,7 @@ int wmi_echo(struct wil6210_priv *wil); int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie); int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring); int wmi_p2p_cfg(struct wil6210_priv *wil, int channel); +int wmi_rxon(struct wil6210_priv *wil, bool on); int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r); int wil6210_init_irq(struct wil6210_priv *wil, int irq); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 063963ee422a..d65da5590c5f 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -893,6 +893,38 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) return rc; } +/** + * wmi_rxon - turn radio on/off + * @on: turn on if true, off otherwise + * + * Only switch radio. Channel should be set separately. + * No timeout for rxon - radio turned on forever unless some other call + * turns it off + */ +int wmi_rxon(struct wil6210_priv *wil, bool on) +{ + int rc; + struct { + struct wil6210_mbox_hdr_wmi wmi; + struct wmi_listen_started_event evt; + } __packed reply; + + wil_info(wil, "%s(%s)\n", __func__, on ? "on" : "off"); + + if (on) { + rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0, + WMI_LISTEN_STARTED_EVENTID, + &reply, sizeof(reply), 100); + if ((rc == 0) && (reply.evt.status != WMI_FW_STATUS_SUCCESS)) + rc = -EINVAL; + } else { + rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0, + WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 20); + } + + return rc; +} + int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) { struct wireless_dev *wdev = wil->wdev; From 3a85543e9f9f6821d27d33d436f2bad96e5166df Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 27 Feb 2014 16:20:41 +0200 Subject: [PATCH 350/414] wil6210: [DEBUG] allow to query Rx and all Tx VRING descriptors Expand debug capabilities to query all Tx/Rx descriptors. Usefull to analyse various hardware/software stall situations. Printed is whole descriptor content and the frame itself. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 40 +++++++++++++++++----- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 1caa31992a7e..74bb427ce303 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -26,6 +26,8 @@ /* Nasty hack. Better have per device instances */ static u32 mem_addr; static u32 dbg_txdesc_index; +static u32 dbg_vring_index; /* 25 for Rx, 0..24 for Tx */ +#define WIL_DBG_VRING_INDEX_RX (WIL6210_MAX_TX_RINGS + 1) static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, const char *name, struct vring *vring) @@ -390,25 +392,39 @@ static const struct file_operations fops_reset = { .write = wil_write_file_reset, .open = simple_open, }; -/*---------Tx descriptor------------*/ +/*---------Tx/Rx descriptor------------*/ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; - struct vring *vring = &(wil->vring_tx[0]); + struct vring *vring; + if (dbg_vring_index <= WIL6210_MAX_TX_RINGS) + vring = &(wil->vring_tx[dbg_vring_index]); + else + vring = &wil->vring_rx; if (!vring->va) { - seq_printf(s, "No Tx VRING\n"); + if (dbg_vring_index <= WIL6210_MAX_TX_RINGS) + seq_printf(s, "No Tx[%2d] VRING\n", dbg_vring_index); + else + seq_puts(s, "No Rx VRING\n"); return 0; } if (dbg_txdesc_index < vring->size) { + /* use struct vring_tx_desc for Rx as well, + * only field used, .dma.length, is the same + */ volatile struct vring_tx_desc *d = &(vring->va[dbg_txdesc_index].tx); volatile u32 *u = (volatile u32 *)d; struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb; - seq_printf(s, "Tx[%3d] = {\n", dbg_txdesc_index); + if (dbg_vring_index <= WIL6210_MAX_TX_RINGS) + seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_vring_index, + dbg_txdesc_index); + else + seq_printf(s, "Rx[%3d] = {\n", dbg_txdesc_index); seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n", u[0], u[1], u[2], u[3]); seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n", @@ -439,8 +455,13 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) } seq_printf(s, "}\n"); } else { - seq_printf(s, "TxDesc index (%d) >= size (%d)\n", - dbg_txdesc_index, vring->size); + if (dbg_vring_index <= WIL6210_MAX_TX_RINGS) + seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n", + dbg_vring_index, dbg_txdesc_index, + vring->size); + else + seq_printf(s, "RxDesc index (%d) >= size (%d)\n", + dbg_txdesc_index, vring->size); } return 0; @@ -581,9 +602,12 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox); debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring); - debugfs_create_file("txdesc", S_IRUGO, dbg, wil, &fops_txdesc); - debugfs_create_u32("txdesc_index", S_IRUGO | S_IWUSR, dbg, + debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc); + debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg, &dbg_txdesc_index); + debugfs_create_u32("vring_index", S_IRUGO | S_IWUSR, dbg, + &dbg_vring_index); + debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf); debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid); debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg, From 59f7c0a9577a965e279a0c15858480100f28f03d Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 27 Feb 2014 16:20:42 +0200 Subject: [PATCH 351/414] wil6210: [DEBUG] Improve Vring printing Print '_' for the 'idle' descriptors - this makes vring representation more visible. Also, for the Tx side, differentiate descriptors having associated skb's - print ones with skb as 'H' and without as 'h'. Good to represent scattered frames. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 74bb427ce303..6fdab1a73e9e 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -30,7 +30,8 @@ static u32 dbg_vring_index; /* 25 for Rx, 0..24 for Tx */ #define WIL_DBG_VRING_INDEX_RX (WIL6210_MAX_TX_RINGS + 1) static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, - const char *name, struct vring *vring) + const char *name, struct vring *vring, + char _s, char _h) { void __iomem *x = wmi_addr(wil, vring->hwtail); @@ -52,8 +53,8 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, volatile struct vring_tx_desc *d = &vring->va[i].tx; if ((i % 64) == 0 && (i != 0)) seq_printf(s, "\n"); - seq_printf(s, "%s", (d->dma.status & BIT(0)) ? - "S" : (vring->ctx[i].skb ? "H" : "h")); + seq_printf(s, "%c", (d->dma.status & BIT(0)) ? + _s : (vring->ctx[i].skb ? _h : 'h')); } seq_printf(s, "\n"); } @@ -65,14 +66,14 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) uint i; struct wil6210_priv *wil = s->private; - wil_print_vring(s, wil, "rx", &wil->vring_rx); + wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_'); for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { struct vring *vring = &(wil->vring_tx[i]); if (vring->va) { char name[10]; snprintf(name, sizeof(name), "tx_%2d", i); - wil_print_vring(s, wil, name, vring); + wil_print_vring(s, wil, name, vring, '_', 'H'); } } From 3df2cd361871eb4636c8ce9cf97e6899c90c588c Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 27 Feb 2014 16:20:43 +0200 Subject: [PATCH 352/414] wil6210: multiple connect - initial support Enable multiple (up to 8 - HW/FW limitation) simultaneous connections. Each connection has its own CID (connection ID) that describes chip's beam-forming entity. Tx Vring should refer to correct CID for frame to reach its destination. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 8 +++- drivers/net/wireless/ath/wil6210/debugfs.c | 45 ++++++++++++++++++++ drivers/net/wireless/ath/wil6210/main.c | 24 ++++++++++- drivers/net/wireless/ath/wil6210/txrx.c | 47 +++++++++++++++++---- drivers/net/wireless/ath/wil6210/wil6210.h | 22 +++++++++- drivers/net/wireless/ath/wil6210/wmi.c | 17 ++++++-- 6 files changed, 148 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 204c7c82b1b5..fa713ef8dc95 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -110,15 +110,19 @@ static int wil_cfg80211_get_station(struct wiphy *wiphy, { struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; + + int cid = wil_find_cid(wil, mac); struct wmi_notify_req_cmd cmd = { - .cid = 0, + .cid = cid, .interval_usec = 0, }; - if (memcmp(mac, wil->dst_addr[0], ETH_ALEN)) + wil_info(wil, "%s(%pM) CID %d\n", __func__, mac, cid); + if (cid < 0) return -ENOENT; /* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */ + /* TODO: keep stats per CID */ rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd), WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20); if (rc) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 6fdab1a73e9e..f12aa0b1e1df 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -71,8 +71,13 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { struct vring *vring = &(wil->vring_tx[i]); if (vring->va) { + int cid = wil->vring2cid_tid[i][0]; + int tid = wil->vring2cid_tid[i][1]; char name[10]; snprintf(name, sizeof(name), "tx_%2d", i); + + seq_printf(s, "\n%pM CID %d TID %d\n", + wil->sta[cid].addr, cid, tid); wil_print_vring(s, wil, name, vring, '_', 'H'); } } @@ -592,6 +597,45 @@ static const struct file_operations fops_temp = { .llseek = seq_lseek, }; +/*---------Station matrix------------*/ + +static int wil_sta_debugfs_show(struct seq_file *s, void *data) +{ + struct wil6210_priv *wil = s->private; + int i; + + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { + struct wil_sta_info *p = &wil->sta[i]; + char *status = "unknown"; + switch (p->status) { + case wil_sta_unused: + status = "unused "; + break; + case wil_sta_conn_pending: + status = "pending "; + break; + case wil_sta_connected: + status = "connected"; + break; + } + seq_printf(s, "[%d] %pM %s\n", i, p->addr, status); + } + + return 0; +} + +static int wil_sta_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_sta_debugfs_show, inode->i_private); +} + +static const struct file_operations fops_sta = { + .open = wil_sta_seq_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek, +}; + /*----------------*/ int wil6210_debugfs_init(struct wil6210_priv *wil) { @@ -603,6 +647,7 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox); debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring); + debugfs_create_file("stations", S_IRUGO, dbg, wil, &fops_sta); debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc); debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg, &dbg_txdesc_index); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index fd30cddd5882..f68481de0ad7 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -113,14 +113,20 @@ static void wil_connect_worker(struct work_struct *work) rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, cid, 0); wil->pending_connect_cid = -1; - if (rc == 0) + if (rc == 0) { + wil->sta[cid].status = wil_sta_connected; wil_link_on(wil); + } else { + wil->sta[cid].status = wil_sta_unused; + } } int wil_priv_init(struct wil6210_priv *wil) { wil_dbg_misc(wil, "%s()\n", __func__); + memset(wil->sta, 0, sizeof(wil->sta)); + mutex_init(&wil->mutex); mutex_init(&wil->wmi_mutex); @@ -370,3 +376,19 @@ int wil_down(struct wil6210_priv *wil) return rc; } + +int wil_find_cid(struct wil6210_priv *wil, const u8 *mac) +{ + int i; + int rc = -ENOENT; + + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { + if ((wil->sta[i].status != wil_sta_unused) && + (0 == memcmp(wil->sta[i].addr, mac, ETH_ALEN))) { + rc = i; + break; + } + } + + return rc; +} diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 0b0975d88b43..eb60023fa217 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -613,6 +613,9 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, } vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); + wil->vring2cid_tid[id][0] = cid; + wil->vring2cid_tid[id][1] = tid; + return 0; out_free: wil_vring_free(wil, vring, 1); @@ -634,10 +637,27 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, struct sk_buff *skb) { - struct vring *v = &wil->vring_tx[0]; + int i; + struct ethhdr *eth = (void *)skb->data; + int cid = wil_find_cid(wil, eth->h_dest); - if (v->va) - return v; + if (cid < 0) + return NULL; + + /* TODO: fix for multiple TID */ + for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) { + if (wil->vring2cid_tid[i][0] == cid) { + struct vring *v = &wil->vring_tx[i]; + wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n", + __func__, eth->h_dest, i); + if (v->va) { + return v; + } else { + wil_dbg_txrx(wil, "vring[%d] not valid\n", i); + return NULL; + } + } + } return NULL; } @@ -740,9 +760,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, } _d = &(vring->va[i].tx); - /* FIXME FW can accept only unicast frames for the peer */ - memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN); - pa = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); @@ -836,6 +853,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct wil6210_priv *wil = ndev_to_wil(ndev); + struct ethhdr *eth = (void *)skb->data; struct vring *vring; int rc; @@ -854,9 +872,22 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) } /* find vring */ - vring = wil_find_tx_vring(wil, skb); + if (is_unicast_ether_addr(eth->h_dest)) { + vring = wil_find_tx_vring(wil, skb); + } else { + int i = 0; + /* TODO: duplicate for all CID's */ + vring = &wil->vring_tx[i]; + if (vring->va) { + int cid = wil->vring2cid_tid[i][0]; + /* FIXME FW can accept only unicast frames */ + memcpy(skb->data, wil->sta[cid].addr, ETH_ALEN); + } else { + vring = NULL; + } + } if (!vring) { - wil_err(wil, "No Tx VRING available\n"); + wil_err(wil, "No Tx VRING found for %pM\n", eth->h_dest); goto drop; } /* set up vring entry */ diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 0d7fba4f09e2..38df203f723d 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -226,6 +226,24 @@ struct wil6210_stats { u16 peer_tx_sector; }; +enum wil_sta_status { + wil_sta_unused = 0, + wil_sta_conn_pending = 1, + wil_sta_connected = 2, +}; +/** + * struct wil_sta_info - data for peer + * + * Peer identified by its CID (connection ID) + * NIC performs beam forming for each peer; + * if no beam forming done, frame exchange is not + * possible. + */ +struct wil_sta_info { + u8 addr[ETH_ALEN]; + enum wil_sta_status status; +}; + struct wil6210_priv { struct pci_dev *pdev; int n_msi; @@ -267,7 +285,8 @@ struct wil6210_priv { /* DMA related */ struct vring vring_rx; struct vring vring_tx[WIL6210_MAX_TX_RINGS]; - u8 dst_addr[WIL6210_MAX_TX_RINGS][ETH_ALEN]; + u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */ + struct wil_sta_info sta[WIL6210_MAX_CID]; /* scan */ struct cfg80211_scan_request *scan_request; @@ -334,6 +353,7 @@ void wil_link_off(struct wil6210_priv *wil); int wil_up(struct wil6210_priv *wil); int wil_down(struct wil6210_priv *wil); void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); +int wil_find_cid(struct wil6210_priv *wil, const u8 *mac); void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr); void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index d65da5590c5f..2d602901675d 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -384,6 +384,11 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) evt->assoc_req_len, evt->assoc_resp_len); return; } + if (evt->cid >= WIL6210_MAX_CID) { + wil_err(wil, "Connect CID invalid : %d\n", evt->cid); + return; + } + ch = evt->channel + 1; wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n", evt->bssid, ch, evt->cid); @@ -439,7 +444,8 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) /* FIXME FW can transmit only ucast frames to peer */ /* FIXME real ring_id instead of hard coded 0 */ - memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN); + memcpy(wil->sta[evt->cid].addr, evt->bssid, ETH_ALEN); + wil->sta[evt->cid].status = wil_sta_conn_pending; wil->pending_connect_cid = evt->cid; queue_work(wil->wmi_wq_conn, &wil->connect_worker); @@ -449,14 +455,19 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, void *d, int len) { struct wmi_disconnect_event *evt = d; + int cid = wil_find_cid(wil, evt->bssid); - wil_dbg_wmi(wil, "Disconnect %pM reason %d proto %d wmi\n", - evt->bssid, + wil_dbg_wmi(wil, "Disconnect %pM CID %d reason %d proto %d wmi\n", + evt->bssid, cid, evt->protocol_reason_status, evt->disconnect_reason); wil->sinfo_gen++; + /* TODO: fix for multiple connections */ + wil6210_disconnect(wil, evt->bssid); + if (cid >= 0) + wil->sta[cid].status = wil_sta_unused; } static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) From b4490f423c0e61b77461be6557c62e533b8c60e3 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 27 Feb 2014 16:20:44 +0200 Subject: [PATCH 353/414] wil6210: Block ACK When running multiple connections, hardware can't do BACK reordering and it should be done on the host. Model after mac80211's implementation. Drop RCU for now; to be re-added when BACK will be stabilized BACK handshaking is not implemented yet in the hardware, pretend it was done to support the way FW operating Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/Makefile | 1 + drivers/net/wireless/ath/wil6210/debugfs.c | 25 ++- drivers/net/wireless/ath/wil6210/main.c | 12 +- drivers/net/wireless/ath/wil6210/rx_reorder.c | 177 ++++++++++++++++++ drivers/net/wireless/ath/wil6210/txrx.c | 6 +- drivers/net/wireless/ath/wil6210/txrx.h | 7 + drivers/net/wireless/ath/wil6210/wil6210.h | 47 +++++ drivers/net/wireless/ath/wil6210/wmi.c | 22 ++- 8 files changed, 290 insertions(+), 7 deletions(-) create mode 100644 drivers/net/wireless/ath/wil6210/rx_reorder.c diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index 990dd42ae79e..c7a3465fd02a 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -9,6 +9,7 @@ wil6210-y += wmi.o wil6210-y += interrupt.o wil6210-y += txrx.o wil6210-y += debug.o +wil6210-y += rx_reorder.o wil6210-$(CONFIG_WIL6210_TRACING) += trace.o # for tracing framework to find trace.h diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index f12aa0b1e1df..729e774ee96d 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -598,11 +598,24 @@ static const struct file_operations fops_temp = { }; /*---------Station matrix------------*/ +static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) +{ + int i; + u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size; + seq_printf(s, "0x%03x [", r->head_seq_num); + for (i = 0; i < r->buf_size; i++) { + if (i == index) + seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|'); + else + seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_'); + } + seq_puts(s, "]\n"); +} static int wil_sta_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; - int i; + int i, tid; for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { struct wil_sta_info *p = &wil->sta[i]; @@ -619,6 +632,16 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data) break; } seq_printf(s, "[%d] %pM %s\n", i, p->addr, status); + + if (p->status == wil_sta_connected) { + for (tid = 0; tid < WIL_STA_TID_NUM; tid++) { + struct wil_tid_ampdu_rx *r = p->tid_rx[tid]; + if (r) { + seq_printf(s, "[%2d] ", tid); + wil_print_rxtid(s, r); + } + } + } } return 0; diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index f68481de0ad7..38906f1bc769 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -18,6 +18,7 @@ #include #include "wil6210.h" +#include "txrx.h" /* * Due to a hardware issue, @@ -54,11 +55,20 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) { - uint i; + uint i, cid; struct net_device *ndev = wil_to_ndev(wil); wil_dbg_misc(wil, "%s()\n", __func__); + for (cid = 0; cid < WIL6210_MAX_CID; cid++) { + struct wil_sta_info *sta = &wil->sta[cid]; + for (i = 0; i < WIL_STA_TID_NUM; i++) { + struct wil_tid_ampdu_rx *r = sta->tid_rx[i]; + sta->tid_rx[i] = NULL; + wil_tid_ampdu_rx_free(wil, r); + } + } + wil_link_off(wil); if (test_bit(wil_status_fwconnected, &wil->status)) { clear_bit(wil_status_fwconnected, &wil->status); diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c new file mode 100644 index 000000000000..d04629fe053f --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -0,0 +1,177 @@ +#include "wil6210.h" +#include "txrx.h" + +#define SEQ_MODULO 0x1000 +#define SEQ_MASK 0xfff + +static inline int seq_less(u16 sq1, u16 sq2) +{ + return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1); +} + +static inline u16 seq_inc(u16 sq) +{ + return (sq + 1) & SEQ_MASK; +} + +static inline u16 seq_sub(u16 sq1, u16 sq2) +{ + return (sq1 - sq2) & SEQ_MASK; +} + +static inline int reorder_index(struct wil_tid_ampdu_rx *r, u16 seq) +{ + return seq_sub(seq, r->ssn) % r->buf_size; +} + +static void wil_release_reorder_frame(struct wil6210_priv *wil, + struct wil_tid_ampdu_rx *r, + int index) +{ + struct net_device *ndev = wil_to_ndev(wil); + struct sk_buff *skb = r->reorder_buf[index]; + + if (!skb) + goto no_frame; + + /* release the frame from the reorder ring buffer */ + r->stored_mpdu_num--; + r->reorder_buf[index] = NULL; + wil_netif_rx_any(skb, ndev); + +no_frame: + r->head_seq_num = seq_inc(r->head_seq_num); +} + +static void wil_release_reorder_frames(struct wil6210_priv *wil, + struct wil_tid_ampdu_rx *r, + u16 hseq) +{ + int index; + + while (seq_less(r->head_seq_num, hseq)) { + index = reorder_index(r, r->head_seq_num); + wil_release_reorder_frame(wil, r, index); + } +} + +static void wil_reorder_release(struct wil6210_priv *wil, + struct wil_tid_ampdu_rx *r) +{ + int index = reorder_index(r, r->head_seq_num); + + while (r->reorder_buf[index]) { + wil_release_reorder_frame(wil, r, index); + index = reorder_index(r, r->head_seq_num); + } +} + +void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) +{ + struct net_device *ndev = wil_to_ndev(wil); + struct vring_rx_desc *d = wil_skb_rxdesc(skb); + int tid = wil_rxdesc_tid(d); + int cid = wil_rxdesc_cid(d); + int mid = wil_rxdesc_mid(d); + u16 seq = wil_rxdesc_seq(d); + struct wil_sta_info *sta = &wil->sta[cid]; + struct wil_tid_ampdu_rx *r = sta->tid_rx[tid]; + u16 hseq; + int index; + + wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n", + mid, cid, tid, seq); + + if (!r) { + wil_netif_rx_any(skb, ndev); + return; + } + + hseq = r->head_seq_num; + + spin_lock(&r->reorder_lock); + + /* frame with out of date sequence number */ + if (seq_less(seq, r->head_seq_num)) { + dev_kfree_skb(skb); + goto out; + } + + /* + * If frame the sequence number exceeds our buffering window + * size release some previous frames to make room for this one. + */ + if (!seq_less(seq, r->head_seq_num + r->buf_size)) { + hseq = seq_inc(seq_sub(seq, r->buf_size)); + /* release stored frames up to new head to stack */ + wil_release_reorder_frames(wil, r, hseq); + } + + /* Now the new frame is always in the range of the reordering buffer */ + + index = reorder_index(r, seq); + + /* check if we already stored this frame */ + if (r->reorder_buf[index]) { + dev_kfree_skb(skb); + goto out; + } + + /* + * If the current MPDU is in the right order and nothing else + * is stored we can process it directly, no need to buffer it. + * If it is first but there's something stored, we may be able + * to release frames after this one. + */ + if (seq == r->head_seq_num && r->stored_mpdu_num == 0) { + r->head_seq_num = seq_inc(r->head_seq_num); + wil_netif_rx_any(skb, ndev); + goto out; + } + + /* put the frame in the reordering buffer */ + r->reorder_buf[index] = skb; + r->reorder_time[index] = jiffies; + r->stored_mpdu_num++; + wil_reorder_release(wil, r); + +out: + spin_unlock(&r->reorder_lock); +} + +struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, + int size, u16 ssn) +{ + struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL); + if (!r) + return NULL; + + r->reorder_buf = + kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL); + r->reorder_time = + kcalloc(size, sizeof(unsigned long), GFP_KERNEL); + if (!r->reorder_buf || !r->reorder_time) { + kfree(r->reorder_buf); + kfree(r->reorder_time); + kfree(r); + return NULL; + } + + spin_lock_init(&r->reorder_lock); + r->ssn = ssn; + r->head_seq_num = ssn; + r->buf_size = size; + r->stored_mpdu_num = 0; + return r; +} + +void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, + struct wil_tid_ampdu_rx *r) +{ + if (!r) + return; + wil_release_reorder_frames(wil, r, r->head_seq_num + r->buf_size); + kfree(r->reorder_buf); + kfree(r->reorder_time); + kfree(r); +} diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index eb60023fa217..48d97156f3db 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -472,7 +472,7 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count) * Pass Rx packet to the netif. Update statistics. * Called in softirq context (NAPI poll). */ -static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) +void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) { int rc; unsigned int len = skb->len; @@ -515,12 +515,12 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota) skb->ip_summed = CHECKSUM_UNNECESSARY; skb->pkt_type = PACKET_OTHERHOST; skb->protocol = htons(ETH_P_802_2); - + wil_netif_rx_any(skb, ndev); } else { skb->protocol = eth_type_trans(skb, ndev); + wil_rx_reorder(wil, skb); } - wil_netif_rx_any(skb, ndev); } wil_rx_refill(wil, v->size); } diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index b3828279204c..bc5706a4f007 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -436,4 +436,11 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb) return (void *)skb->cb; } +void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev); +void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb); +struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, + int size, u16 ssn); +void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, + struct wil_tid_ampdu_rx *r); + #endif /* WIL6210_TXRX_H */ diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 38df203f723d..304b990295b7 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -215,6 +215,46 @@ enum { /* for wil6210_priv.status */ struct pci_dev; +/** + * struct tid_ampdu_rx - TID aggregation information (Rx). + * + * @reorder_buf: buffer to reorder incoming aggregated MPDUs + * @reorder_time: jiffies when skb was added + * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) + * @reorder_timer: releases expired frames from the reorder buffer. + * @last_rx: jiffies of last rx activity + * @head_seq_num: head sequence number in reordering buffer. + * @stored_mpdu_num: number of MPDUs in reordering buffer + * @ssn: Starting Sequence Number expected to be aggregated. + * @buf_size: buffer size for incoming A-MPDUs + * @timeout: reset timer value (in TUs). + * @dialog_token: dialog token for aggregation session + * @rcu_head: RCU head used for freeing this struct + * @reorder_lock: serializes access to reorder buffer, see below. + * + * This structure's lifetime is managed by RCU, assignments to + * the array holding it must hold the aggregation mutex. + * + * The @reorder_lock is used to protect the members of this + * struct, except for @timeout, @buf_size and @dialog_token, + * which are constant across the lifetime of the struct (the + * dialog token being used only for debugging). + */ +struct wil_tid_ampdu_rx { + spinlock_t reorder_lock; /* see above */ + struct sk_buff **reorder_buf; + unsigned long *reorder_time; + struct timer_list session_timer; + struct timer_list reorder_timer; + unsigned long last_rx; + u16 head_seq_num; + u16 stored_mpdu_num; + u16 ssn; + u16 buf_size; + u16 timeout; + u8 dialog_token; +}; + struct wil6210_stats { u64 tsf; u32 snr; @@ -231,6 +271,9 @@ enum wil_sta_status { wil_sta_conn_pending = 1, wil_sta_connected = 2, }; + +#define WIL_STA_TID_NUM (16) + /** * struct wil_sta_info - data for peer * @@ -242,6 +285,10 @@ enum wil_sta_status { struct wil_sta_info { u8 addr[ETH_ALEN]; enum wil_sta_status status; + /* Rx BACK */ + struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM]; + unsigned long tid_rx_timer_expired[BITS_TO_LONGS(WIL_STA_TID_NUM)]; + unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)]; }; struct wil6210_priv { diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 2d602901675d..dfbc239b149d 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -563,10 +563,27 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d, int len) { struct wmi_vring_ba_status_event *evt = d; + uint cid, i; wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n", - evt->ringid, evt->status ? "N/A" : "OK", evt->agg_wsize, - __le16_to_cpu(evt->ba_timeout)); + evt->ringid, evt->status == WMI_BA_AGREED ? "OK" : "N/A", + evt->agg_wsize, __le16_to_cpu(evt->ba_timeout)); + for (cid = 0; cid < WIL6210_MAX_CID; cid++) { + struct wil_sta_info *sta = &wil->sta[cid]; + + if (sta->status == wil_sta_unused) + continue; + wil_dbg_wmi(wil, "Init BACK for CID %d %pM\n", cid, sta->addr); + for (i = 0; i < WIL_STA_TID_NUM; i++) { + struct wil_tid_ampdu_rx *r = sta->tid_rx[i]; + sta->tid_rx[i] = NULL; + wil_tid_ampdu_rx_free(wil, r); + if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize) + sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil, + evt->agg_wsize, 0); + } + } + } static const struct { @@ -949,6 +966,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) }, .mid = 0, /* TODO - what is it? */ .decap_trans_type = WMI_DECAP_TYPE_802_3, + .reorder_type = WMI_RX_SW_REORDER, }; struct { struct wil6210_mbox_hdr_wmi wmi; From 9a1773847d592c546f1fd5100d6ff434b414bedc Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 27 Feb 2014 16:20:45 +0200 Subject: [PATCH 354/414] wil6210: Find free vring for Tx There are 24 possible Tx vrings; when doind multiple connections, more then one vring has to be used. Search for free one and select it. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 38906f1bc769..5079e4944205 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -107,12 +107,23 @@ static void wil_connect_timer_fn(ulong x) schedule_work(&wil->disconnect_worker); } +static int wil_find_free_vring(struct wil6210_priv *wil) +{ + int i; + for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { + if (!wil->vring_tx[i].va) + return i; + } + return -EINVAL; +} + static void wil_connect_worker(struct work_struct *work) { int rc; struct wil6210_priv *wil = container_of(work, struct wil6210_priv, connect_worker); int cid = wil->pending_connect_cid; + int ringid = wil_find_free_vring(wil); if (cid < 0) { wil_err(wil, "No connection pending\n"); @@ -121,7 +132,7 @@ static void wil_connect_worker(struct work_struct *work) wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid); - rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, cid, 0); + rc = wil_vring_init_tx(wil, ringid, WIL6210_TX_RING_SIZE, cid, 0); wil->pending_connect_cid = -1; if (rc == 0) { wil->sta[cid].status = wil_sta_connected; From fb3cac572657fccf4e4406bd9737a0b3aaf54458 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 27 Feb 2014 16:20:46 +0200 Subject: [PATCH 355/414] wil6210: broadcast Tx Hardware do not support "real" broadcast on the air. Use method similar to the Directed Multicast Service (DMS) as described in the 10.23.15.2 "DMS procedures" This service copies frame and delivers unicast for each associated peer Do the following: send original frame to 1-st Tx vring, and send copies to all other active vrings. As currently hardware/firmware don't support A-MSDU, convert broadcast frame to unicast instead of wrapping it in A-MSDU Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/txrx.c | 65 +++++++++++++++++++++---- 1 file changed, 55 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 48d97156f3db..5ff59ee9c9f6 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -662,6 +662,60 @@ static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, return NULL; } +static void wil_set_da_for_vring(struct wil6210_priv *wil, + struct sk_buff *skb, int vring_index) +{ + struct ethhdr *eth = (void *)skb->data; + int cid = wil->vring2cid_tid[vring_index][0]; + memcpy(eth->h_dest, wil->sta[cid].addr, ETH_ALEN); +} + +static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, + struct sk_buff *skb); +/* + * Find 1-st vring and return it; set dest address for this vring in skb + * duplicate skb and send it to other active vrings + */ +static struct vring *wil_tx_bcast(struct wil6210_priv *wil, + struct sk_buff *skb) +{ + struct vring *v, *v2; + struct sk_buff *skb2; + int i; + + /* find 1-st vring */ + for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { + v = &wil->vring_tx[i]; + if (v->va) + goto found; + } + + wil_err(wil, "Tx while no vrings active?\n"); + + return NULL; + +found: + wil_dbg_txrx(wil, "BCAST -> ring %d\n", i); + wil_set_da_for_vring(wil, skb, i); + + /* find other active vrings and duplicate skb for each */ + for (i++; i < WIL6210_MAX_TX_RINGS; i++) { + v2 = &wil->vring_tx[i]; + if (!v2->va) + continue; + skb2 = skb_copy(skb, GFP_ATOMIC); + if (skb2) { + wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i); + wil_set_da_for_vring(wil, skb2, i); + wil_tx_vring(wil, v2, skb2); + } else { + wil_err(wil, "skb_copy failed\n"); + } + } + + return v; +} + static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len, int vring_index) { @@ -875,16 +929,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (is_unicast_ether_addr(eth->h_dest)) { vring = wil_find_tx_vring(wil, skb); } else { - int i = 0; - /* TODO: duplicate for all CID's */ - vring = &wil->vring_tx[i]; - if (vring->va) { - int cid = wil->vring2cid_tid[i][0]; - /* FIXME FW can accept only unicast frames */ - memcpy(skb->data, wil->sta[cid].addr, ETH_ALEN); - } else { - vring = NULL; - } + vring = wil_tx_bcast(wil, skb); } if (!vring) { wil_err(wil, "No Tx VRING found for %pM\n", eth->h_dest); From 7b05b0ab89e692eb45b011169afb2359d5d92c6c Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 27 Feb 2014 16:20:47 +0200 Subject: [PATCH 356/414] wil6210: fix BACK status processing When FW notifies about BACK status change, it provides ring ID. Process BA status for requested connection only. As for now, FW don't report Rx BACK status, it reports Tx one instead. As per current algorithm used in the firmware, imply Rx BACK state is in sync with Tx one Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/wmi.c | 45 +++++++++++++++++--------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index dfbc239b149d..635aa322608c 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -563,27 +563,42 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d, int len) { struct wmi_vring_ba_status_event *evt = d; - uint cid, i; + struct wil_sta_info *sta; + uint i, cid; + + /* TODO: use Rx BA status, not Tx one */ wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n", - evt->ringid, evt->status == WMI_BA_AGREED ? "OK" : "N/A", + evt->ringid, + evt->status == WMI_BA_AGREED ? "OK" : "N/A", evt->agg_wsize, __le16_to_cpu(evt->ba_timeout)); - for (cid = 0; cid < WIL6210_MAX_CID; cid++) { - struct wil_sta_info *sta = &wil->sta[cid]; - if (sta->status == wil_sta_unused) - continue; - wil_dbg_wmi(wil, "Init BACK for CID %d %pM\n", cid, sta->addr); - for (i = 0; i < WIL_STA_TID_NUM; i++) { - struct wil_tid_ampdu_rx *r = sta->tid_rx[i]; - sta->tid_rx[i] = NULL; - wil_tid_ampdu_rx_free(wil, r); - if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize) - sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil, - evt->agg_wsize, 0); - } + if (evt->ringid >= WIL6210_MAX_TX_RINGS) { + wil_err(wil, "invalid ring id %d\n", evt->ringid); + return; } + cid = wil->vring2cid_tid[evt->ringid][0]; + if (cid >= WIL6210_MAX_CID) { + wil_err(wil, "invalid CID %d for vring %d\n", cid, evt->ringid); + return; + } + + sta = &wil->sta[cid]; + if (sta->status == wil_sta_unused) { + wil_err(wil, "CID %d unused\n", cid); + return; + } + + wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr); + for (i = 0; i < WIL_STA_TID_NUM; i++) { + struct wil_tid_ampdu_rx *r = sta->tid_rx[i]; + sta->tid_rx[i] = NULL; + wil_tid_ampdu_rx_free(wil, r); + if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize) + sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil, + evt->agg_wsize, 0); + } } static const struct { From ef28afdb1cbb01dd15840eae3786b84ddfa83c6a Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 27 Feb 2014 16:20:48 +0200 Subject: [PATCH 357/414] wil6210: dump_station initial support Rx stats is not calculated per STA - just give some number Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 82 +++++++++++++++++---- 1 file changed, 66 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index fa713ef8dc95..495347baf523 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -104,27 +104,21 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type) return -EOPNOTSUPP; } -static int wil_cfg80211_get_station(struct wiphy *wiphy, - struct net_device *ndev, - u8 *mac, struct station_info *sinfo) +static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, + struct station_info *sinfo) { - struct wil6210_priv *wil = wiphy_to_wil(wiphy); - int rc; - - int cid = wil_find_cid(wil, mac); struct wmi_notify_req_cmd cmd = { .cid = cid, .interval_usec = 0, }; + struct { + struct wil6210_mbox_hdr_wmi wmi; + struct wmi_notify_req_done_event evt; + } __packed reply; + int rc; - wil_info(wil, "%s(%pM) CID %d\n", __func__, mac, cid); - if (cid < 0) - return -ENOENT; - - /* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */ - /* TODO: keep stats per CID */ rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd), - WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20); + WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20); if (rc) return rc; @@ -132,7 +126,7 @@ static int wil_cfg80211_get_station(struct wiphy *wiphy, sinfo->filled |= STATION_INFO_TX_BITRATE; sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; - sinfo->txrate.mcs = wil->stats.bf_mcs; + sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs); sinfo->filled |= STATION_INFO_RX_BITRATE; sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; sinfo->rxrate.mcs = wil->stats.last_mcs_rx; @@ -142,7 +136,62 @@ static int wil_cfg80211_get_station(struct wiphy *wiphy, sinfo->signal = 12; /* TODO: provide real value */ } - return 0; + return rc; +} + +static int wil_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *ndev, + u8 *mac, struct station_info *sinfo) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + + int cid = wil_find_cid(wil, mac); + + wil_info(wil, "%s(%pM) CID %d\n", __func__, mac, cid); + if (cid < 0) + return -ENOENT; + + rc = wil_cid_fill_sinfo(wil, cid, sinfo); + + return rc; +} + +/* + * Find @idx-th active STA for station dump. + */ +static int wil_find_cid_by_idx(struct wil6210_priv *wil, int idx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { + if (wil->sta[i].status == wil_sta_unused) + continue; + if (idx == 0) + return i; + idx--; + } + + return -ENOENT; +} + +static int wil_cfg80211_dump_station(struct wiphy *wiphy, + struct net_device *dev, int idx, + u8 *mac, struct station_info *sinfo) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + int cid = wil_find_cid_by_idx(wil, idx); + + if (cid < 0) + return -ENOENT; + + memcpy(mac, wil->sta[cid].addr, ETH_ALEN); + wil_info(wil, "%s(%pM) CID %d\n", __func__, mac, cid); + + rc = wil_cid_fill_sinfo(wil, cid, sinfo); + + return rc; } static int wil_cfg80211_change_iface(struct wiphy *wiphy, @@ -583,6 +632,7 @@ static struct cfg80211_ops wil_cfg80211_ops = { .disconnect = wil_cfg80211_disconnect, .change_virtual_intf = wil_cfg80211_change_iface, .get_station = wil_cfg80211_get_station, + .dump_station = wil_cfg80211_dump_station, .remain_on_channel = wil_remain_on_channel, .cancel_remain_on_channel = wil_cancel_remain_on_channel, .mgmt_tx = wil_cfg80211_mgmt_tx, From c8b78b5f0fa2783e9289c67e3f7524e6679874a9 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 27 Feb 2014 16:20:49 +0200 Subject: [PATCH 358/414] wil6210: per-connection statistics Calculate statistics per connection, report with "iw station dump" Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 36 +++++++++++++++++++-- drivers/net/wireless/ath/wil6210/txrx.c | 21 ++++++++++-- drivers/net/wireless/ath/wil6210/wil6210.h | 11 +++++++ drivers/net/wireless/ath/wil6210/wmi.c | 15 ++++++++- 4 files changed, 77 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 495347baf523..12e0539c8eff 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -115,6 +115,7 @@ static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, struct wil6210_mbox_hdr_wmi wmi; struct wmi_notify_req_done_event evt; } __packed reply; + struct wil_net_stats *stats = &wil->sta[cid].stats; int rc; rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd), @@ -122,14 +123,43 @@ static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, if (rc) return rc; + wil_dbg_wmi(wil, "Link status for CID %d: {\n" + " MCS %d TSF 0x%016llx\n" + " BF status 0x%08x SNR 0x%08x\n" + " Tx Tpt %d goodput %d Rx goodput %d\n" + " Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n", + cid, le16_to_cpu(reply.evt.bf_mcs), + le64_to_cpu(reply.evt.tsf), reply.evt.status, + le32_to_cpu(reply.evt.snr_val), + le32_to_cpu(reply.evt.tx_tpt), + le32_to_cpu(reply.evt.tx_goodput), + le32_to_cpu(reply.evt.rx_goodput), + le16_to_cpu(reply.evt.my_rx_sector), + le16_to_cpu(reply.evt.my_tx_sector), + le16_to_cpu(reply.evt.other_rx_sector), + le16_to_cpu(reply.evt.other_tx_sector)); + sinfo->generation = wil->sinfo_gen; - sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->filled = STATION_INFO_RX_BYTES | + STATION_INFO_TX_BYTES | + STATION_INFO_RX_PACKETS | + STATION_INFO_TX_PACKETS | + STATION_INFO_RX_BITRATE | + STATION_INFO_TX_BITRATE | + STATION_INFO_RX_DROP_MISC | + STATION_INFO_TX_FAILED; + sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs); - sinfo->filled |= STATION_INFO_RX_BITRATE; sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; - sinfo->rxrate.mcs = wil->stats.last_mcs_rx; + sinfo->rxrate.mcs = stats->last_mcs_rx; + sinfo->rx_bytes = stats->rx_bytes; + sinfo->rx_packets = stats->rx_packets; + sinfo->rx_dropped_misc = stats->rx_dropped; + sinfo->tx_bytes = stats->tx_bytes; + sinfo->tx_packets = stats->tx_packets; + sinfo->tx_failed = stats->tx_errors; if (test_bit(wil_status_fwconnected, &wil->status)) { sinfo->filled |= STATION_INFO_SIGNAL; diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 5ff59ee9c9f6..baced1bca04c 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -344,6 +344,9 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, u16 dmalen; u8 ftype; u8 ds_bits; + int cid; + struct wil_net_stats *stats; + BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb)); @@ -383,8 +386,10 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb_headlen(skb), false); - - wil->stats.last_mcs_rx = wil_rxdesc_mcs(d); + cid = wil_rxdesc_cid(d); + stats = &wil->sta[cid].stats; + stats->last_mcs_rx = wil_rxdesc_mcs(d); + wil->stats.last_mcs_rx = stats->last_mcs_rx; /* use radiotap header only if required */ if (ndev->type == ARPHRD_IEEE80211_RADIOTAP) @@ -475,7 +480,11 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count) void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) { int rc; + struct wil6210_priv *wil = ndev_to_wil(ndev); unsigned int len = skb->len; + struct vring_rx_desc *d = wil_skb_rxdesc(skb); + int cid = wil_rxdesc_cid(d); + struct wil_net_stats *stats = &wil->sta[cid].stats; skb_orphan(skb); @@ -483,10 +492,13 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) if (likely(rc == NET_RX_SUCCESS)) { ndev->stats.rx_packets++; + stats->rx_packets++; ndev->stats.rx_bytes += len; + stats->rx_bytes += len; } else { ndev->stats.rx_dropped++; + stats->rx_dropped++; } } @@ -968,6 +980,8 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) struct device *dev = wil_to_dev(wil); struct vring *vring = &wil->vring_tx[ringid]; int done = 0; + int cid = wil->vring2cid_tid[ringid][0]; + struct wil_net_stats *stats = &wil->sta[cid].stats; if (!vring->va) { wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid); @@ -1009,9 +1023,12 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) if (skb) { if (d->dma.error == 0) { ndev->stats.tx_packets++; + stats->tx_packets++; ndev->stats.tx_bytes += skb->len; + stats->tx_bytes += skb->len; } else { ndev->stats.tx_errors++; + stats->tx_errors++; } dev_kfree_skb_any(skb); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 304b990295b7..b64175aae1dd 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -274,6 +274,16 @@ enum wil_sta_status { #define WIL_STA_TID_NUM (16) +struct wil_net_stats { + unsigned long rx_packets; + unsigned long tx_packets; + unsigned long rx_bytes; + unsigned long tx_bytes; + unsigned long tx_errors; + unsigned long rx_dropped; + u16 last_mcs_rx; +}; + /** * struct wil_sta_info - data for peer * @@ -285,6 +295,7 @@ enum wil_sta_status { struct wil_sta_info { u8 addr[ETH_ALEN]; enum wil_sta_status status; + struct wil_net_stats stats; /* Rx BACK */ struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM]; unsigned long tid_rx_timer_expired[BITS_TO_LONGS(WIL_STA_TID_NUM)]; diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 635aa322608c..8de7ffdc0f29 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -510,10 +510,16 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, int sz = eapol_len + ETH_HLEN; struct sk_buff *skb; struct ethhdr *eth; + int cid; + struct wil_net_stats *stats = NULL; wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len, evt->src_mac); + cid = wil_find_cid(wil, evt->src_mac); + if (cid >= 0) + stats = &wil->sta[cid].stats; + if (eapol_len > 196) { /* TODO: revisit size limit */ wil_err(wil, "EAPOL too large\n"); return; @@ -524,6 +530,7 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, wil_err(wil, "Failed to allocate skb\n"); return; } + eth = (struct ethhdr *)skb_put(skb, ETH_HLEN); memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN); memcpy(eth->h_source, evt->src_mac, ETH_ALEN); @@ -532,9 +539,15 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, skb->protocol = eth_type_trans(skb, ndev); if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) { ndev->stats.rx_packets++; - ndev->stats.rx_bytes += skb->len; + ndev->stats.rx_bytes += sz; + if (stats) { + stats->rx_packets++; + stats->rx_bytes += sz; + } } else { ndev->stats.rx_dropped++; + if (stats) + stats->rx_dropped++; } } From 91886b0b7d65b8f5e0f6b2b7de90cd714d41844e Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 27 Feb 2014 16:20:50 +0200 Subject: [PATCH 359/414] wil6210: disconnect only requested peer Disconnect event reported by the FW, should lead to disconnection of only requested peer. Find for the appropriate CID and disconnect only it For AP-like interface, notify cfg80211 with del_sta(), for the client type interface, disconnect and turn link off. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 81 +++++++++++++++++-------- 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 5079e4944205..361c693270cc 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -53,38 +53,69 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, __raw_writel(*s++, d++); } +static void wil_disconnect_cid(struct wil6210_priv *wil, int cid) +{ + uint i; + struct wil_sta_info *sta = &wil->sta[cid]; + for (i = 0; i < WIL_STA_TID_NUM; i++) { + struct wil_tid_ampdu_rx *r = sta->tid_rx[i]; + sta->tid_rx[i] = NULL; + wil_tid_ampdu_rx_free(wil, r); + } + for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { + if (wil->vring2cid_tid[i][0] == cid) + wil_vring_fini_tx(wil, i); + } + memset(&sta->stats, 0, sizeof(sta->stats)); +} + static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) { - uint i, cid; + int cid = -ENOENT; struct net_device *ndev = wil_to_ndev(wil); + struct wireless_dev *wdev = wil->wdev; - wil_dbg_misc(wil, "%s()\n", __func__); + might_sleep(); + if (bssid) { + cid = wil_find_cid(wil, bssid); + wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid); + } else { + wil_dbg_misc(wil, "%s(all)\n", __func__); + } - for (cid = 0; cid < WIL6210_MAX_CID; cid++) { - struct wil_sta_info *sta = &wil->sta[cid]; - for (i = 0; i < WIL_STA_TID_NUM; i++) { - struct wil_tid_ampdu_rx *r = sta->tid_rx[i]; - sta->tid_rx[i] = NULL; - wil_tid_ampdu_rx_free(wil, r); + if (cid >= 0) /* disconnect 1 peer */ + wil_disconnect_cid(wil, cid); + else /* disconnect all */ + for (cid = 0; cid < WIL6210_MAX_CID; cid++) + wil_disconnect_cid(wil, cid); + + /* link state */ + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + wil_link_off(wil); + if (test_bit(wil_status_fwconnected, &wil->status)) { + clear_bit(wil_status_fwconnected, &wil->status); + cfg80211_disconnected(ndev, + WLAN_STATUS_UNSPECIFIED_FAILURE, + NULL, 0, GFP_KERNEL); + } else if (test_bit(wil_status_fwconnecting, &wil->status)) { + cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); } + clear_bit(wil_status_fwconnecting, &wil->status); + wil_dbg_misc(wil, "clear_bit(wil_status_dontscan)\n"); + clear_bit(wil_status_dontscan, &wil->status); + break; + default: + /* AP-like interface and monitor: + * never scan, always connected + */ + if (bssid) + cfg80211_del_sta(ndev, bssid, GFP_KERNEL); + break; } - - wil_link_off(wil); - if (test_bit(wil_status_fwconnected, &wil->status)) { - clear_bit(wil_status_fwconnected, &wil->status); - cfg80211_disconnected(ndev, - WLAN_STATUS_UNSPECIFIED_FAILURE, - NULL, 0, GFP_KERNEL); - } else if (test_bit(wil_status_fwconnecting, &wil->status)) { - cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL); - } - clear_bit(wil_status_fwconnecting, &wil->status); - for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) - wil_vring_fini_tx(wil, i); - - clear_bit(wil_status_dontscan, &wil->status); } static void wil_disconnect_worker(struct work_struct *work) From 93ae6d49e2ddd05431184779d8ace0bc189a597b Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 27 Feb 2014 16:20:51 +0200 Subject: [PATCH 360/414] wil6210: Fill vring2cid_tid table early Need to fill translation table before calling WMI with WMI_VRING_CFG_CMDID since firmware may generate events during this call; and events need translation table filled to be properly dispatched Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/txrx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index baced1bca04c..9b4388b842a2 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -610,6 +610,9 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, if (rc) goto out; + wil->vring2cid_tid[id][0] = cid; + wil->vring2cid_tid[id][1] = tid; + cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa); rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd), @@ -625,9 +628,6 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, } vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); - wil->vring2cid_tid[id][0] = cid; - wil->vring2cid_tid[id][1] = tid; - return 0; out_free: wil_vring_free(wil, vring, 1); From b8b33a3a67ef0b3ca57a647aa6966a2310ae60bb Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 27 Feb 2014 16:20:52 +0200 Subject: [PATCH 361/414] wil6210: Provide signal strength indication When notifying about Rx mgmt (ex: during scan), extract signal strength reported by the hardware. signal is not MBM, it is arbitrary units 0..100 Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 7 ++++--- drivers/net/wireless/ath/wil6210/wmi.c | 12 ++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 12e0539c8eff..c19e8954d8b3 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -125,12 +125,13 @@ static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, wil_dbg_wmi(wil, "Link status for CID %d: {\n" " MCS %d TSF 0x%016llx\n" - " BF status 0x%08x SNR 0x%08x\n" + " BF status 0x%08x SNR 0x%08x SQI %d%%\n" " Tx Tpt %d goodput %d Rx goodput %d\n" " Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n", cid, le16_to_cpu(reply.evt.bf_mcs), le64_to_cpu(reply.evt.tsf), reply.evt.status, le32_to_cpu(reply.evt.snr_val), + reply.evt.sqi, le32_to_cpu(reply.evt.tx_tpt), le32_to_cpu(reply.evt.tx_goodput), le32_to_cpu(reply.evt.rx_goodput), @@ -163,7 +164,7 @@ static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, if (test_bit(wil_status_fwconnected, &wil->status)) { sinfo->filled |= STATION_INFO_SIGNAL; - sinfo->signal = 12; /* TODO: provide real value */ + sinfo->signal = reply.evt.sqi; } return rc; @@ -698,7 +699,7 @@ static void wil_wiphy_init(struct wiphy *wiphy) wiphy->bands[IEEE80211_BAND_60GHZ] = &wil_band_60ghz; /* TODO: figure this out */ - wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; wiphy->cipher_suites = wil_cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 8de7ffdc0f29..70b3a9b20450 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -307,14 +307,14 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) u32 freq = ieee80211_channel_to_frequency(ch_no, IEEE80211_BAND_60GHZ); struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq); - /* TODO convert LE to CPU */ - s32 signal = 0; /* TODO */ + s32 signal = data->info.sqi; __le16 fc = rx_mgmt_frame->frame_control; u32 d_len = le32_to_cpu(data->info.len); u16 d_status = le16_to_cpu(data->info.status); - wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d\n", - data->info.channel, data->info.mcs, data->info.snr); + wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d SQI %d%%\n", + data->info.channel, data->info.mcs, data->info.snr, + data->info.sqi); wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len, le16_to_cpu(fc)); wil_dbg_wmi(wil, "qid %d mid %d cid %d\n", @@ -487,11 +487,11 @@ static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector); wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector); wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n" - "BF status 0x%08x SNR 0x%08x\n" + "BF status 0x%08x SNR 0x%08x SQI %d%%\n" "Tx Tpt %d goodput %d Rx goodput %d\n" "Sectors(rx:tx) my %d:%d peer %d:%d\n", wil->stats.bf_mcs, wil->stats.tsf, evt->status, - wil->stats.snr, le32_to_cpu(evt->tx_tpt), + wil->stats.snr, evt->sqi, le32_to_cpu(evt->tx_tpt), le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput), wil->stats.my_rx_sector, wil->stats.my_tx_sector, wil->stats.peer_rx_sector, wil->stats.peer_tx_sector); From 108d1eb612d4f4094dc5dea11521f0b9b02622e4 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 27 Feb 2014 16:20:53 +0200 Subject: [PATCH 362/414] wil6210: use ether_addr_equal Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 361c693270cc..a0ea135efd11 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -16,6 +16,7 @@ #include #include +#include #include "wil6210.h" #include "txrx.h" @@ -436,7 +437,7 @@ int wil_find_cid(struct wil6210_priv *wil, const u8 *mac) for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { if ((wil->sta[i].status != wil_sta_unused) && - (0 == memcmp(wil->sta[i].addr, mac, ETH_ALEN))) { + ether_addr_equal(wil->sta[i].addr, mac)) { rc = i; break; } From 4d55a0a1a8efb3fef4205b7d9464428a90f2fac4 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 27 Feb 2014 16:20:54 +0200 Subject: [PATCH 363/414] wil6210: single station disconnect implement del_station() method in the struct cfg80211_ops It allows to disconnect single peer from the AP Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 9 +++++++++ drivers/net/wireless/ath/wil6210/main.c | 6 ++++++ drivers/net/wireless/ath/wil6210/wil6210.h | 1 + drivers/net/wireless/ath/wil6210/wmi.c | 21 ++++++++++++++------- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index c19e8954d8b3..a4da064dbbc4 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -657,6 +657,14 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, return rc; } +static int wil_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, u8 *mac) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + wil6210_disconnect(wil, mac); + return 0; +} + static struct cfg80211_ops wil_cfg80211_ops = { .scan = wil_cfg80211_scan, .connect = wil_cfg80211_connect, @@ -674,6 +682,7 @@ static struct cfg80211_ops wil_cfg80211_ops = { /* AP mode */ .start_ap = wil_cfg80211_start_ap, .stop_ap = wil_cfg80211_stop_ap, + .del_station = wil_cfg80211_del_station, }; static void wil_wiphy_init(struct wiphy *wiphy) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index a0ea135efd11..41c362dee032 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -58,6 +58,12 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid) { uint i; struct wil_sta_info *sta = &wil->sta[cid]; + + if (sta->status != wil_sta_unused) { + wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING); + sta->status = wil_sta_unused; + } + for (i = 0; i < WIL_STA_TID_NUM; i++) { struct wil_tid_ampdu_rx *r = sta->tid_rx[i]; sta->tid_rx[i] = NULL; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index b64175aae1dd..980dccc82b32 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -437,6 +437,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring); int wmi_p2p_cfg(struct wil6210_priv *wil, int channel); int wmi_rxon(struct wil6210_priv *wil, bool on); int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r); +int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason); int wil6210_init_irq(struct wil6210_priv *wil, int irq); void wil6210_fini_irq(struct wil6210_priv *wil, int irq); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 70b3a9b20450..24eed0963581 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -455,19 +455,14 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, void *d, int len) { struct wmi_disconnect_event *evt = d; - int cid = wil_find_cid(wil, evt->bssid); - wil_dbg_wmi(wil, "Disconnect %pM CID %d reason %d proto %d wmi\n", - evt->bssid, cid, + wil_dbg_wmi(wil, "Disconnect %pM reason %d proto %d wmi\n", + evt->bssid, evt->protocol_reason_status, evt->disconnect_reason); wil->sinfo_gen++; - /* TODO: fix for multiple connections */ - wil6210_disconnect(wil, evt->bssid); - if (cid >= 0) - wil->sta[cid].status = wil_sta_unused; } static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) @@ -1062,6 +1057,18 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r) return 0; } +int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason) +{ + struct wmi_disconnect_sta_cmd cmd = { + .disconnect_reason = cpu_to_le16(reason), + }; + memcpy(cmd.dst_mac, mac, ETH_ALEN); + + wil_dbg_wmi(wil, "%s(%pM, reason %d)\n", __func__, mac, reason); + + return wmi_send(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd)); +} + void wmi_event_flush(struct wil6210_priv *wil) { struct pending_wmi_event *evt, *t; From 0bbc4adebdb3ced39e53955f03153f4718cc3a81 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 27 Feb 2014 16:20:55 +0200 Subject: [PATCH 364/414] wil6210: do not reorder groupcast Rx Groupcast frames are not subject for BACK reordering because they are not ACK'ed and one can't request re-transmitt Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/txrx.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 9b4388b842a2..092081e209da 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -529,8 +529,14 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota) skb->protocol = htons(ETH_P_802_2); wil_netif_rx_any(skb, ndev); } else { + struct ethhdr *eth = (void *)skb->data; + skb->protocol = eth_type_trans(skb, ndev); - wil_rx_reorder(wil, skb); + + if (is_unicast_ether_addr(eth->h_dest)) + wil_rx_reorder(wil, skb); + else + wil_netif_rx_any(skb, ndev); } } From 6b7dce12b3e810a107735ab9e701f2be4e75db29 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 27 Feb 2014 17:06:58 +0100 Subject: [PATCH 365/414] rtlwifi: Remove redundant if clause Signed-off-by: Heinrich Schuchardt Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192se/rf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/rf.c b/drivers/net/wireless/rtlwifi/rtl8192se/rf.c index 92d38ab3c60e..78a81c1e390b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/rf.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/rf.c @@ -52,7 +52,7 @@ static void _rtl92s_get_powerbase(struct ieee80211_hw *hw, u8 *p_pwrlevel, /* We only care about the path A for legacy. */ if (rtlefuse->eeprom_version < 2) { pwrbase0 = pwrlevel[0] + (rtlefuse->legacy_httxpowerdiff & 0xf); - } else if (rtlefuse->eeprom_version >= 2) { + } else { legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff [RF90_PATH_A][chnl - 1]; From fa0ecbb9905d985a77e76801ba1153394ba593e8 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Thu, 27 Feb 2014 19:35:12 -0800 Subject: [PATCH 366/414] mwifiex: remove global variable cmd_wait_q_required There is a race condition while queuing synchronous command and asynchronous command requested from different threads, because the wait_q_enabled flag is set based on a global variable cmd_wait_q_required. The issue is fixed by removing this global variable and using a unified function with an argument 'sync' passed into the function. Signed-off-by: Bing Zhao Signed-off-by: Amitkumar Karwar Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/11h.c | 4 +- drivers/net/wireless/mwifiex/11n.c | 8 +- drivers/net/wireless/mwifiex/11n_rxreorder.c | 2 +- drivers/net/wireless/mwifiex/cfg80211.c | 167 +++++++++---------- drivers/net/wireless/mwifiex/cmdevt.c | 36 +--- drivers/net/wireless/mwifiex/ie.c | 6 +- drivers/net/wireless/mwifiex/join.c | 37 ++-- drivers/net/wireless/mwifiex/main.c | 5 +- drivers/net/wireless/mwifiex/main.h | 8 +- drivers/net/wireless/mwifiex/scan.c | 4 +- drivers/net/wireless/mwifiex/sta_cmd.c | 84 +++++----- drivers/net/wireless/mwifiex/sta_cmdresp.c | 9 +- drivers/net/wireless/mwifiex/sta_event.c | 38 ++--- drivers/net/wireless/mwifiex/sta_ioctl.c | 117 ++++++------- drivers/net/wireless/mwifiex/tdls.c | 16 +- drivers/net/wireless/mwifiex/uap_cmd.c | 4 +- drivers/net/wireless/mwifiex/uap_event.c | 6 +- drivers/net/wireless/mwifiex/util.c | 2 +- 18 files changed, 255 insertions(+), 298 deletions(-) diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c index 8d683070bdb3..e76b0db4e3e6 100644 --- a/drivers/net/wireless/mwifiex/11h.c +++ b/drivers/net/wireless/mwifiex/11h.c @@ -73,8 +73,8 @@ static int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag) { u32 enable = flag; - return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, - HostCmd_ACT_GEN_SET, DOT11H_I, &enable); + return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_SET, DOT11H_I, &enable, true); } /* This functions processes TLV buffer for a pending BSS Join command. diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index 37677af8d2fc..79ead928a64e 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -574,8 +574,8 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac) memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN); /* We don't wait for the response of this command */ - ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_REQ, - 0, 0, &add_ba_req); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ, + 0, 0, &add_ba_req, false); return ret; } @@ -602,8 +602,8 @@ int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac, memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN); /* We don't wait for the response of this command */ - ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA, - HostCmd_ACT_GEN_SET, 0, &delba); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_DELBA, + HostCmd_ACT_GEN_SET, 0, &delba, false); return ret; } diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index 35329cfc9a9b..c3323c492614 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -650,7 +650,7 @@ void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv, delba.del_ba_param_set |= cpu_to_le16( (u16) event->origninator << DELBA_INITIATOR_POS); delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT); - mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba); + mwifiex_send_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba, false); } /* diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 68c51a8e5bea..bfe9316e196c 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -252,9 +252,9 @@ mwifiex_cfg80211_mgmt_frame_register(struct wiphy *wiphy, if (mask != priv->mgmt_frame_mask) { priv->mgmt_frame_mask = mask; - mwifiex_send_cmd_async(priv, HostCmd_CMD_MGMT_FRAME_REG, - HostCmd_ACT_GEN_SET, 0, - &priv->mgmt_frame_mask); + mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG, + HostCmd_ACT_GEN_SET, 0, + &priv->mgmt_frame_mask, false); wiphy_dbg(wiphy, "info: mgmt frame registered\n"); } } @@ -515,8 +515,8 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); - if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, - HostCmd_ACT_GEN_SET, 0, NULL)) { + if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, + HostCmd_ACT_GEN_SET, 0, NULL, false)) { wiphy_err(wiphy, "11D: setting domain info in FW\n"); return -1; } @@ -580,9 +580,9 @@ mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr) frag_thr > MWIFIEX_FRAG_MAX_VALUE) frag_thr = MWIFIEX_FRAG_MAX_VALUE; - return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, - HostCmd_ACT_GEN_SET, FRAG_THRESH_I, - &frag_thr); + return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_SET, FRAG_THRESH_I, + &frag_thr, true); } /* @@ -597,9 +597,9 @@ mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr) if (rts_thr < MWIFIEX_RTS_MIN_VALUE || rts_thr > MWIFIEX_RTS_MAX_VALUE) rts_thr = MWIFIEX_RTS_MAX_VALUE; - return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, - HostCmd_ACT_GEN_SET, RTS_THRESH_I, - &rts_thr); + return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_SET, RTS_THRESH_I, + &rts_thr, true); } /* @@ -637,20 +637,19 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) bss_started = priv->bss_started; - ret = mwifiex_send_cmd_sync(priv, - HostCmd_CMD_UAP_BSS_STOP, - HostCmd_ACT_GEN_SET, 0, - NULL); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, + HostCmd_ACT_GEN_SET, 0, + NULL, true); if (ret) { wiphy_err(wiphy, "Failed to stop the BSS\n"); kfree(bss_cfg); return ret; } - ret = mwifiex_send_cmd_async(priv, - HostCmd_CMD_UAP_SYS_CONFIG, - HostCmd_ACT_GEN_SET, - UAP_BSS_PARAMS_I, bss_cfg); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, + HostCmd_ACT_GEN_SET, + UAP_BSS_PARAMS_I, bss_cfg, + false); kfree(bss_cfg); @@ -662,10 +661,9 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) if (!bss_started) break; - ret = mwifiex_send_cmd_async(priv, - HostCmd_CMD_UAP_BSS_START, - HostCmd_ACT_GEN_SET, 0, - NULL); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START, + HostCmd_ACT_GEN_SET, 0, + NULL, false); if (ret) { wiphy_err(wiphy, "Failed to start BSS\n"); return ret; @@ -700,8 +698,8 @@ mwifiex_cfg80211_deinit_p2p(struct mwifiex_private *priv) if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_STA); - if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG, - HostCmd_ACT_GEN_SET, 0, &mode)) + if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG, + HostCmd_ACT_GEN_SET, 0, &mode, true)) return -1; return 0; @@ -721,13 +719,13 @@ mwifiex_cfg80211_init_p2p_client(struct mwifiex_private *priv) return -1; mode = P2P_MODE_DEVICE; - if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG, - HostCmd_ACT_GEN_SET, 0, &mode)) + if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG, + HostCmd_ACT_GEN_SET, 0, &mode, true)) return -1; mode = P2P_MODE_CLIENT; - if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG, - HostCmd_ACT_GEN_SET, 0, &mode)) + if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG, + HostCmd_ACT_GEN_SET, 0, &mode, true)) return -1; return 0; @@ -747,13 +745,13 @@ mwifiex_cfg80211_init_p2p_go(struct mwifiex_private *priv) return -1; mode = P2P_MODE_DEVICE; - if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG, - HostCmd_ACT_GEN_SET, 0, &mode)) + if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG, + HostCmd_ACT_GEN_SET, 0, &mode, true)) return -1; mode = P2P_MODE_GO; - if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_P2P_MODE_CFG, - HostCmd_ACT_GEN_SET, 0, &mode)) + if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG, + HostCmd_ACT_GEN_SET, 0, &mode, true)) return -1; if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) @@ -853,8 +851,8 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_SET_BSS_MODE, - HostCmd_ACT_GEN_SET, 0, NULL); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, + HostCmd_ACT_GEN_SET, 0, NULL, true); return ret; } @@ -942,8 +940,8 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; /* Get signal information from the firmware */ - if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_RSSI_INFO, - HostCmd_ACT_GEN_GET, 0, NULL)) { + if (mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO, + HostCmd_ACT_GEN_GET, 0, NULL, true)) { dev_err(priv->adapter->dev, "failed to get signal information\n"); return -EFAULT; } @@ -954,9 +952,9 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, } /* Get DTIM period information from firmware */ - mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, - HostCmd_ACT_GEN_GET, DTIM_PERIOD_I, - &priv->dtim_period); + mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_GET, DTIM_PERIOD_I, + &priv->dtim_period, true); mwifiex_parse_htinfo(priv, priv->tx_htinfo, &sinfo->txrate); @@ -1186,8 +1184,8 @@ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy, if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) bitmap_rates[2] |= mask->control[band].ht_mcs[1] << 8; - return mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG, - HostCmd_ACT_GEN_SET, 0, bitmap_rates); + return mwifiex_send_cmd(priv, HostCmd_CMD_TX_RATE_CFG, + HostCmd_ACT_GEN_SET, 0, bitmap_rates, true); } /* @@ -1216,14 +1214,14 @@ static int mwifiex_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy, subsc_evt.bcn_h_rssi_cfg.abs_value = abs(rssi_thold); subsc_evt.bcn_l_rssi_cfg.evt_freq = 1; subsc_evt.bcn_h_rssi_cfg.evt_freq = 1; - return mwifiex_send_cmd_sync(priv, - HostCmd_CMD_802_11_SUBSCRIBE_EVENT, - 0, 0, &subsc_evt); + return mwifiex_send_cmd(priv, + HostCmd_CMD_802_11_SUBSCRIBE_EVENT, + 0, 0, &subsc_evt, true); } else { subsc_evt.action = HostCmd_ACT_BITWISE_CLR; - return mwifiex_send_cmd_sync(priv, - HostCmd_CMD_802_11_SUBSCRIBE_EVENT, - 0, 0, &subsc_evt); + return mwifiex_send_cmd(priv, + HostCmd_CMD_802_11_SUBSCRIBE_EVENT, + 0, 0, &subsc_evt, true); } return 0; @@ -1276,10 +1274,9 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, if (!mac || is_broadcast_ether_addr(mac)) { wiphy_dbg(wiphy, "%s: NULL/broadcast mac address\n", __func__); list_for_each_entry(sta_node, &priv->sta_list, list) { - if (mwifiex_send_cmd_sync(priv, - HostCmd_CMD_UAP_STA_DEAUTH, - HostCmd_ACT_GEN_SET, 0, - sta_node->mac_addr)) + if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH, + HostCmd_ACT_GEN_SET, 0, + sta_node->mac_addr, true)) return -1; mwifiex_uap_del_sta_data(priv, sta_node); } @@ -1289,10 +1286,9 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, sta_node = mwifiex_get_sta_entry(priv, mac); spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); if (sta_node) { - if (mwifiex_send_cmd_sync(priv, - HostCmd_CMD_UAP_STA_DEAUTH, - HostCmd_ACT_GEN_SET, 0, - sta_node->mac_addr)) + if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH, + HostCmd_ACT_GEN_SET, 0, + sta_node->mac_addr, true)) return -1; mwifiex_uap_del_sta_data(priv, sta_node); } @@ -1333,8 +1329,8 @@ mwifiex_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) ant_cfg.tx_ant = tx_ant; ant_cfg.rx_ant = rx_ant; - return mwifiex_send_cmd_sync(priv, HostCmd_CMD_RF_ANTENNA, - HostCmd_ACT_GEN_SET, 0, &ant_cfg); + return mwifiex_send_cmd(priv, HostCmd_CMD_RF_ANTENNA, + HostCmd_ACT_GEN_SET, 0, &ant_cfg, true); } /* cfg80211 operation handler for stop ap. @@ -1349,8 +1345,8 @@ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) priv->ap_11n_enabled = 0; - if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP, - HostCmd_ACT_GEN_SET, 0, NULL)) { + if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, + HostCmd_ACT_GEN_SET, 0, NULL, true)) { wiphy_err(wiphy, "Failed to stop the BSS\n"); return -1; } @@ -1461,16 +1457,16 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, bss_cfg->ps_sta_ao_timer = 10 * params->inactivity_timeout; } - if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP, - HostCmd_ACT_GEN_SET, 0, NULL)) { + if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, + HostCmd_ACT_GEN_SET, 0, NULL, true)) { wiphy_err(wiphy, "Failed to stop the BSS\n"); kfree(bss_cfg); return -1; } - if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG, - HostCmd_ACT_GEN_SET, - UAP_BSS_PARAMS_I, bss_cfg)) { + if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, + HostCmd_ACT_GEN_SET, + UAP_BSS_PARAMS_I, bss_cfg, false)) { wiphy_err(wiphy, "Failed to set the SSID\n"); kfree(bss_cfg); return -1; @@ -1478,8 +1474,8 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, kfree(bss_cfg); - if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_BSS_START, - HostCmd_ACT_GEN_SET, 0, NULL)) { + if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START, + HostCmd_ACT_GEN_SET, 0, NULL, false)) { wiphy_err(wiphy, "Failed to start the BSS\n"); return -1; } @@ -1489,9 +1485,9 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, else priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; - if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL, - HostCmd_ACT_GEN_SET, 0, - &priv->curr_pkt_filter)) + if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, + &priv->curr_pkt_filter, true)) return -1; return 0; @@ -2459,9 +2455,8 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, MWIFIEX_CRITERIA_UNICAST | MWIFIEX_CRITERIA_MULTICAST; - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MEF_CFG, - HostCmd_ACT_GEN_SET, 0, - &mef_cfg); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_MEF_CFG, + HostCmd_ACT_GEN_SET, 0, &mef_cfg, true); kfree(mef_entry); return ret; @@ -2573,9 +2568,9 @@ static int mwifiex_cfg80211_set_coalesce(struct wiphy *wiphy, if (!coalesce) { dev_dbg(adapter->dev, "Disable coalesce and reset all previous rules\n"); - return mwifiex_send_cmd_sync(priv, HostCmd_CMD_COALESCE_CFG, - HostCmd_ACT_GEN_SET, 0, - &coalesce_cfg); + return mwifiex_send_cmd(priv, HostCmd_CMD_COALESCE_CFG, + HostCmd_ACT_GEN_SET, 0, + &coalesce_cfg, true); } coalesce_cfg.num_of_rules = coalesce->n_rules; @@ -2590,8 +2585,8 @@ static int mwifiex_cfg80211_set_coalesce(struct wiphy *wiphy, } } - return mwifiex_send_cmd_sync(priv, HostCmd_CMD_COALESCE_CFG, - HostCmd_ACT_GEN_SET, 0, &coalesce_cfg); + return mwifiex_send_cmd(priv, HostCmd_CMD_COALESCE_CFG, + HostCmd_ACT_GEN_SET, 0, &coalesce_cfg, true); } /* cfg80211 ops handler for tdls_mgmt. @@ -2940,17 +2935,17 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) country_code); } - mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, - HostCmd_ACT_GEN_GET, FRAG_THRESH_I, &thr); + mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_GET, FRAG_THRESH_I, &thr, true); wiphy->frag_threshold = thr; - mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, - HostCmd_ACT_GEN_GET, RTS_THRESH_I, &thr); + mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_GET, RTS_THRESH_I, &thr, true); wiphy->rts_threshold = thr; - mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, - HostCmd_ACT_GEN_GET, SHORT_RETRY_LIM_I, &retry); + mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_GET, SHORT_RETRY_LIM_I, &retry, true); wiphy->retry_short = (u8) retry; - mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, - HostCmd_ACT_GEN_GET, LONG_RETRY_LIM_I, &retry); + mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_GET, LONG_RETRY_LIM_I, &retry, true); wiphy->retry_long = (u8) retry; adapter->wiphy = wiphy; diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index f4faeaf322be..64e708b79f0e 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -37,13 +37,12 @@ static void mwifiex_init_cmd_node(struct mwifiex_private *priv, struct cmd_ctrl_node *cmd_node, - u32 cmd_oid, void *data_buf) + u32 cmd_oid, void *data_buf, bool sync) { cmd_node->priv = priv; cmd_node->cmd_oid = cmd_oid; - if (priv->adapter->cmd_wait_q_required) { - cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required; - priv->adapter->cmd_wait_q_required = false; + if (sync) { + cmd_node->wait_q_enabled = true; cmd_node->cmd_wait_q_woken = false; cmd_node->condition = &cmd_node->cmd_wait_q_woken; } @@ -480,28 +479,7 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter) } /* - * This function is used to send synchronous command to the firmware. - * - * it allocates a wait queue for the command and wait for the command - * response. - */ -int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no, - u16 cmd_action, u32 cmd_oid, void *data_buf) -{ - int ret = 0; - struct mwifiex_adapter *adapter = priv->adapter; - - adapter->cmd_wait_q_required = true; - - ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid, - data_buf); - - return ret; -} - - -/* - * This function prepares a command and asynchronously send it to the firmware. + * This function prepares a command and send it to the firmware. * * Preparation includes - * - Sanity tests to make sure the card is still present or the FW @@ -511,8 +489,8 @@ int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no, * - Fill up the non-default parameters and buffer pointers * - Add the command to pending queue */ -int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, - u16 cmd_action, u32 cmd_oid, void *data_buf) +int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no, + u16 cmd_action, u32 cmd_oid, void *data_buf, bool sync) { int ret; struct mwifiex_adapter *adapter = priv->adapter; @@ -550,7 +528,7 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, } /* Initialize the command node */ - mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, data_buf); + mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, data_buf, sync); if (!cmd_node->cmd_skb) { dev_err(adapter->dev, "PREP_CMD: no free cmd buf\n"); diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c index 81ac001ee741..3bf3d58bbc02 100644 --- a/drivers/net/wireless/mwifiex/ie.c +++ b/drivers/net/wireless/mwifiex/ie.c @@ -138,9 +138,9 @@ mwifiex_update_autoindex_ies(struct mwifiex_private *priv, } if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) - return mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG, - HostCmd_ACT_GEN_SET, - UAP_CUSTOM_IE_I, ie_list); + return mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, + HostCmd_ACT_GEN_SET, + UAP_CUSTOM_IE_I, ie_list, false); return 0; } diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 34472ea53841..e9bd43526d80 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -901,9 +901,9 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, mwifiex_get_active_data_rates(priv, adhoc_start->data_rate); if ((adapter->adhoc_start_band & BAND_G) && (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) { - if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, - HostCmd_ACT_GEN_SET, 0, - &priv->curr_pkt_filter)) { + if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, + &priv->curr_pkt_filter, false)) { dev_err(adapter->dev, "ADHOC_S_CMD: G Protection config failed\n"); return -1; @@ -1073,9 +1073,9 @@ mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, priv-> curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON; - if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, - HostCmd_ACT_GEN_SET, 0, - &curr_pkt_filter)) { + if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, + &curr_pkt_filter, false)) { dev_err(priv->adapter->dev, "ADHOC_J_CMD: G Protection config failed\n"); return -1; @@ -1312,8 +1312,8 @@ int mwifiex_associate(struct mwifiex_private *priv, retrieval */ priv->assoc_rsp_size = 0; - return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_ASSOCIATE, - HostCmd_ACT_GEN_SET, 0, bss_desc); + return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_ASSOCIATE, + HostCmd_ACT_GEN_SET, 0, bss_desc, true); } /* @@ -1338,8 +1338,8 @@ mwifiex_adhoc_start(struct mwifiex_private *priv, else mwifiex_set_ba_params(priv); - return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_START, - HostCmd_ACT_GEN_SET, 0, adhoc_ssid); + return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_START, + HostCmd_ACT_GEN_SET, 0, adhoc_ssid, true); } /* @@ -1383,8 +1383,8 @@ int mwifiex_adhoc_join(struct mwifiex_private *priv, dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %c\n", priv->curr_bss_params.band); - return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_JOIN, - HostCmd_ACT_GEN_SET, 0, bss_desc); + return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_JOIN, + HostCmd_ACT_GEN_SET, 0, bss_desc, true); } /* @@ -1403,8 +1403,8 @@ static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac) else memcpy(mac_address, mac, ETH_ALEN); - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_DEAUTHENTICATE, - HostCmd_ACT_GEN_SET, 0, mac_address); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_DEAUTHENTICATE, + HostCmd_ACT_GEN_SET, 0, mac_address, true); return ret; } @@ -1432,12 +1432,11 @@ int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac) GFP_KERNEL); break; case NL80211_IFTYPE_ADHOC: - return mwifiex_send_cmd_sync(priv, - HostCmd_CMD_802_11_AD_HOC_STOP, - HostCmd_ACT_GEN_SET, 0, NULL); + return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_STOP, + HostCmd_ACT_GEN_SET, 0, NULL, true); case NL80211_IFTYPE_AP: - return mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP, - HostCmd_ACT_GEN_SET, 0, NULL); + return mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, + HostCmd_ACT_GEN_SET, 0, NULL, true); default: break; } diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index f87ce28a8060..5397ee0ad652 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -678,8 +678,8 @@ mwifiex_set_mac_address(struct net_device *dev, void *addr) memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN); /* Send request to firmware */ - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_MAC_ADDRESS, - HostCmd_ACT_GEN_SET, 0, NULL); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_MAC_ADDRESS, + HostCmd_ACT_GEN_SET, 0, NULL, true); if (!ret) memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN); @@ -871,7 +871,6 @@ mwifiex_add_card(void *card, struct semaphore *sem, adapter->is_suspended = false; adapter->hs_activated = false; init_waitqueue_head(&adapter->hs_activate_wait_q); - adapter->cmd_wait_q_required = false; init_waitqueue_head(&adapter->cmd_wait_q.wait); adapter->cmd_wait_q.status = 0; adapter->scan_wait_q_woken = false; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index cb1148f0de69..6c04baa5bcf9 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -779,7 +779,6 @@ struct mwifiex_adapter { struct mwifiex_dbg dbg; u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE]; u32 arp_filter_size; - u16 cmd_wait_q_required; struct mwifiex_wait_queue cmd_wait_q; u8 scan_wait_q_woken; spinlock_t queue_lock; /* lock for tx queues */ @@ -839,11 +838,8 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter); int mwifiex_complete_cmd(struct mwifiex_adapter *adapter, struct cmd_ctrl_node *cmd_node); -int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, - u16 cmd_action, u32 cmd_oid, void *data_buf); - -int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no, - u16 cmd_action, u32 cmd_oid, void *data_buf); +int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no, + u16 cmd_action, u32 cmd_oid, void *data_buf, bool sync); void mwifiex_cmd_timeout_func(unsigned long function_context); diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 92adbb1ebabc..0e8ca7bab3e7 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -738,8 +738,8 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, else cmd_no = HostCmd_CMD_802_11_SCAN; - ret = mwifiex_send_cmd_async(priv, cmd_no, HostCmd_ACT_GEN_SET, - 0, scan_cfg_out); + ret = mwifiex_send_cmd(priv, cmd_no, HostCmd_ACT_GEN_SET, + 0, scan_cfg_out, false); /* rate IE is updated per scan command but same starting * pointer is used each time so that rate IE from earlier diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 5aa3d39e48bc..4315a3ba3b92 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1411,9 +1411,9 @@ int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv, /* property header is 6 bytes, data must fit in cmd buffer */ if (prop && prop->value && prop->length > 6 && prop->length <= MWIFIEX_SIZE_OF_CMD_BUFFER - S_DS_GEN) { - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_CFG_DATA, - HostCmd_ACT_GEN_SET, 0, - prop); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_CFG_DATA, + HostCmd_ACT_GEN_SET, 0, + prop, true); if (ret) return ret; } @@ -1912,15 +1912,16 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) if (first_sta) { if (priv->adapter->iface_type == MWIFIEX_PCIE) { - ret = mwifiex_send_cmd_sync(priv, - HostCmd_CMD_PCIE_DESC_DETAILS, - HostCmd_ACT_GEN_SET, 0, NULL); + ret = mwifiex_send_cmd(priv, + HostCmd_CMD_PCIE_DESC_DETAILS, + HostCmd_ACT_GEN_SET, 0, NULL, + true); if (ret) return -1; } - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_FUNC_INIT, - HostCmd_ACT_GEN_SET, 0, NULL); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_FUNC_INIT, + HostCmd_ACT_GEN_SET, 0, NULL, true); if (ret) return -1; @@ -1938,55 +1939,57 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) } if (adapter->cal_data) { - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_CFG_DATA, - HostCmd_ACT_GEN_SET, 0, NULL); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_CFG_DATA, + HostCmd_ACT_GEN_SET, 0, NULL, + true); if (ret) return -1; } /* Read MAC address from HW */ - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_GET_HW_SPEC, - HostCmd_ACT_GEN_GET, 0, NULL); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_GET_HW_SPEC, + HostCmd_ACT_GEN_GET, 0, NULL, true); if (ret) return -1; /* Reconfigure tx buf size */ - ret = mwifiex_send_cmd_sync(priv, - HostCmd_CMD_RECONFIGURE_TX_BUFF, - HostCmd_ACT_GEN_SET, 0, - &priv->adapter->tx_buf_size); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, + HostCmd_ACT_GEN_SET, 0, + &priv->adapter->tx_buf_size, true); if (ret) return -1; if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { /* Enable IEEE PS by default */ priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; - ret = mwifiex_send_cmd_sync( - priv, HostCmd_CMD_802_11_PS_MODE_ENH, - EN_AUTO_PS, BITMAP_STA_PS, NULL); + ret = mwifiex_send_cmd(priv, + HostCmd_CMD_802_11_PS_MODE_ENH, + EN_AUTO_PS, BITMAP_STA_PS, NULL, + true); if (ret) return -1; } } /* get tx rate */ - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG, - HostCmd_ACT_GEN_GET, 0, NULL); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_TX_RATE_CFG, + HostCmd_ACT_GEN_GET, 0, NULL, true); if (ret) return -1; priv->data_rate = 0; /* get tx power */ - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_RF_TX_PWR, - HostCmd_ACT_GEN_GET, 0, NULL); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_RF_TX_PWR, + HostCmd_ACT_GEN_GET, 0, NULL, true); if (ret) return -1; if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) { /* set ibss coalescing_status */ - ret = mwifiex_send_cmd_sync( - priv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, - HostCmd_ACT_GEN_SET, 0, &enable); + ret = mwifiex_send_cmd( + priv, + HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, + HostCmd_ACT_GEN_SET, 0, &enable, true); if (ret) return -1; } @@ -1994,16 +1997,16 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl)); amsdu_aggr_ctrl.enable = true; /* Send request to firmware */ - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_AMSDU_AGGR_CTRL, - HostCmd_ACT_GEN_SET, 0, - &amsdu_aggr_ctrl); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_AMSDU_AGGR_CTRL, + HostCmd_ACT_GEN_SET, 0, + &amsdu_aggr_ctrl, true); if (ret) return -1; /* MAC Control must be the last command in init_fw */ /* set MAC Control */ - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL, - HostCmd_ACT_GEN_SET, 0, - &priv->curr_pkt_filter); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, + &priv->curr_pkt_filter, true); if (ret) return -1; @@ -2012,10 +2015,9 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) /* Enable auto deep sleep */ auto_ds.auto_ds = DEEP_SLEEP_ON; auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME; - ret = mwifiex_send_cmd_sync(priv, - HostCmd_CMD_802_11_PS_MODE_ENH, - EN_AUTO_PS, BITMAP_AUTO_DS, - &auto_ds); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, + EN_AUTO_PS, BITMAP_AUTO_DS, + &auto_ds, true); if (ret) return -1; } @@ -2023,9 +2025,9 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { /* Send cmd to FW to enable/disable 11D function */ state_11d = ENABLE_11D; - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, - HostCmd_ACT_GEN_SET, DOT11D_I, - &state_11d); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_SET, DOT11D_I, + &state_11d, true); if (ret) dev_err(priv->adapter->dev, "11D: failed to enable 11D\n"); @@ -2038,8 +2040,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) * (Short GI, Channel BW, Green field support etc.) for transmit */ tx_cfg.tx_htcap = MWIFIEX_FW_DEF_HTTXCFG; - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_11N_CFG, - HostCmd_ACT_GEN_SET, 0, &tx_cfg); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_CFG, + HostCmd_ACT_GEN_SET, 0, &tx_cfg, true); ret = -EINPROGRESS; diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 1c5e18804074..a8f7d545e22a 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -158,8 +158,8 @@ static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv, priv->subsc_evt_rssi_state = EVENT_HANDLED; - mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SUBSCRIBE_EVENT, - 0, 0, subsc_evt); + mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SUBSCRIBE_EVENT, + 0, 0, subsc_evt, false); return 0; } @@ -317,9 +317,8 @@ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, if (priv->is_data_rate_auto) priv->data_rate = 0; else - return mwifiex_send_cmd_async(priv, - HostCmd_CMD_802_11_TX_RATE_QUERY, - HostCmd_ACT_GEN_GET, 0, NULL); + return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_TX_RATE_QUERY, + HostCmd_ACT_GEN_GET, 0, NULL, false); return 0; } diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 92ff7b324b00..fd2a7165cfa5 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -293,9 +293,8 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_HS_ACT_REQ: dev_dbg(adapter->dev, "event: HS_ACT_REQ\n"); - ret = mwifiex_send_cmd_async(priv, - HostCmd_CMD_802_11_HS_CFG_ENH, - 0, 0, NULL); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_HS_CFG_ENH, + 0, 0, NULL, false); break; case EVENT_MIC_ERR_UNICAST: @@ -326,9 +325,8 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_BG_SCAN_REPORT: dev_dbg(adapter->dev, "event: BGS_REPORT\n"); - ret = mwifiex_send_cmd_async(priv, - HostCmd_CMD_802_11_BG_SCAN_QUERY, - HostCmd_ACT_GEN_GET, 0, NULL); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_QUERY, + HostCmd_ACT_GEN_GET, 0, NULL, false); break; case EVENT_PORT_RELEASE: @@ -345,16 +343,16 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_WMM_STATUS_CHANGE: dev_dbg(adapter->dev, "event: WMM status changed\n"); - ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_WMM_GET_STATUS, - 0, 0, NULL); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_WMM_GET_STATUS, + 0, 0, NULL, false); break; case EVENT_RSSI_LOW: cfg80211_cqm_rssi_notify(priv->netdev, NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, GFP_KERNEL); - mwifiex_send_cmd_async(priv, HostCmd_CMD_RSSI_INFO, - HostCmd_ACT_GEN_GET, 0, NULL); + mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO, + HostCmd_ACT_GEN_GET, 0, NULL, false); priv->subsc_evt_rssi_state = RSSI_LOW_RECVD; dev_dbg(adapter->dev, "event: Beacon RSSI_LOW\n"); break; @@ -368,8 +366,8 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) cfg80211_cqm_rssi_notify(priv->netdev, NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, GFP_KERNEL); - mwifiex_send_cmd_async(priv, HostCmd_CMD_RSSI_INFO, - HostCmd_ACT_GEN_GET, 0, NULL); + mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO, + HostCmd_ACT_GEN_GET, 0, NULL, false); priv->subsc_evt_rssi_state = RSSI_HIGH_RECVD; dev_dbg(adapter->dev, "event: Beacon RSSI_HIGH\n"); break; @@ -396,15 +394,15 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) break; case EVENT_IBSS_COALESCED: dev_dbg(adapter->dev, "event: IBSS_COALESCED\n"); - ret = mwifiex_send_cmd_async(priv, + ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, - HostCmd_ACT_GEN_GET, 0, NULL); + HostCmd_ACT_GEN_GET, 0, NULL, false); break; case EVENT_ADDBA: dev_dbg(adapter->dev, "event: ADDBA Request\n"); - mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_RSP, - HostCmd_ACT_GEN_SET, 0, - adapter->event_body); + mwifiex_send_cmd(priv, HostCmd_CMD_11N_ADDBA_RSP, + HostCmd_ACT_GEN_SET, 0, + adapter->event_body, false); break; case EVENT_DELBA: dev_dbg(adapter->dev, "event: DELBA Request\n"); @@ -455,10 +453,10 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) priv->csa_expire_time = jiffies + msecs_to_jiffies(DFS_CHAN_MOVE_TIME); priv->csa_chan = priv->curr_bss_params.bss_descriptor.channel; - ret = mwifiex_send_cmd_async(priv, - HostCmd_CMD_802_11_DEAUTHENTICATE, + ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_DEAUTHENTICATE, HostCmd_ACT_GEN_SET, 0, - priv->curr_bss_params.bss_descriptor.mac_address); + priv->curr_bss_params.bss_descriptor.mac_address, + false); break; default: diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index b393d55b3aa0..33170af150f6 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -108,19 +108,19 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, "info: Set multicast list=%d\n", mcast_list->num_multicast_addr); /* Send multicast addresses to firmware */ - ret = mwifiex_send_cmd_async(priv, - HostCmd_CMD_MAC_MULTICAST_ADR, - HostCmd_ACT_GEN_SET, 0, - mcast_list); + ret = mwifiex_send_cmd(priv, + HostCmd_CMD_MAC_MULTICAST_ADR, + HostCmd_ACT_GEN_SET, 0, + mcast_list, false); } } dev_dbg(priv->adapter->dev, "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n", old_pkt_filter, priv->curr_pkt_filter); if (old_pkt_filter != priv->curr_pkt_filter) { - ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, - HostCmd_ACT_GEN_SET, - 0, &priv->curr_pkt_filter); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, + 0, &priv->curr_pkt_filter, false); } return ret; @@ -237,8 +237,8 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv, rcu_read_unlock(); - if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, - HostCmd_ACT_GEN_SET, 0, NULL)) { + if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, + HostCmd_ACT_GEN_SET, 0, NULL, false)) { wiphy_err(priv->adapter->wiphy, "11D: setting domain info in FW\n"); return -1; @@ -429,16 +429,13 @@ static int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, status = -1; break; } - if (cmd_type == MWIFIEX_SYNC_CMD) - status = mwifiex_send_cmd_sync(priv, - HostCmd_CMD_802_11_HS_CFG_ENH, - HostCmd_ACT_GEN_SET, 0, - &adapter->hs_cfg); - else - status = mwifiex_send_cmd_async(priv, - HostCmd_CMD_802_11_HS_CFG_ENH, - HostCmd_ACT_GEN_SET, 0, - &adapter->hs_cfg); + + status = mwifiex_send_cmd(priv, + HostCmd_CMD_802_11_HS_CFG_ENH, + HostCmd_ACT_GEN_SET, 0, + &adapter->hs_cfg, + cmd_type == MWIFIEX_SYNC_CMD); + if (hs_cfg->conditions == HS_CFG_CANCEL) /* Restore previous condition */ adapter->hs_cfg.conditions = @@ -586,8 +583,8 @@ int mwifiex_disable_auto_ds(struct mwifiex_private *priv) auto_ds.auto_ds = DEEP_SLEEP_OFF; - return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_PS_MODE_ENH, - DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds); + return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, + DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds, true); } EXPORT_SYMBOL_GPL(mwifiex_disable_auto_ds); @@ -601,8 +598,8 @@ int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, u32 *rate) { int ret; - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_TX_RATE_QUERY, - HostCmd_ACT_GEN_GET, 0, NULL); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_TX_RATE_QUERY, + HostCmd_ACT_GEN_GET, 0, NULL, true); if (!ret) { if (priv->is_data_rate_auto) @@ -698,8 +695,8 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv, pg->power_max = (s8) dbm; pg->ht_bandwidth = HT_BW_40; } - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TXPWR_CFG, - HostCmd_ACT_GEN_SET, 0, buf); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_TXPWR_CFG, + HostCmd_ACT_GEN_SET, 0, buf, true); kfree(buf); return ret; @@ -722,12 +719,11 @@ int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode) else adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS; - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_PS_MODE_ENH, - sub_cmd, BITMAP_STA_PS, NULL); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, + sub_cmd, BITMAP_STA_PS, NULL, true); if ((!ret) && (sub_cmd == DIS_AUTO_PS)) - ret = mwifiex_send_cmd_async(priv, - HostCmd_CMD_802_11_PS_MODE_ENH, - GET_PS, 0, NULL); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, + GET_PS, 0, NULL, false); return ret; } @@ -851,9 +847,9 @@ static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private *priv, struct mwifiex_ds_encrypt_key *encrypt_key) { - return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_KEY_MATERIAL, - HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, - encrypt_key); + return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, + encrypt_key, true); } /* @@ -917,9 +913,8 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, enc_key = NULL; /* Send request to firmware */ - ret = mwifiex_send_cmd_async(priv, - HostCmd_CMD_802_11_KEY_MATERIAL, - HostCmd_ACT_GEN_SET, 0, enc_key); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, 0, enc_key, false); if (ret) return ret; } @@ -929,9 +924,9 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, else priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL, - HostCmd_ACT_GEN_SET, 0, - &priv->curr_pkt_filter); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, + &priv->curr_pkt_filter, true); return ret; } @@ -966,10 +961,9 @@ static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv, */ /* Send the key as PTK to firmware */ encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; - ret = mwifiex_send_cmd_async(priv, - HostCmd_CMD_802_11_KEY_MATERIAL, - HostCmd_ACT_GEN_SET, - KEY_INFO_ENABLED, encrypt_key); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, + KEY_INFO_ENABLED, encrypt_key, false); if (ret) return ret; @@ -993,15 +987,13 @@ static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv, encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; if (remove_key) - ret = mwifiex_send_cmd_sync(priv, - HostCmd_CMD_802_11_KEY_MATERIAL, - HostCmd_ACT_GEN_SET, - !KEY_INFO_ENABLED, encrypt_key); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, + !KEY_INFO_ENABLED, encrypt_key, true); else - ret = mwifiex_send_cmd_sync(priv, - HostCmd_CMD_802_11_KEY_MATERIAL, - HostCmd_ACT_GEN_SET, - KEY_INFO_ENABLED, encrypt_key); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, + KEY_INFO_ENABLED, encrypt_key, true); return ret; } @@ -1105,8 +1097,8 @@ mwifiex_get_ver_ext(struct mwifiex_private *priv) struct mwifiex_ver_ext ver_ext; memset(&ver_ext, 0, sizeof(struct host_cmd_ds_version_ext)); - if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_VERSION_EXT, - HostCmd_ACT_GEN_GET, 0, &ver_ext)) + if (mwifiex_send_cmd(priv, HostCmd_CMD_VERSION_EXT, + HostCmd_ACT_GEN_GET, 0, &ver_ext, true)) return -1; return 0; @@ -1131,8 +1123,8 @@ mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action, ieee80211_frequency_to_channel(chan->center_freq); roc_cfg.duration = cpu_to_le32(duration); } - if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_REMAIN_ON_CHAN, - action, 0, &roc_cfg)) { + if (mwifiex_send_cmd(priv, HostCmd_CMD_REMAIN_ON_CHAN, + action, 0, &roc_cfg, true)) { dev_err(priv->adapter->dev, "failed to remain on channel\n"); return -1; } @@ -1164,8 +1156,8 @@ mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role) break; } - mwifiex_send_cmd_sync(priv, HostCmd_CMD_SET_BSS_MODE, - HostCmd_ACT_GEN_SET, 0, NULL); + mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, + HostCmd_ACT_GEN_SET, 0, NULL, true); return mwifiex_sta_init_cmd(priv, false); } @@ -1180,8 +1172,8 @@ int mwifiex_get_stats_info(struct mwifiex_private *priv, struct mwifiex_ds_get_stats *log) { - return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG, - HostCmd_ACT_GEN_GET, 0, log); + return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_GET_LOG, + HostCmd_ACT_GEN_GET, 0, log, true); } /* @@ -1223,8 +1215,7 @@ static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv, return -1; } - return mwifiex_send_cmd_sync(priv, cmd_no, action, 0, reg_rw); - + return mwifiex_send_cmd(priv, cmd_no, action, 0, reg_rw, true); } /* @@ -1289,8 +1280,8 @@ mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes, rd_eeprom.byte_count = cpu_to_le16((u16) bytes); /* Send request to firmware */ - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_EEPROM_ACCESS, - HostCmd_ACT_GEN_GET, 0, &rd_eeprom); + ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_EEPROM_ACCESS, + HostCmd_ACT_GEN_GET, 0, &rd_eeprom, true); if (!ret) memcpy(value, rd_eeprom.value, MAX_EEPROM_DATA); diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index 1ba2a16ee471..8cec6e4ba8c4 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -864,8 +864,8 @@ mwifiex_tdls_process_config_link(struct mwifiex_private *priv, u8 *peer) memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN); tdls_oper.tdls_action = MWIFIEX_TDLS_CONFIG_LINK; - return mwifiex_send_cmd_sync(priv, HostCmd_CMD_TDLS_OPER, - HostCmd_ACT_GEN_SET, 0, &tdls_oper); + return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER, + HostCmd_ACT_GEN_SET, 0, &tdls_oper, true); } static int @@ -891,8 +891,8 @@ mwifiex_tdls_process_create_link(struct mwifiex_private *priv, u8 *peer) mwifiex_hold_tdls_packets(priv, peer); memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN); tdls_oper.tdls_action = MWIFIEX_TDLS_CREATE_LINK; - return mwifiex_send_cmd_sync(priv, HostCmd_CMD_TDLS_OPER, - HostCmd_ACT_GEN_SET, 0, &tdls_oper); + return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER, + HostCmd_ACT_GEN_SET, 0, &tdls_oper, true); } static int @@ -920,8 +920,8 @@ mwifiex_tdls_process_disable_link(struct mwifiex_private *priv, u8 *peer) mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN); memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN); tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK; - return mwifiex_send_cmd_sync(priv, HostCmd_CMD_TDLS_OPER, - HostCmd_ACT_GEN_SET, 0, &tdls_oper); + return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER, + HostCmd_ACT_GEN_SET, 0, &tdls_oper, true); } static int @@ -1033,8 +1033,8 @@ void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv) TDLS_LINK_TEARDOWN); memcpy(&tdls_oper.peer_mac, sta_ptr->mac_addr, ETH_ALEN); tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK; - if (mwifiex_send_cmd_async(priv, HostCmd_CMD_TDLS_OPER, - HostCmd_ACT_GEN_SET, 0, &tdls_oper)) + if (mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER, + HostCmd_ACT_GEN_SET, 0, &tdls_oper, false)) dev_warn(priv->adapter->dev, "Disable link failed for TDLS peer %pM", sta_ptr->mac_addr); diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index 64424c81b44f..a6a6a53cda40 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c @@ -226,8 +226,8 @@ void mwifiex_set_vht_width(struct mwifiex_private *priv, if (ap_11ac_enable && width >= NL80211_CHAN_WIDTH_80) vht_cfg.misc_config |= VHT_BW_80_160_80P80; - mwifiex_send_cmd_sync(priv, HostCmd_CMD_11AC_CFG, - HostCmd_ACT_GEN_SET, 0, &vht_cfg); + mwifiex_send_cmd(priv, HostCmd_CMD_11AC_CFG, + HostCmd_ACT_GEN_SET, 0, &vht_cfg, true); return; } diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index 2d47ba70225c..ae50e916d8f2 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -150,9 +150,9 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) case EVENT_ADDBA: dev_dbg(adapter->dev, "event: ADDBA Request\n"); if (priv->media_connected) - mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_RSP, - HostCmd_ACT_GEN_SET, 0, - adapter->event_body); + mwifiex_send_cmd(priv, HostCmd_CMD_11N_ADDBA_RSP, + HostCmd_ACT_GEN_SET, 0, + adapter->event_body, false); break; case EVENT_DELBA: dev_dbg(adapter->dev, "event: DELBA Request\n"); diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 8d37bfc578bd..098de8810729 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -72,7 +72,7 @@ int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, return -1; } - return mwifiex_send_cmd_sync(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL); + return mwifiex_send_cmd(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL, true); } EXPORT_SYMBOL_GPL(mwifiex_init_shutdown_fw); From 828cf2222f05a22e51cdde4fb959d256bf31613b Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 27 Feb 2014 19:35:13 -0800 Subject: [PATCH 367/414] mwifiex: change transmit buffer size for 8897 Currently default Tx buffer size configured to firmware is 2K for all chipsets. This patch changes it to 4K for SD/PCIe/USB 8897 chipsets as per firmware requirements. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/init.c | 1 - drivers/net/wireless/mwifiex/pcie.c | 2 ++ drivers/net/wireless/mwifiex/pcie.h | 3 +++ drivers/net/wireless/mwifiex/sdio.c | 2 ++ drivers/net/wireless/mwifiex/sdio.h | 6 ++++++ drivers/net/wireless/mwifiex/usb.c | 2 ++ 6 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 759492817aeb..4ecd0b208ac6 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -234,7 +234,6 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) adapter->pm_wakeup_fw_try = false; - adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; adapter->is_hs_configured = false; diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index d11d4acf0890..92c31b5c269c 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -190,6 +190,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, card->pcie.firmware = data->firmware; card->pcie.reg = data->reg; card->pcie.blksz_fw_dl = data->blksz_fw_dl; + card->pcie.tx_buf_size = data->tx_buf_size; } if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops, @@ -2320,6 +2321,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) } adapter->dev = &pdev->dev; + adapter->tx_buf_size = card->pcie.tx_buf_size; strcpy(adapter->fw_name, card->pcie.firmware); return 0; diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h index d322ab8604ea..193af75bf582 100644 --- a/drivers/net/wireless/mwifiex/pcie.h +++ b/drivers/net/wireless/mwifiex/pcie.h @@ -195,18 +195,21 @@ struct mwifiex_pcie_device { const char *firmware; const struct mwifiex_pcie_card_reg *reg; u16 blksz_fw_dl; + u16 tx_buf_size; }; static const struct mwifiex_pcie_device mwifiex_pcie8766 = { .firmware = PCIE8766_DEFAULT_FW_NAME, .reg = &mwifiex_reg_8766, .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, + .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, }; static const struct mwifiex_pcie_device mwifiex_pcie8897 = { .firmware = PCIE8897_DEFAULT_FW_NAME, .reg = &mwifiex_reg_8897, .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, + .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, }; struct mwifiex_evt_buf_desc { diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index b44a31523461..d5661a6209be 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -84,6 +84,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) card->mp_agg_pkt_limit = data->mp_agg_pkt_limit; card->supports_sdio_new_mode = data->supports_sdio_new_mode; card->has_control_mask = data->has_control_mask; + card->tx_buf_size = data->tx_buf_size; } sdio_claim_host(func); @@ -1760,6 +1761,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) /* save adapter pointer in card */ card->adapter = adapter; + adapter->tx_buf_size = card->tx_buf_size; sdio_claim_host(func); diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index 532ae0ac4dfb..c71201b2e2a3 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -233,6 +233,7 @@ struct sdio_mmc_card { u8 mp_agg_pkt_limit; bool supports_sdio_new_mode; bool has_control_mask; + u16 tx_buf_size; u32 mp_rd_bitmap; u32 mp_wr_bitmap; @@ -256,6 +257,7 @@ struct mwifiex_sdio_device { u8 mp_agg_pkt_limit; bool supports_sdio_new_mode; bool has_control_mask; + u16 tx_buf_size; }; static const struct mwifiex_sdio_card_reg mwifiex_reg_sd87xx = { @@ -312,6 +314,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = { .mp_agg_pkt_limit = 8, .supports_sdio_new_mode = false, .has_control_mask = true, + .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = { @@ -321,6 +324,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = { .mp_agg_pkt_limit = 8, .supports_sdio_new_mode = false, .has_control_mask = true, + .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = { @@ -330,6 +334,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = { .mp_agg_pkt_limit = 8, .supports_sdio_new_mode = false, .has_control_mask = true, + .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { @@ -339,6 +344,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { .mp_agg_pkt_limit = 16, .supports_sdio_new_mode = true, .has_control_mask = false, + .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, }; /* diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index e8ebbd4bc3cd..21d1316adaa0 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -776,11 +776,13 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) switch (le16_to_cpu(card->udev->descriptor.idProduct)) { case USB8897_PID_1: case USB8897_PID_2: + adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K; strcpy(adapter->fw_name, USB8897_DEFAULT_FW_NAME); break; case USB8797_PID_1: case USB8797_PID_2: default: + adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; strcpy(adapter->fw_name, USB8797_DEFAULT_FW_NAME); break; } From 4af2bd49e6777d39db9bafc868860f0cfdd04652 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 27 Feb 2014 19:35:15 -0800 Subject: [PATCH 368/414] mwifiex: abort scan while cancelling pending command mwifiex_cancel_pending_ioctl() and mwifiex_cancel_all_pending_cmd() are called in command timeout and driver unload paths respectively. If scan operation is in progress, we should abort it smoothly. Reported-by: Tim Shepard Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cmdevt.c | 38 ++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 64e708b79f0e..58cf3a98f1f7 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -966,7 +966,9 @@ void mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) { struct cmd_ctrl_node *cmd_node = NULL, *tmp_node; - unsigned long flags; + unsigned long flags, cmd_flags; + struct mwifiex_private *priv; + int i; /* Cancel current cmd */ if ((adapter->curr_cmd) && (adapter->curr_cmd->wait_q_enabled)) { @@ -1006,9 +1008,21 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) } spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); - spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); - adapter->scan_processing = false; - spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + if (adapter->scan_processing) { + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); + adapter->scan_processing = false; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (!priv) + continue; + if (priv->scan_request) { + dev_dbg(adapter->dev, "info: aborting scan\n"); + cfg80211_scan_done(priv->scan_request, 1); + priv->scan_request = NULL; + } + } + } } /* @@ -1027,7 +1041,8 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; unsigned long cmd_flags; unsigned long scan_pending_q_flags; - bool cancel_scan_cmd = false; + struct mwifiex_private *priv; + int i; if ((adapter->curr_cmd) && (adapter->curr_cmd->wait_q_enabled)) { @@ -1053,15 +1068,24 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) mwifiex_insert_cmd_to_free_q(adapter, cmd_node); spin_lock_irqsave(&adapter->scan_pending_q_lock, scan_pending_q_flags); - cancel_scan_cmd = true; } spin_unlock_irqrestore(&adapter->scan_pending_q_lock, scan_pending_q_flags); - if (cancel_scan_cmd) { + if (adapter->scan_processing) { spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); adapter->scan_processing = false; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (!priv) + continue; + if (priv->scan_request) { + dev_dbg(adapter->dev, "info: aborting scan\n"); + cfg80211_scan_done(priv->scan_request, 1); + priv->scan_request = NULL; + } + } } adapter->cmd_wait_q.status = -1; } From ace273551b7c9c2cfbfc606ac4cd518c67f80faf Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 27 Feb 2014 19:35:16 -0800 Subject: [PATCH 369/414] mwifiex: skipping pending commands after unload We skip downloading other commands after FUNC_SHUTDOWN is queued during driver unload. Main thread should be woken up each time after freeing skipped command so that FUNC_SHUTDOWN gets served in case if there are other pending commands before FUNC_SHUTDOWN. Also, call mwifiex_complete_cmd() only for synchronous commands. Reported-by: Avery Pennarun Signed-off-by: Amitkumar Karwar Signed-off-by: Maithili Hinge Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cmdevt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 58cf3a98f1f7..0958764d2bae 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -165,8 +165,10 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, dev_err(adapter->dev, "DNLD_CMD: FW in reset state, ignore cmd %#x\n", cmd_code); - mwifiex_complete_cmd(adapter, cmd_node); + if (cmd_node->wait_q_enabled) + mwifiex_complete_cmd(adapter, cmd_node); mwifiex_recycle_cmd_node(adapter, cmd_node); + queue_work(adapter->workqueue, &adapter->main_work); return -1; } From 848819f43878a3a3f7c659fee3b6e16c334c3062 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 27 Feb 2014 19:35:17 -0800 Subject: [PATCH 370/414] mwifiex: stop AP at shutdown time Deauth is sent to AP when the device is acting as station at shutdown time. Similarly we should stop AP operation also. mwifiex_deauthenticate() takes care closing the connection based on provided interface type. Add a new function to simplify the code. Reported-by: Avery Pennarun Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/join.c | 15 ++++++++++++++- drivers/net/wireless/mwifiex/main.h | 1 + drivers/net/wireless/mwifiex/pcie.c | 7 +------ drivers/net/wireless/mwifiex/sdio.c | 7 +------ drivers/net/wireless/mwifiex/usb.c | 8 ++------ 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index e9bd43526d80..89dc62a467f4 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -1443,7 +1443,20 @@ int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac) return ret; } -EXPORT_SYMBOL_GPL(mwifiex_deauthenticate); + +/* This function deauthenticates/disconnects from all BSS. */ +void mwifiex_deauthenticate_all(struct mwifiex_adapter *adapter) +{ + struct mwifiex_private *priv; + int i; + + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (priv) + mwifiex_deauthenticate(priv, NULL); + } +} +EXPORT_SYMBOL_GPL(mwifiex_deauthenticate_all); /* * This function converts band to radio type used in channel TLV. diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 6c04baa5bcf9..e9d64fc7d786 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -927,6 +927,7 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, void mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason); u8 mwifiex_band_to_radio_type(u8 band); int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac); +void mwifiex_deauthenticate_all(struct mwifiex_adapter *adapter); int mwifiex_adhoc_start(struct mwifiex_private *priv, struct cfg80211_ssid *adhoc_ssid); int mwifiex_adhoc_join(struct mwifiex_private *priv, diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 92c31b5c269c..d2af2127b41a 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -211,7 +211,6 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev) struct pcie_service_card *card; struct mwifiex_adapter *adapter; struct mwifiex_private *priv; - int i; card = pci_get_drvdata(pdev); if (!card) @@ -230,11 +229,7 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev) mwifiex_pcie_resume(&pdev->dev); #endif - for (i = 0; i < adapter->priv_num; i++) - if ((GET_BSS_ROLE(adapter->priv[i]) == - MWIFIEX_BSS_ROLE_STA) && - adapter->priv[i]->media_connected) - mwifiex_deauthenticate(adapter->priv[i], NULL); + mwifiex_deauthenticate_all(adapter); priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index d5661a6209be..e0dcd3ed7a69 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -166,7 +166,6 @@ mwifiex_sdio_remove(struct sdio_func *func) struct sdio_mmc_card *card; struct mwifiex_adapter *adapter; struct mwifiex_private *priv; - int i; pr_debug("info: SDIO func num=%d\n", func->num); @@ -185,11 +184,7 @@ mwifiex_sdio_remove(struct sdio_func *func) if (adapter->is_suspended) mwifiex_sdio_resume(adapter->dev); - for (i = 0; i < adapter->priv_num; i++) - if ((GET_BSS_ROLE(adapter->priv[i]) == - MWIFIEX_BSS_ROLE_STA) && - adapter->priv[i]->media_connected) - mwifiex_deauthenticate(adapter->priv[i], NULL); + mwifiex_deauthenticate_all(adapter); priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); mwifiex_disable_auto_ds(priv); diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 21d1316adaa0..93d5d73c4800 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -1036,7 +1036,6 @@ static void mwifiex_usb_cleanup_module(void) if (usb_card && usb_card->adapter) { struct mwifiex_adapter *adapter = usb_card->adapter; - int i; /* In case driver is removed when asynchronous FW downloading is * in progress @@ -1047,11 +1046,8 @@ static void mwifiex_usb_cleanup_module(void) if (adapter->is_suspended) mwifiex_usb_resume(usb_card->intf); #endif - for (i = 0; i < adapter->priv_num; i++) - if ((GET_BSS_ROLE(adapter->priv[i]) == - MWIFIEX_BSS_ROLE_STA) && - adapter->priv[i]->media_connected) - mwifiex_deauthenticate(adapter->priv[i], NULL); + + mwifiex_deauthenticate_all(adapter); mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY), From 81c7883c46fddd53b7a98c3659ffae21189ae4ab Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Tue, 25 Feb 2014 20:30:35 +0100 Subject: [PATCH 371/414] brcmfmac: Put frame sdio tx error handling in sub function. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../wireless/brcm80211/brcmfmac/dhd_sdio.c | 112 ++++++------------ 1 file changed, 33 insertions(+), 79 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 0ccb7affeb04..c894ee358153 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -1237,6 +1237,28 @@ static void brcmf_sdio_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx) bus->cur_read.len = 0; } +static void brcmf_sdio_txfail(struct brcmf_sdio *bus) +{ + struct brcmf_sdio_dev *sdiodev = bus->sdiodev; + u8 i, hi, lo; + + /* On failure, abort the command and terminate the frame */ + brcmf_err("sdio error, abort command and terminate frame\n"); + bus->sdcnt.tx_sderrs++; + + brcmf_sdiod_abort(sdiodev, SDIO_FUNC_2); + brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, NULL); + bus->sdcnt.f1regdata++; + + for (i = 0; i < 3; i++) { + hi = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_WFRAMEBCHI, NULL); + lo = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_WFRAMEBCLO, NULL); + bus->sdcnt.f1regdata += 2; + if ((hi == 0) && (lo == 0)) + break; + } +} + /* return total length of buffer chain */ static uint brcmf_sdio_glom_len(struct brcmf_sdio *bus) { @@ -2252,7 +2274,6 @@ static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq, uint chan) { int ret; - int i; struct sk_buff *pkt_next, *tmp; brcmf_dbg(TRACE, "Enter\n"); @@ -2265,28 +2286,9 @@ static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq, ret = brcmf_sdiod_send_pkt(bus->sdiodev, pktq); bus->sdcnt.f2txdata++; - if (ret < 0) { - /* On failure, abort the command and terminate the frame */ - brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", - ret); - bus->sdcnt.tx_sderrs++; + if (ret < 0) + brcmf_sdio_txfail(bus); - brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2); - brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL, - SFC_WF_TERM, NULL); - bus->sdcnt.f1regdata++; - - for (i = 0; i < 3; i++) { - u8 hi, lo; - hi = brcmf_sdiod_regrb(bus->sdiodev, - SBSDIO_FUNC1_WFRAMEBCHI, NULL); - lo = brcmf_sdiod_regrb(bus->sdiodev, - SBSDIO_FUNC1_WFRAMEBCLO, NULL); - bus->sdcnt.f1regdata += 2; - if ((hi == 0) && (lo == 0)) - break; - } - } sdio_release_host(bus->sdiodev->func[1]); done: @@ -2588,42 +2590,17 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) brcmf_sdio_clrintr(bus); if (data_ok(bus) && bus->ctrl_frame_stat && - (bus->clkstate == CLK_AVAIL)) { - int i; + (bus->clkstate == CLK_AVAIL)) { sdio_claim_host(bus->sdiodev->func[1]); err = brcmf_sdiod_send_buf(bus->sdiodev, bus->ctrl_frame_buf, (u32)bus->ctrl_frame_len); - if (err < 0) { - /* On failure, abort the command and - terminate the frame */ - brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", - err); - bus->sdcnt.tx_sderrs++; - - brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2); - - brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL, - SFC_WF_TERM, &err); - bus->sdcnt.f1regdata++; - - for (i = 0; i < 3; i++) { - u8 hi, lo; - hi = brcmf_sdiod_regrb(bus->sdiodev, - SBSDIO_FUNC1_WFRAMEBCHI, - &err); - lo = brcmf_sdiod_regrb(bus->sdiodev, - SBSDIO_FUNC1_WFRAMEBCLO, - &err); - bus->sdcnt.f1regdata += 2; - if ((hi == 0) && (lo == 0)) - break; - } - - } else { + if (err < 0) + brcmf_sdio_txfail(bus); + else bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP; - } + sdio_release_host(bus->sdiodev->func[1]); bus->ctrl_frame_stat = false; brcmf_sdio_wait_event_wakeup(bus); @@ -2793,38 +2770,15 @@ break2: static int brcmf_sdio_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len) { - int i; int ret; bus->ctrl_frame_stat = false; ret = brcmf_sdiod_send_buf(bus->sdiodev, frame, len); - if (ret < 0) { - /* On failure, abort the command and terminate the frame */ - brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", - ret); - bus->sdcnt.tx_sderrs++; - - brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2); - - brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL, - SFC_WF_TERM, NULL); - bus->sdcnt.f1regdata++; - - for (i = 0; i < 3; i++) { - u8 hi, lo; - hi = brcmf_sdiod_regrb(bus->sdiodev, - SBSDIO_FUNC1_WFRAMEBCHI, NULL); - lo = brcmf_sdiod_regrb(bus->sdiodev, - SBSDIO_FUNC1_WFRAMEBCLO, NULL); - bus->sdcnt.f1regdata += 2; - if (hi == 0 && lo == 0) - break; - } - return ret; - } - - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP; + if (ret < 0) + brcmf_sdio_txfail(bus); + else + bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP; return ret; } From 4aca7a185aeba4472e7a798e5d834d7702ebbeca Mon Sep 17 00:00:00 2001 From: Daniel Kim Date: Tue, 25 Feb 2014 20:30:36 +0100 Subject: [PATCH 372/414] brcmfmac: Correct mcs index report There is a mismatch between the mcs index(0-7) reported to cfg80211 and the actual mcs index(0-15) in use. This patch resolves the mismatch by setting mcs info with the number of chains read from FW. Reviewed-by: Arend Van Spriel Signed-off-by: Daniel Kim Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../wireless/brcm80211/brcmfmac/wl_cfg80211.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 474df2ce6e3b..00bd1e16c3ce 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -5306,6 +5306,8 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg) u32 band_list[3]; u32 nmode; u32 bw_cap[2] = { 0, 0 }; + u32 rxchain; + u32 nchain; s8 phy; s32 err; u32 nband; @@ -5342,6 +5344,16 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg) brcmf_dbg(INFO, "nmode=%d, bw_cap=(%d, %d)\n", nmode, bw_cap[IEEE80211_BAND_2GHZ], bw_cap[IEEE80211_BAND_5GHZ]); + err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain); + if (err) { + brcmf_err("rxchain error (%d)\n", err); + nchain = 1; + } else { + for (nchain = 0; rxchain; nchain++) + rxchain = rxchain & (rxchain - 1); + } + brcmf_dbg(INFO, "nchain=%d\n", nchain); + err = brcmf_construct_reginfo(cfg, bw_cap); if (err) { brcmf_err("brcmf_construct_reginfo failed (%d)\n", err); @@ -5370,10 +5382,7 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg) band->ht_cap.ht_supported = true; band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; - /* An HT shall support all EQM rates for one spatial - * stream - */ - band->ht_cap.mcs.rx_mask[0] = 0xff; + memset(band->ht_cap.mcs.rx_mask, 0xff, nchain); band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; bands[band->band] = band; } From af1fa210f4fc6e304b859b386a3c8a266b1110ab Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Thu, 27 Feb 2014 19:25:00 +0100 Subject: [PATCH 373/414] brcmfmac: use pre-allocated scatter-gather table for txglomming Instead of allocating a scatter-gather table for every transmit reuse a pre-allocated table. The transmit path will be faster by taking out this allocation. Reviewed-by: Daniel (Deognyoun) Kim Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmfmac/bcmsdh.c | 47 +++++++++++++++---- .../wireless/brcm80211/brcmfmac/dhd_sdio.c | 8 +--- .../wireless/brcm80211/brcmfmac/sdio_host.h | 2 + 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 07e7d2520257..9eea7d4dd501 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -53,6 +53,12 @@ /* Maximum milliseconds to wait for F2 to come up */ #define SDIO_WAIT_F2RDY 3000 +#define BRCMF_DEFAULT_TXGLOM_SIZE 32 /* max tx frames in glom chain */ +#define BRCMF_DEFAULT_RXGLOM_SIZE 32 /* max rx frames in glom chain */ + +static int brcmf_sdiod_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE; +module_param_named(txglomsz, brcmf_sdiod_txglomsz, int, 0); +MODULE_PARM_DESC(txglomsz, "maximum tx packet chain size [SDIO]"); static irqreturn_t brcmf_sdiod_oob_irqhandler(int irq, void *dev_id) { @@ -487,7 +493,6 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn, struct mmc_request mmc_req; struct mmc_command mmc_cmd; struct mmc_data mmc_dat; - struct sg_table st; struct scatterlist *sgl; int ret = 0; @@ -532,16 +537,11 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn, pkt_offset = 0; pkt_next = target_list->next; - if (sg_alloc_table(&st, max_seg_cnt, GFP_KERNEL)) { - ret = -ENOMEM; - goto exit; - } - memset(&mmc_req, 0, sizeof(struct mmc_request)); memset(&mmc_cmd, 0, sizeof(struct mmc_command)); memset(&mmc_dat, 0, sizeof(struct mmc_data)); - mmc_dat.sg = st.sgl; + mmc_dat.sg = sdiodev->sgtable.sgl; mmc_dat.blksz = func_blk_sz; mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; mmc_cmd.opcode = SD_IO_RW_EXTENDED; @@ -557,7 +557,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn, while (seg_sz) { req_sz = 0; sg_cnt = 0; - sgl = st.sgl; + sgl = sdiodev->sgtable.sgl; /* prep sg table */ while (pkt_next != (struct sk_buff *)target_list) { pkt_data = pkt_next->data + pkt_offset; @@ -639,7 +639,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn, } exit: - sg_free_table(&st); + sg_init_table(sdiodev->sgtable.sgl, sdiodev->sgtable.orig_nents); while ((pkt_next = __skb_dequeue(&local_list)) != NULL) brcmu_pkt_buf_free_skb(pkt_next); @@ -863,6 +863,29 @@ int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn) return 0; } +static void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev) +{ + uint nents; + int err; + + if (!sdiodev->sg_support) + return; + + nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE, brcmf_sdiod_txglomsz); + nents += (nents >> 4) + 1; + + WARN_ON(nents > sdiodev->max_segment_count); + + brcmf_dbg(TRACE, "nents=%d\n", nents); + err = sg_alloc_table(&sdiodev->sgtable, nents, GFP_KERNEL); + if (err < 0) { + brcmf_err("allocation failed: disable scatter-gather"); + sdiodev->sg_support = false; + } + + sdiodev->txglomsz = brcmf_sdiod_txglomsz; +} + static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev) { if (sdiodev->bus) { @@ -880,6 +903,7 @@ static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev) sdio_disable_func(sdiodev->func[1]); sdio_release_host(sdiodev->func[1]); + sg_free_table(&sdiodev->sgtable); sdiodev->sbwad = 0; return 0; @@ -935,6 +959,11 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev) SG_MAX_SINGLE_ALLOC); sdiodev->max_segment_size = host->max_seg_size; + /* allocate scatter-gather table. sg support + * will be disabled upon allocation failure. + */ + brcmf_sdiod_sgtable_alloc(sdiodev); + /* try to attach to the target device */ sdiodev->bus = brcmf_sdio_probe(sdiodev); if (!sdiodev->bus) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index c894ee358153..b5ded8a57cb0 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -113,8 +113,6 @@ struct rte_console { #define BRCMF_TXBOUND 20 /* Default for max tx frames in one scheduling */ -#define BRCMF_DEFAULT_TXGLOM_SIZE 32 /* max tx frames in glom chain */ - #define BRCMF_TXMINMAX 1 /* Max tx frames if rx still pending */ #define MEMBLOCK 2048 /* Block size used for downloading @@ -511,10 +509,6 @@ static const uint max_roundup = 512; #define ALIGNMENT 4 -static int brcmf_sdio_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE; -module_param_named(txglomsz, brcmf_sdio_txglomsz, int, 0); -MODULE_PARM_DESC(txglomsz, "maximum tx packet chain size [SDIO]"); - enum brcmf_sdio_frmtype { BRCMF_SDIO_FT_NORMAL, BRCMF_SDIO_FT_SUPER, @@ -2321,7 +2315,7 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes) __skb_queue_head_init(&pktq); if (bus->txglom) pkt_num = min_t(u8, bus->tx_max - bus->tx_seq, - brcmf_sdio_txglomsz); + bus->sdiodev->txglomsz); pkt_num = min_t(u32, pkt_num, brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol)); spin_lock_bh(&bus->txqlock); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h index 5e53eb1b2ffa..3deab7959a0d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h @@ -180,6 +180,8 @@ struct brcmf_sdio_dev { uint max_request_size; ushort max_segment_count; uint max_segment_size; + uint txglomsz; + struct sg_table sgtable; }; /* sdio core registers */ From 38ec3f3f6142d1517ce0f1c96502fd1c05d2fc52 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 27 Feb 2014 19:35:15 -0800 Subject: [PATCH 374/414] mwifiex: block further commands after timeout This patch adds a check in command preparation routine. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cmdevt.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 0958764d2bae..83195d96e78c 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -514,6 +514,11 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no, return -1; } + if (adapter->num_cmd_timeout) { + dev_err(adapter->dev, "PREP_CMD: FW is in bad state\n"); + return -1; + } + if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET) { if (cmd_no != HostCmd_CMD_FUNC_INIT) { dev_err(adapter->dev, "PREP_CMD: FW in reset state\n"); From e50e06fd0418d5994fad8ca8d3ce049403059112 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 27 Feb 2014 19:35:16 -0800 Subject: [PATCH 375/414] mwifiex: get rid of extra num_cmd_timeout variable We already have one in mwifiex_adapter structure. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cmdevt.c | 3 +-- drivers/net/wireless/mwifiex/main.h | 1 - drivers/net/wireless/mwifiex/util.c | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 83195d96e78c..686943c52d18 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -892,7 +892,6 @@ mwifiex_cmd_timeout_func(unsigned long function_context) struct timeval tstamp; adapter->num_cmd_timeout++; - adapter->dbg.num_cmd_timeout++; if (!adapter->curr_cmd) { dev_dbg(adapter->dev, "cmd: empty curr_cmd\n"); return; @@ -916,7 +915,7 @@ mwifiex_cmd_timeout_func(unsigned long function_context) adapter->dbg.num_cmd_host_to_card_failure); dev_err(adapter->dev, "num_cmd_timeout = %d\n", - adapter->dbg.num_cmd_timeout); + adapter->num_cmd_timeout); dev_err(adapter->dev, "num_tx_timeout = %d\n", adapter->dbg.num_tx_timeout); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index e9d64fc7d786..df09ddb64eec 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -145,7 +145,6 @@ struct mwifiex_dbg { u32 num_cmd_assoc_success; u32 num_cmd_assoc_failure; u32 num_tx_timeout; - u32 num_cmd_timeout; u16 timeout_cmd_id; u16 timeout_cmd_act; u16 last_cmd_id[DBG_CMD_NUM]; diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 098de8810729..7022c69f0a29 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -104,6 +104,7 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv, info->pm_wakeup_fw_try = adapter->pm_wakeup_fw_try; info->is_hs_configured = adapter->is_hs_configured; info->hs_activated = adapter->hs_activated; + info->num_cmd_timeout = adapter->num_cmd_timeout; info->num_cmd_host_to_card_failure = adapter->dbg.num_cmd_host_to_card_failure; info->num_cmd_sleep_cfm_host_to_card_failure @@ -119,7 +120,6 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv, info->num_cmd_assoc_failure = adapter->dbg.num_cmd_assoc_failure; info->num_tx_timeout = adapter->dbg.num_tx_timeout; - info->num_cmd_timeout = adapter->dbg.num_cmd_timeout; info->timeout_cmd_id = adapter->dbg.timeout_cmd_id; info->timeout_cmd_act = adapter->dbg.timeout_cmd_act; memcpy(info->last_cmd_id, adapter->dbg.last_cmd_id, From 0c9c4a09f752e3cbe47fd5ea2d7f5f4837f95580 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 27 Feb 2014 19:35:17 -0800 Subject: [PATCH 376/414] mwifiex: replace num_cmd_timeout with is_cmd_timedout Command timeout happens when firmware goes into bad state. There is no chance that next command will be successful after this. Hence we will maintain a flag instead of count. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/README | 2 +- drivers/net/wireless/mwifiex/cmdevt.c | 10 +++++----- drivers/net/wireless/mwifiex/debugfs.c | 4 ++-- drivers/net/wireless/mwifiex/ioctl.h | 2 +- drivers/net/wireless/mwifiex/main.h | 2 +- drivers/net/wireless/mwifiex/sta_event.c | 2 +- drivers/net/wireless/mwifiex/util.c | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README index 3d64613ebb29..b9242c3dca43 100644 --- a/drivers/net/wireless/mwifiex/README +++ b/drivers/net/wireless/mwifiex/README @@ -131,7 +131,7 @@ info hs_configured = <0/1, host sleep not configured/configured> hs_activated = <0/1, extended host sleep not activated/activated> num_tx_timeout = - num_cmd_timeout = + is_cmd_timedout = <0/1 command timeout not occurred/occurred> timeout_cmd_id = timeout_cmd_act = last_cmd_id = diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 686943c52d18..b4d28edaf8aa 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -514,7 +514,7 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no, return -1; } - if (adapter->num_cmd_timeout) { + if (adapter->is_cmd_timedout) { dev_err(adapter->dev, "PREP_CMD: FW is in bad state\n"); return -1; } @@ -780,7 +780,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) return -1; } - adapter->num_cmd_timeout = 0; + adapter->is_cmd_timedout = 0; resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data; if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) { @@ -891,7 +891,7 @@ mwifiex_cmd_timeout_func(unsigned long function_context) struct cmd_ctrl_node *cmd_node; struct timeval tstamp; - adapter->num_cmd_timeout++; + adapter->is_cmd_timedout = 1; if (!adapter->curr_cmd) { dev_dbg(adapter->dev, "cmd: empty curr_cmd\n"); return; @@ -914,8 +914,8 @@ mwifiex_cmd_timeout_func(unsigned long function_context) dev_err(adapter->dev, "num_cmd_h2c_failure = %d\n", adapter->dbg.num_cmd_host_to_card_failure); - dev_err(adapter->dev, "num_cmd_timeout = %d\n", - adapter->num_cmd_timeout); + dev_err(adapter->dev, "is_cmd_timedout = %d\n", + adapter->is_cmd_timedout); dev_err(adapter->dev, "num_tx_timeout = %d\n", adapter->dbg.num_tx_timeout); diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index a5f9875cfd6e..61b467a7ebdd 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -85,8 +85,8 @@ static struct mwifiex_debug_data items[] = { item_addr(hs_activated), 1}, {"num_tx_timeout", item_size(num_tx_timeout), item_addr(num_tx_timeout), 1}, - {"num_cmd_timeout", item_size(num_cmd_timeout), - item_addr(num_cmd_timeout), 1}, + {"is_cmd_timedout", item_size(is_cmd_timedout), + item_addr(is_cmd_timedout), 1}, {"timeout_cmd_id", item_size(timeout_cmd_id), item_addr(timeout_cmd_id), 1}, {"timeout_cmd_act", item_size(timeout_cmd_act), diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 5974642f38b1..1fb2212079ae 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -209,7 +209,7 @@ struct mwifiex_debug_info { u32 num_cmd_assoc_success; u32 num_cmd_assoc_failure; u32 num_tx_timeout; - u32 num_cmd_timeout; + u8 is_cmd_timedout; u16 timeout_cmd_id; u16 timeout_cmd_act; u16 last_cmd_id[DBG_CMD_NUM]; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index df09ddb64eec..51ac9e3355a2 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -719,7 +719,7 @@ struct mwifiex_adapter { struct cmd_ctrl_node *curr_cmd; /* spin lock for command */ spinlock_t mwifiex_cmd_lock; - u32 num_cmd_timeout; + u8 is_cmd_timedout; u16 last_init_cmd; struct timer_list cmd_timer; struct list_head cmd_free_q; diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index fd2a7165cfa5..368450cc56c7 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -116,7 +116,7 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code) adapter->tx_lock_flag = false; adapter->pps_uapsd_mode = false; - if (adapter->num_cmd_timeout && adapter->curr_cmd) + if (adapter->is_cmd_timedout && adapter->curr_cmd) return; priv->media_connected = false; dev_dbg(adapter->dev, diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 7022c69f0a29..c3824e37f3f2 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -104,7 +104,7 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv, info->pm_wakeup_fw_try = adapter->pm_wakeup_fw_try; info->is_hs_configured = adapter->is_hs_configured; info->hs_activated = adapter->hs_activated; - info->num_cmd_timeout = adapter->num_cmd_timeout; + info->is_cmd_timedout = adapter->is_cmd_timedout; info->num_cmd_host_to_card_failure = adapter->dbg.num_cmd_host_to_card_failure; info->num_cmd_sleep_cfm_host_to_card_failure From a5333914536debe05f36ed0d0273f1ddab744eea Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 27 Feb 2014 19:35:18 -0800 Subject: [PATCH 377/414] mwifiex: update MCS information as per antenna settings Even if the device is changed to 1X1 mode, data is sent with higher MCS rates after association. This patch fixes the problem by updating MCS information field in HT capability when antenna setting changes so that correct information will be advertised in association and probe request. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 31 +++++++++++++++++++++++-- drivers/net/wireless/mwifiex/cfp.c | 2 +- drivers/net/wireless/mwifiex/cmdevt.c | 1 + drivers/net/wireless/mwifiex/fw.h | 13 +++++++++++ drivers/net/wireless/mwifiex/main.h | 1 + 5 files changed, 45 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index bfe9316e196c..51ce99cfcfb9 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1324,6 +1324,33 @@ mwifiex_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) tx_ant = RF_ANTENNA_AUTO; rx_ant = RF_ANTENNA_AUTO; } + } else { + struct ieee80211_sta_ht_cap *ht_info; + int rx_mcs_supp; + enum ieee80211_band band; + + if ((tx_ant == 0x1 && rx_ant == 0x1)) { + adapter->user_dev_mcs_support = HT_STREAM_1X1; + if (adapter->is_hw_11ac_capable) + adapter->usr_dot_11ac_mcs_support = + MWIFIEX_11AC_MCS_MAP_1X1; + } else { + adapter->user_dev_mcs_support = HT_STREAM_2X2; + if (adapter->is_hw_11ac_capable) + adapter->usr_dot_11ac_mcs_support = + MWIFIEX_11AC_MCS_MAP_2X2; + } + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (!adapter->wiphy->bands[band]) + continue; + + ht_info = &adapter->wiphy->bands[band]->ht_cap; + rx_mcs_supp = + GET_RXMCSSUPP(adapter->user_dev_mcs_support); + memset(&ht_info->mcs, 0, adapter->number_of_antenna); + memset(&ht_info->mcs, 0xff, rx_mcs_supp); + } } ant_cfg.tx_ant = tx_ant; @@ -2093,8 +2120,8 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, ht_info->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU; ht_info->cap |= IEEE80211_HT_CAP_SM_PS; - rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support); - /* Set MCS for 1x1 */ + rx_mcs_supp = GET_RXMCSSUPP(adapter->user_dev_mcs_support); + /* Set MCS for 1x1/2x2 */ memset(mcs, 0xff, rx_mcs_supp); /* Clear all the other values */ memset(&mcs[rx_mcs_supp], 0, diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c index 2c3226bf86f8..0ddec3d4b059 100644 --- a/drivers/net/wireless/mwifiex/cfp.c +++ b/drivers/net/wireless/mwifiex/cfp.c @@ -253,7 +253,7 @@ u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv, u8 index, u8 ht_info) { u32 mcs_num_supp = - (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) ? 16 : 8; + (priv->adapter->user_dev_mcs_support == HT_STREAM_2X2) ? 16 : 8; u32 rate; if (priv->adapter->is_hw_11ac_capable) diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index b4d28edaf8aa..14e05c9f4663 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -1592,6 +1592,7 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, adapter->hw_dot_11n_dev_cap = le32_to_cpu(hw_spec->dot_11n_dev_cap); adapter->hw_dev_mcs_support = hw_spec->dev_mcs_support; + adapter->user_dev_mcs_support = adapter->hw_dev_mcs_support; if (adapter->if_ops.update_mp_end_port) adapter->if_ops.update_mp_end_port(adapter, diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index aa8abef58349..39cb3542f79c 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -236,8 +236,21 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { */ #define MWIFIEX_FW_DEF_HTTXCFG (BIT(1) | BIT(4) | BIT(5) | BIT(6)) +/* 11AC Tx and Rx MCS map for 1x1 mode: + * IEEE80211_VHT_MCS_SUPPORT_0_9 for stream 1 + * IEEE80211_VHT_MCS_NOT_SUPPORTED for remaining 7 streams + */ +#define MWIFIEX_11AC_MCS_MAP_1X1 0xfffefffe + +/* 11AC Tx and Rx MCS map for 2x2 mode: + * IEEE80211_VHT_MCS_SUPPORT_0_9 for stream 1 and 2 + * IEEE80211_VHT_MCS_NOT_SUPPORTED for remaining 6 streams + */ +#define MWIFIEX_11AC_MCS_MAP_2X2 0xfffafffa + #define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f) #define SETHT_MCS32(x) (x[4] |= 1) +#define HT_STREAM_1X1 0x11 #define HT_STREAM_2X2 0x22 #define SET_SECONDARYCHAN(RadioType, SECCHAN) (RadioType |= (SECCHAN << 4)) diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 51ac9e3355a2..f0289c12e041 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -773,6 +773,7 @@ struct mwifiex_adapter { u8 event_body[MAX_EVENT_SIZE]; u32 hw_dot_11n_dev_cap; u8 hw_dev_mcs_support; + u8 user_dev_mcs_support; u8 adhoc_11n_enabled; u8 sec_chan_offset; struct mwifiex_dbg dbg; From 3e3831c4fdc53aabf3a56419ef6d96a841c52435 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Tue, 25 Feb 2014 20:30:38 +0100 Subject: [PATCH 378/414] brcmfmac: reset suspend flag upon sdio suspend failure The suspend callback first sets the suspend flag used in the driver but after that the actual suspend is done, which may fail. Reset the flag upon suspend failure. Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 9eea7d4dd501..4a6508e7e3a1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -1101,9 +1101,7 @@ static int brcmf_ops_sdio_suspend(struct device *dev) struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; int ret = 0; - brcmf_dbg(SDIO, "\n"); - - atomic_set(&sdiodev->suspend, true); + brcmf_dbg(SDIO, "Enter\n"); sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]); if (!(sdio_flags & MMC_PM_KEEP_POWER)) { @@ -1111,9 +1109,12 @@ static int brcmf_ops_sdio_suspend(struct device *dev) return -EINVAL; } + atomic_set(&sdiodev->suspend, true); + ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER); if (ret) { brcmf_err("Failed to set pm_flags\n"); + atomic_set(&sdiodev->suspend, false); return ret; } @@ -1127,6 +1128,7 @@ static int brcmf_ops_sdio_resume(struct device *dev) struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; + brcmf_dbg(SDIO, "Enter\n"); brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS); atomic_set(&sdiodev->suspend, false); return 0; From c8e4955653a470ece7bf580c84fc88eb58cc9850 Mon Sep 17 00:00:00 2001 From: Silvan Jegen Date: Tue, 25 Feb 2014 18:12:52 +0100 Subject: [PATCH 379/414] net: Replace min macro with min_t Instead of an explicit cast, use the min_t macro. Signed-off-by: Silvan Jegen Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 2 +- drivers/net/wireless/b43/sysfs.c | 2 +- drivers/net/wireless/b43/xmit.c | 2 +- drivers/net/wireless/b43legacy/main.c | 4 ++-- drivers/net/wireless/b43legacy/sysfs.c | 2 +- drivers/net/wireless/b43legacy/xmit.c | 2 +- drivers/net/wireless/cw1200/fwio.c | 4 ++-- drivers/net/wireless/ipw2x00/ipw2100.c | 2 +- drivers/net/wireless/ipw2x00/ipw2200.c | 2 +- drivers/net/wireless/libertas/if_sdio.c | 4 ++-- drivers/net/wireless/mwifiex/debugfs.c | 4 ++-- drivers/net/wireless/p54/p54usb.c | 2 +- drivers/net/wireless/prism54/isl_ioctl.c | 2 +- drivers/net/wireless/rt2x00/rt2x00debug.c | 2 +- drivers/net/wireless/ti/wlcore/main.c | 2 +- drivers/net/wireless/ti/wlcore/spi.c | 4 ++-- drivers/net/wireless/ti/wlcore/sysfs.c | 2 +- 17 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index c75237eb55a1..69fc3d65531a 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1549,7 +1549,7 @@ static void b43_write_beacon_template(struct b43_wldev *dev, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon); bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); - len = min((size_t) dev->wl->current_beacon->len, + len = min_t(size_t, dev->wl->current_beacon->len, 0x200 - sizeof(struct b43_plcp_hdr6)); rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value; diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c index 8e8431d4eb0c..3190493bd07f 100644 --- a/drivers/net/wireless/b43/sysfs.c +++ b/drivers/net/wireless/b43/sysfs.c @@ -40,7 +40,7 @@ static int get_integer(const char *buf, size_t count) if (count == 0) goto out; - count = min(count, (size_t) 10); + count = min_t(size_t, count, 10); memcpy(tmp, buf, count); ret = simple_strtol(tmp, NULL, 10); out: diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 218a0f37af46..31adb8cf0291 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -337,7 +337,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, /* iv16 */ memcpy(txhdr->iv + 10, ((u8 *) wlhdr) + wlhdr_len, 3); } else { - iv_len = min((size_t) info->control.hw_key->iv_len, + iv_len = min_t(size_t, info->control.hw_key->iv_len, ARRAY_SIZE(txhdr->iv)); memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); } diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 349c77605231..1aec2146a2bf 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -978,7 +978,7 @@ static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon); bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); - len = min((size_t)dev->wl->current_beacon->len, + len = min_t(size_t, dev->wl->current_beacon->len, 0x200 - sizeof(struct b43legacy_plcp_hdr6)); rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value; @@ -1155,7 +1155,7 @@ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev, b43legacy_write_probe_resp_plcp(dev, 0x350, size, &b43legacy_b_ratetable[3]); - size = min((size_t)size, + size = min_t(size_t, size, 0x200 - sizeof(struct b43legacy_plcp_hdr6)); b43legacy_write_template_common(dev, probe_resp_data, size, ram_offset, diff --git a/drivers/net/wireless/b43legacy/sysfs.c b/drivers/net/wireless/b43legacy/sysfs.c index 57f8b089767c..2a1da15c913b 100644 --- a/drivers/net/wireless/b43legacy/sysfs.c +++ b/drivers/net/wireless/b43legacy/sysfs.c @@ -42,7 +42,7 @@ static int get_integer(const char *buf, size_t count) if (count == 0) goto out; - count = min(count, (size_t)10); + count = min_t(size_t, count, 10); memcpy(tmp, buf, count); ret = simple_strtol(tmp, NULL, 10); out: diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index 86588c9ff0f2..34bf3f0b729f 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -254,7 +254,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, B43legacy_TX4_MAC_KEYALG_SHIFT) & B43legacy_TX4_MAC_KEYALG; wlhdr_len = ieee80211_hdrlen(wlhdr->frame_control); - iv_len = min((size_t)info->control.hw_key->iv_len, + iv_len = min_t(size_t, info->control.hw_key->iv_len, ARRAY_SIZE(txhdr->iv)); memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len); } else { diff --git a/drivers/net/wireless/cw1200/fwio.c b/drivers/net/wireless/cw1200/fwio.c index 5a9ffd3a6a6c..e23d67e0bfe6 100644 --- a/drivers/net/wireless/cw1200/fwio.c +++ b/drivers/net/wireless/cw1200/fwio.c @@ -202,8 +202,8 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) } /* calculate the block size */ - tx_size = block_size = min((size_t)(firmware->size - put), - (size_t)DOWNLOAD_BLOCK_SIZE); + tx_size = block_size = min_t(size_t, firmware->size - put, + DOWNLOAD_BLOCK_SIZE); memcpy(buf, &firmware->data[put], block_size); if (block_size < DOWNLOAD_BLOCK_SIZE) { diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 3aba49259ef1..dfc6dfc56d52 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -7065,7 +7065,7 @@ static int ipw2100_wx_set_nick(struct net_device *dev, if (wrqu->data.length > IW_ESSID_MAX_SIZE) return -E2BIG; - wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick)); + wrqu->data.length = min_t(size_t, wrqu->data.length, sizeof(priv->nick)); memset(priv->nick, 0, sizeof(priv->nick)); memcpy(priv->nick, extra, wrqu->data.length); diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 139326065bd9..c5aa404069f3 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -9169,7 +9169,7 @@ static int ipw_wx_set_nick(struct net_device *dev, if (wrqu->data.length > IW_ESSID_MAX_SIZE) return -E2BIG; mutex_lock(&priv->mutex); - wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick)); + wrqu->data.length = min_t(size_t, wrqu->data.length, sizeof(priv->nick)); memset(priv->nick, 0, sizeof(priv->nick)); memcpy(priv->nick, extra, wrqu->data.length); IPW_DEBUG_TRACE("<<\n"); diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 58c6ee5de98f..33ceda296c9c 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -498,7 +498,7 @@ static int if_sdio_prog_helper(struct if_sdio_card *card, */ mdelay(2); - chunk_size = min(size, (size_t)60); + chunk_size = min_t(size_t, size, 60); *((__le32*)chunk_buffer) = cpu_to_le32(chunk_size); memcpy(chunk_buffer + 4, firmware, chunk_size); @@ -639,7 +639,7 @@ static int if_sdio_prog_real(struct if_sdio_card *card, req_size = size; while (req_size) { - chunk_size = min(req_size, (size_t)512); + chunk_size = min_t(size_t, req_size, 512); memcpy(chunk_buffer, firmware, chunk_size); /* diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index 61b467a7ebdd..b8a49aad12fd 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -493,7 +493,7 @@ mwifiex_regrdwr_write(struct file *file, { unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *) addr; - size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1)); + size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1); int ret; u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX; @@ -594,7 +594,7 @@ mwifiex_rdeeprom_write(struct file *file, { unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *) addr; - size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1)); + size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1); int ret = 0; int offset = -1, bytes = -1; diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 6e635cfa24c8..b7ab3dfb3de8 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -513,7 +513,7 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) if (!buf) return -ENOMEM; - left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size); + left = block_size = min_t(size_t, P54U_FW_BLOCK, priv->fw->size); strcpy(buf, p54u_firmware_upload_3887); left -= strlen(p54u_firmware_upload_3887); tmp += strlen(p54u_firmware_upload_3887); diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 78fa64d3f223..ecbb0546cf3e 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -644,7 +644,7 @@ prism54_translate_bss(struct net_device *ndev, struct iw_request_info *info, wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie); if (wpa_ie_len > 0) { iwe.cmd = IWEVGENIE; - iwe.u.data.length = min(wpa_ie_len, (size_t)MAX_WPA_IE_LEN); + iwe.u.data.length = min_t(size_t, wpa_ie_len, MAX_WPA_IE_LEN); current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, wpa_ie); } diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 2e3d1645e68b..90fdb02b55e7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -286,7 +286,7 @@ static ssize_t rt2x00debug_read_queue_dump(struct file *file, if (retval) return retval; - status = min((size_t)skb->len, length); + status = min_t(size_t, skb->len, length); if (copy_to_user(buf, skb->data, status)) { status = -EFAULT; goto exit; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 4175a57ac9f5..ed88d3913483 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -800,7 +800,7 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen) size_t len; /* Make sure we have enough room */ - len = min(maxlen, (size_t)(PAGE_SIZE - wl->fwlog_size)); + len = min_t(size_t, maxlen, PAGE_SIZE - wl->fwlog_size); /* Fill the FW log file, consumed by the sysfs fwlog entry */ memcpy(wl->fwlog + wl->fwlog_size, memblock, len); diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index b2c018dccf18..dbe826dd7c23 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -211,7 +211,7 @@ static int __must_check wl12xx_spi_raw_read(struct device *child, int addr, u32 chunk_len; while (len > 0) { - chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len); + chunk_len = min_t(size_t, WSPI_MAX_CHUNK_SIZE, len); cmd = &wl->buffer_cmd; busy_buf = wl->buffer_busyword; @@ -285,7 +285,7 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr, cmd = &commands[0]; i = 0; while (len > 0) { - chunk_len = min((size_t)WSPI_MAX_CHUNK_SIZE, len); + chunk_len = min_t(size_t, WSPI_MAX_CHUNK_SIZE, len); *cmd = 0; *cmd |= WSPI_CMD_WRITE; diff --git a/drivers/net/wireless/ti/wlcore/sysfs.c b/drivers/net/wireless/ti/wlcore/sysfs.c index 8e583497940d..24dd288d6809 100644 --- a/drivers/net/wireless/ti/wlcore/sysfs.c +++ b/drivers/net/wireless/ti/wlcore/sysfs.c @@ -152,7 +152,7 @@ static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj, } /* Seeking is not supported - old logs are not kept. Disregard pos. */ - len = min(count, (size_t)wl->fwlog_size); + len = min_t(size_t, count, wl->fwlog_size); wl->fwlog_size -= len; memcpy(buffer, wl->fwlog, len); From 727b662c2b3476840b7fef7a44685fb0a0898c48 Mon Sep 17 00:00:00 2001 From: Sylvain Roger Rieunier Date: Thu, 27 Feb 2014 14:36:06 +0100 Subject: [PATCH 380/414] ath9k: fix invalid max frame length According to 802.11n-2012 standard in paragraph PPDU Fromat(20.3.2) HT-mixed format Hearder PPDU contains : L_STF, L_LTF, L_SIG, HT_SIG, HT_STF, HT_LTF they are symbols in the preamble, there are in time unit(us) that's for why it can't be computed in bytes Signed-off-by: Sylvain ROGER RIEUNIER Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 8f28711cfd4e..306ea322c65d 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1040,11 +1040,11 @@ static int ath_max_framelen(int usec, int mcs, bool ht40, bool sgi) int symbols, bits; int bytes = 0; + usec -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); symbols = sgi ? TIME_SYMBOLS_HALFGI(usec) : TIME_SYMBOLS(usec); bits = symbols * bits_per_symbol[mcs % 8][ht40] * streams; bits -= OFDM_PLCP_BITS; bytes = bits / 8; - bytes -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); if (bytes > 65532) bytes = 65532; From 6241226f68ea5285674adeb846a1a4544470724e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 28 Feb 2014 19:02:24 +0100 Subject: [PATCH 381/414] ath9k_hw: toggle weak signal detection in AP mode on older chipsets The commit 80b4205b "ath9k: Fix OFDM weak signal detection for AP mode" prevented weak signal detection changes from taking effect in AP mode on all chipsets, claiming it is "not allowed". The main reason for not disabling weak signal detection in AP mode is that typically beacon RSSI is used to track whether it is needed to boost range, and this is unavailable in AP mode for obvious reasons. The problem with not disabling weak signal detection is that older chipsets are very sensitive to high PHY error counts. When faced with heavy noise, this can lead to an excessive amount of "Failed to stop TX DMA" errors in the field. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ani.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index d28923b7435b..3227ee059813 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -176,16 +176,18 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel, if (ah->opmode == NL80211_IFTYPE_STATION && BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH) weak_sig = true; - /* - * OFDM Weak signal detection is always enabled for AP mode. + * Newer chipsets are better at dealing with high PHY error counts - + * keep weak signal detection enabled when no RSSI threshold is + * available to determine if it is needed (mode != STA) */ - if (ah->opmode != NL80211_IFTYPE_AP && - aniState->ofdmWeakSigDetect != weak_sig) { - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - entry_ofdm->ofdm_weak_signal_on); - } + else if (AR_SREV_9300_20_OR_LATER(ah) && + ah->opmode != NL80211_IFTYPE_STATION) + weak_sig = true; + + if (aniState->ofdmWeakSigDetect != weak_sig) + ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + weak_sig); if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) { ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; From f5547245217ed54bbb2a72c109c6756323bdb98f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 28 Feb 2014 19:02:25 +0100 Subject: [PATCH 382/414] ath9k_hw: tweak noise immunity thresholds for older chipsets Older chipsets are more sensitive to high PHY error counts, and the current noise immunity thresholds were based on tests run at QCA with newer chipsets. This patch brings back the values from the old ANI implementation for old chipsets, and it also disables weak signal detection on an earlier noise immunity level, to improve overall radio stability on affected devices. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ani.c | 23 +++++++++++++++++++---- drivers/net/wireless/ath/ath9k/ani.h | 4 ++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 3227ee059813..2ce5079007b6 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -185,10 +185,18 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel, ah->opmode != NL80211_IFTYPE_STATION) weak_sig = true; + /* Older chipsets are more sensitive to high PHY error counts */ + else if (!AR_SREV_9300_20_OR_LATER(ah) && + aniState->ofdmNoiseImmunityLevel >= 8) + weak_sig = false; + if (aniState->ofdmWeakSigDetect != weak_sig) ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, weak_sig); + if (!AR_SREV_9300_20_OR_LATER(ah)) + return; + if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) { ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI; @@ -485,10 +493,17 @@ void ath9k_hw_ani_init(struct ath_hw *ah) ath_dbg(common, ANI, "Initialize ANI\n"); - ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; - ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; - ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; - ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW; + if (AR_SREV_9300_20_OR_LATER(ah)) { + ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; + ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; + ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; + ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW; + } else { + ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD; + ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD; + ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD; + ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD; + } ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index 21e7b83c3f6a..c40965b4c1e2 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -22,12 +22,16 @@ /* units are errors per second */ #define ATH9K_ANI_OFDM_TRIG_HIGH 3500 #define ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI 1000 +#define ATH9K_ANI_OFDM_TRIG_HIGH_OLD 500 #define ATH9K_ANI_OFDM_TRIG_LOW 400 #define ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI 900 +#define ATH9K_ANI_OFDM_TRIG_LOW_OLD 200 #define ATH9K_ANI_CCK_TRIG_HIGH 600 +#define ATH9K_ANI_CCK_TRIG_HIGH_OLD 200 #define ATH9K_ANI_CCK_TRIG_LOW 300 +#define ATH9K_ANI_CCK_TRIG_LOW_OLD 100 #define ATH9K_ANI_SPUR_IMMUNE_LVL 3 #define ATH9K_ANI_FIRSTEP_LVL 2 From 4c59ff221e070eda4ff014b866a4797c6c18abbb Mon Sep 17 00:00:00 2001 From: "Zhao, Gang" Date: Sat, 1 Mar 2014 14:26:29 +0800 Subject: [PATCH 383/414] wireless: Kconfig: add missing dependency Previous driver changes to airo, atmel, wl3501_cs, and usb_zd1201 need to include , which depends on CFG80211, so add the missing dependency. Reported-by: kbuild test robot Signed-off-by: Zhao, Gang Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 200020eb3005..d1fab435f5a3 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -53,7 +53,7 @@ config LIBERTAS_THINFIRM_USB config AIRO tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" - depends on ISA_DMA_API && (PCI || BROKEN) + depends on CFG80211 && ISA_DMA_API && (PCI || BROKEN) select WIRELESS_EXT select CRYPTO select WEXT_SPY @@ -73,7 +73,7 @@ config AIRO config ATMEL tristate "Atmel at76c50x chipset 802.11b support" - depends on (PCI || PCMCIA) + depends on CFG80211 && (PCI || PCMCIA) select WIRELESS_EXT select WEXT_PRIV select FW_LOADER @@ -138,7 +138,7 @@ config AIRO_CS config PCMCIA_WL3501 tristate "Planet WL3501 PCMCIA cards" - depends on PCMCIA + depends on CFG80211 && PCMCIA select WIRELESS_EXT select WEXT_SPY help @@ -168,7 +168,7 @@ config PRISM54 config USB_ZD1201 tristate "USB ZD1201 based Wireless device support" - depends on USB + depends on CFG80211 && USB select WIRELESS_EXT select WEXT_PRIV select FW_LOADER From 7661e97542d57d54317407ff4790e2d6d94a0852 Mon Sep 17 00:00:00 2001 From: Ivaylo Dimitrov Date: Sat, 1 Mar 2014 14:52:06 +0200 Subject: [PATCH 384/414] wl1251: use skb_trim to make skb shorter the current code is directly setting skb->len, which is not correct and brings problems with HAVE_EFFICIENT_UNALIGNED_ACCESS enabled in config Signed-off-by: Ivaylo Dimitrov Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wl1251/rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ti/wl1251/rx.c b/drivers/net/wireless/ti/wl1251/rx.c index 123c4bb50e0a..cde0eaf99714 100644 --- a/drivers/net/wireless/ti/wl1251/rx.c +++ b/drivers/net/wireless/ti/wl1251/rx.c @@ -180,7 +180,7 @@ static void wl1251_rx_body(struct wl1251 *wl, wl1251_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); /* The actual length doesn't include the target's alignment */ - skb->len = desc->length - PLCP_HEADER_LENGTH; + skb_trim(skb, desc->length - PLCP_HEADER_LENGTH); fc = (u16 *)skb->data; From af31cb5a57084146aae5c01df6b85f54067528aa Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 2 Mar 2014 11:20:50 +0200 Subject: [PATCH 385/414] wil6210: fix buffer overflow in wil_txdesc_debugfs_show() Wrong index comparison logic, found by smatch: drivers/net/wireless/ath/wil6210/debugfs.c:402 wil_txdesc_debugfs_show() warn: buffer overflow 'wil->vring_tx' 24 <= 24 Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 729e774ee96d..1d09a4b0a0f4 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -26,8 +26,7 @@ /* Nasty hack. Better have per device instances */ static u32 mem_addr; static u32 dbg_txdesc_index; -static u32 dbg_vring_index; /* 25 for Rx, 0..24 for Tx */ -#define WIL_DBG_VRING_INDEX_RX (WIL6210_MAX_TX_RINGS + 1) +static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, const char *name, struct vring *vring, @@ -404,13 +403,14 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; struct vring *vring; - if (dbg_vring_index <= WIL6210_MAX_TX_RINGS) + bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS); + if (tx) vring = &(wil->vring_tx[dbg_vring_index]); else vring = &wil->vring_rx; if (!vring->va) { - if (dbg_vring_index <= WIL6210_MAX_TX_RINGS) + if (tx) seq_printf(s, "No Tx[%2d] VRING\n", dbg_vring_index); else seq_puts(s, "No Rx VRING\n"); @@ -426,7 +426,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) volatile u32 *u = (volatile u32 *)d; struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb; - if (dbg_vring_index <= WIL6210_MAX_TX_RINGS) + if (tx) seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_vring_index, dbg_txdesc_index); else @@ -461,7 +461,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) } seq_printf(s, "}\n"); } else { - if (dbg_vring_index <= WIL6210_MAX_TX_RINGS) + if (tx) seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n", dbg_vring_index, dbg_txdesc_index, vring->size); From c14c5d99a453af6b86f15aca8fe9005b2b8f3b26 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 2 Mar 2014 11:20:51 +0200 Subject: [PATCH 386/414] wil6210: fix smatch warning in wil_cfg80211_get_station() Smatch suggests to propagate error code from wil_find_cid(), and, indeed, it is a good idea. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index a4da064dbbc4..743930357061 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -181,7 +181,7 @@ static int wil_cfg80211_get_station(struct wiphy *wiphy, wil_info(wil, "%s(%pM) CID %d\n", __func__, mac, cid); if (cid < 0) - return -ENOENT; + return cid; rc = wil_cid_fill_sinfo(wil, cid, sinfo); From 4c552a5be78bd66abd59441a21fec348ee376b49 Mon Sep 17 00:00:00 2001 From: andrea merello Date: Tue, 18 Feb 2014 02:10:45 +0100 Subject: [PATCH 387/414] rtl818x: Make sure the TX descriptor "valid" flag is written by last The TX descriptors are consumed by the HW using DMA. Even if in the driver code the memory write that sets the "valid" flag appears after all other writes, the CPU may reorder writes, causing the HW to consider as valid a not-fully-written yet descriptor. This may cause HW incorrect behaviour. This can happen because (AFAIK) the HW may attempt DMA asynchronously without waiting to be kicked by the following register write. This patch adds a write memory barrier to enforce writes ordering. Reported-by: Dan Carpenter Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 1f2462e92528..45d2cc14d71c 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -335,6 +335,11 @@ static void rtl8180_tx(struct ieee80211_hw *dev, entry->flags2 = info->control.rates[1].idx >= 0 ? ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0; entry->retry_limit = info->control.rates[0].count; + + /* We must be sure that tx_flags is written last because the HW + * looks at it to check if the rest of data is valid or not + */ + wmb(); entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); if (ring->entries - skb_queue_len(&ring->queue) < 2) From c24782e612dce377cf9149ad787998af7694f757 Mon Sep 17 00:00:00 2001 From: andrea merello Date: Tue, 18 Feb 2014 02:10:46 +0100 Subject: [PATCH 388/414] rtl818x: make sure TX descriptor writes are done before kicking DMA The TX descriptors are consumed by the HW using DMA. Even if in the driver code the TX descriptor writes appears before the HW "dma kick" register writes, the CPU may reorder them. If this happens, the TX may not happen at all becase the "valid" descriptor flag may have not been set yet. This patch adds a write memory barrier to ensures the TX descriptor is written before writing to the HW "dma kick" register. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 45d2cc14d71c..959e699702e8 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -341,6 +341,12 @@ static void rtl8180_tx(struct ieee80211_hw *dev, */ wmb(); entry->flags = cpu_to_le32(tx_flags); + /* We must be sure this has been written before followings HW + * register write, because this write will made the HW attempts + * to DMA the just-written data + */ + wmb(); + __skb_queue_tail(&ring->queue, skb); if (ring->entries - skb_queue_len(&ring->queue) < 2) ieee80211_stop_queue(dev, prio); From aa45a673b291fd761275493bc15316d79555ed55 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 28 Feb 2014 15:16:43 -0600 Subject: [PATCH 389/414] rtlwifi: btcoexist: Add new mini driver A new driver in the rtlwifi family for the RTL8723BE will soon be added. The bluetooth coexistence code for this device has been split into a separate mini driver as it will be shared with other devices. This commit adds the the headers and sources, and modifies Kconfig and Makefile to configure and build this driver. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/Kconfig | 8 +- drivers/net/wireless/rtlwifi/Makefile | 1 + .../net/wireless/rtlwifi/btcoexist/Makefile | 7 + .../rtlwifi/btcoexist/halbt_precomp.h | 87 + .../rtlwifi/btcoexist/halbtc8723b2ant.c | 3698 +++++++++++++++++ .../rtlwifi/btcoexist/halbtc8723b2ant.h | 173 + .../wireless/rtlwifi/btcoexist/halbtcoutsrc.c | 1011 +++++ .../wireless/rtlwifi/btcoexist/halbtcoutsrc.h | 559 +++ .../net/wireless/rtlwifi/btcoexist/rtl_btc.c | 218 + .../net/wireless/rtlwifi/btcoexist/rtl_btc.h | 52 + .../wireless/rtlwifi/rtl8723com/fw_common.c | 849 ++++ .../wireless/rtlwifi/rtl8723com/fw_common.h | 50 + .../wireless/rtlwifi/rtl8723com/phy_common.h | 75 + drivers/net/wireless/rtlwifi/wifi.h | 60 + 14 files changed, 6847 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/rtlwifi/btcoexist/Makefile create mode 100644 drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h create mode 100644 drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c create mode 100644 drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h create mode 100644 drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c create mode 100644 drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h create mode 100644 drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c create mode 100644 drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h create mode 100644 drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c create mode 100644 drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h create mode 100644 drivers/net/wireless/rtlwifi/rtl8723com/phy_common.h diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig index c2ffce7a907c..29c6ce5c3371 100644 --- a/drivers/net/wireless/rtlwifi/Kconfig +++ b/drivers/net/wireless/rtlwifi/Kconfig @@ -5,7 +5,7 @@ menuconfig RTL_CARDS ---help--- This option will enable support for the Realtek mac80211-based wireless drivers. Drivers rtl8192ce, rtl8192cu, rtl8192se, rtl8192de, - rtl8723eu, and rtl8188eu share some common code. + rtl8723ae, and rtl8188ae share some common code. if RTL_CARDS @@ -48,6 +48,7 @@ config RTL8723AE depends on PCI select RTLWIFI select RTLWIFI_PCI + select RTLBTCOEXIST ---help--- This is the driver for Realtek RTL8723AE 802.11n PCIe wireless network adapters. @@ -101,4 +102,9 @@ config RTL8192C_COMMON depends on RTL8192CE || RTL8192CU default y +config RTLBTCOEXIST + tristate + depends on RTL8723AE + default y + endif diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile index d56f023a4b90..f354c5f9aed5 100644 --- a/drivers/net/wireless/rtlwifi/Makefile +++ b/drivers/net/wireless/rtlwifi/Makefile @@ -25,5 +25,6 @@ obj-$(CONFIG_RTL8192SE) += rtl8192se/ obj-$(CONFIG_RTL8192DE) += rtl8192de/ obj-$(CONFIG_RTL8723AE) += rtl8723ae/ obj-$(CONFIG_RTL8188EE) += rtl8188ee/ +obj-$(CONFIG_RTLBTCOEXIST) += btcoexist/ ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/rtlwifi/btcoexist/Makefile b/drivers/net/wireless/rtlwifi/btcoexist/Makefile new file mode 100644 index 000000000000..47ceecfcb7dc --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/Makefile @@ -0,0 +1,7 @@ +btcoexist-objs := halbtc8723b2ant.o \ + halbtcoutsrc.o \ + rtl_btc.o + +obj-$(CONFIG_RTLBTCOEXIST) += btcoexist.o + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h b/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h new file mode 100644 index 000000000000..582532fc199a --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h @@ -0,0 +1,87 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * Larry Finger + * + ******************************************************************************/ + +#ifndef __HALBT_PRECOMP_H__ +#define __HALBT_PRECOMP_H__ +/************************************************************* + * include files + *************************************************************/ +#include "../wifi.h" +#include "../efuse.h" +#include "../base.h" +#include "../regd.h" +#include "../cam.h" +#include "../ps.h" +#include "../pci.h" + +#include "halbtcoutsrc.h" + +#include "halbtc8723b2ant.h" + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + +#define MASKBYTE0 0xff +#define MASKBYTE1 0xff00 +#define MASKBYTE2 0xff0000 +#define MASKBYTE3 0xff000000 +#define MASKHWORD 0xffff0000 +#define MASKLWORD 0x0000ffff +#define MASKDWORD 0xffffffff +#define MASK12BITS 0xfff +#define MASKH4BITS 0xf0000000 +#define MASKOFDM_D 0xffc00000 +#define MASKCCK 0x3f3f3f3f + +#endif /* __HALBT_PRECOMP_H__ */ diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c new file mode 100644 index 000000000000..d916ab9f3c38 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -0,0 +1,3698 @@ +/****************************************************************************** + * + * Copyright(c) 2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +/*************************************************************** + * Description: + * + * This file is for RTL8723B Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + **************************************************************/ +/************************************************************** + * include files + **************************************************************/ +#include "halbt_precomp.h" +/************************************************************** + * Global variables, these are static variables + **************************************************************/ +static struct coex_dm_8723b_2ant glcoex_dm_8723b_2ant; +static struct coex_dm_8723b_2ant *coex_dm = &glcoex_dm_8723b_2ant; +static struct coex_sta_8723b_2ant glcoex_sta_8723b_2ant; +static struct coex_sta_8723b_2ant *coex_sta = &glcoex_sta_8723b_2ant; + +static const char *const glbt_info_src_8723b_2ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +static u32 glcoex_ver_date_8723b_2ant = 20130731; +static u32 glcoex_ver_8723b_2ant = 0x3b; + +/************************************************************** + * local function proto type if needed + **************************************************************/ +/************************************************************** + * local function start with btc8723b2ant_ + **************************************************************/ +static u8 btc8723b2ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, + u8 rssi_thresh1) +{ + s32 bt_rssi = 0; + u8 bt_rssi_state = coex_sta->pre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) { + bt_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "switch to High\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "stay at Low\n"); + } + } else { + if (bt_rssi < rssi_thresh) { + bt_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "switch to Low\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "stay at High\n"); + } + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi thresh error!!\n"); + return coex_sta->pre_bt_rssi_state; + } + + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) { + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "switch to Medium\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "stay at Low\n"); + } + } else if ((coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) { + bt_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "switch to High\n"); + } else if (bt_rssi < rssi_thresh) { + bt_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "switch to Low\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "stay at Medium\n"); + } + } else { + if (bt_rssi < rssi_thresh1) { + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "switch to Medium\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state " + "stay at High\n"); + } + } + } + + coex_sta->pre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +static u8 btc8723b2ant_wifi_rssi_state(struct btc_coexist *btcoexist, + u8 index, u8 level_num, + u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 wifi_rssi = 0; + u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) { + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "switch to High\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "stay at Low\n"); + } + } else { + if (wifi_rssi < rssi_thresh) { + wifi_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "switch to Low\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "stay at High\n"); + } + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI thresh error!!\n"); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) { + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "switch to Medium\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "stay at Low\n"); + } + } else if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT) { + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "switch to High\n"); + } else if (wifi_rssi < rssi_thresh) { + wifi_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "switch to Low\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "stay at Medium\n"); + } + } else { + if (wifi_rssi < rssi_thresh1) { + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "switch to Medium\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state " + "stay at High\n"); + } + } + } + + coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + + return wifi_rssi_state; +} + +static void btc8723b2ant_monitor_bt_ctr(struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0; + u32 reg_lp_tx = 0, reg_lp_rx = 0; + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], High Priority Tx/Rx(reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + reg_hp_txrx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], Low Priority Tx/Rx(reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx); + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +} + +static bool btc8723b2ant_is_wifi_status_changed(struct btc_coexist *btcoexist) +{ + static bool pre_wifi_busy; + static bool pre_under_4way; + static bool pre_bt_hs_on; + bool wifi_busy = false, under_4way = false, bt_hs_on = false; + bool wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + } + + return false; +} + +static void btc8723b2ant_update_bt_link_info(struct btc_coexist *btcoexist) +{ + /*struct btc_stack_info *stack_info = &btcoexist->stack_info;*/ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool bt_hs_on = false; + +#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 1) /* profile from bt patch */ + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } +#else /* profile from bt stack */ + bt_link_info->bt_link_exist = stack_info->bt_link_exist; + bt_link_info->sco_exist = stack_info->sco_exist; + bt_link_info->a2dp_exist = stack_info->a2dp_exist; + bt_link_info->pan_exist = stack_info->pan_exist; + bt_link_info->hid_exist = stack_info->hid_exist; + + /*for win-8 stack HID report error*/ + if (!stack_info->hid_exist) + stack_info->hid_exist = coex_sta->hid_exist; + /*sync BTInfo with BT firmware and stack*/ + /* when stack HID report error, here we use the info from bt fw.*/ + if (!stack_info->bt_link_exist) + stack_info->bt_link_exist = coex_sta->bt_link_exist; +#endif + /* check if Sco only */ + if (bt_link_info->sco_exist && !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; +} + +static u8 btc8723b2ant_action_algorithm(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool bt_hs_on = false; + u8 algorithm = BT_8723B_2ANT_COEX_ALGO_UNDEFINED; + u8 num_of_diff_profile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], No BT link exists!!!\n"); + return algorithm; + } + + if (bt_link_info->sco_exist) + num_of_diff_profile++; + if (bt_link_info->hid_exist) + num_of_diff_profile++; + if (bt_link_info->pan_exist) + num_of_diff_profile++; + if (bt_link_info->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 1) { + if (bt_link_info->sco_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO only\n"); + algorithm = BT_8723B_2ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], HID only\n"); + algorithm = BT_8723B_2ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], A2DP only\n"); + algorithm = BT_8723B_2ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], PAN(HS) only\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANHS; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], PAN(EDR) only\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + HID\n"); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + A2DP ==> SCO\n"); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + PAN(HS)\n"); + algorithm = BT_8723B_2ANT_COEX_ALGO_SCO; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + PAN(EDR)\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], HID + A2DP\n"); + algorithm = BT_8723B_2ANT_COEX_ALGO_HID_A2DP; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], HID + PAN(HS)\n"); + algorithm = BT_8723B_2ANT_COEX_ALGO_HID; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], HID + PAN(EDR)\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], A2DP + PAN(HS)\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex],A2DP + PAN(EDR)\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (num_of_diff_profile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + HID + A2DP" + " ==> HID\n"); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + HID + " + "PAN(HS)\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + HID + " + "PAN(EDR)\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + A2DP + " + "PAN(HS)\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + A2DP + " + "PAN(EDR) ==> HID\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], HID + A2DP + " + "PAN(HS)\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], HID + A2DP + " + "PAN(EDR)\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (num_of_diff_profile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Error!!! SCO + HID" + " + A2DP + PAN(HS)\n"); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + HID + A2DP +" + " PAN(EDR)==>PAN(EDR)+HID\n"); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + return algorithm; +} + +static bool btc8723b_need_dec_pwr(struct btc_coexist *btcoexist) +{ + bool ret = false; + bool bt_hs_on = false, wifi_connected = false; + s32 bt_hs_rssi = 0; + u8 bt_rssi_state; + + if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on)) + return false; + if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected)) + return false; + if (!btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi)) + return false; + + bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0); + + if (wifi_connected) { + if (bt_hs_on) { + if (bt_hs_rssi > 37) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], Need to decrease bt " + "power for HS mode!!\n"); + ret = true; + } + } else { + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], Need to decrease bt " + "power for Wifi is connected!!\n"); + ret = true; + } + } + } + + return ret; +} + +static void btc8723b2ant_set_fw_dac_swing_level(struct btc_coexist *btcoexist, + u8 dac_swing_lvl) +{ + u8 h2c_parameter[1] = {0}; + + /* There are several type of dacswing + * 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 + */ + h2c_parameter[0] = dac_swing_lvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], Set Dac Swing Level=0x%x\n", dac_swing_lvl); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], FW write 0x64=0x%x\n", h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter); +} + +static void btc8723b2ant_set_fw_dec_bt_pwr(struct btc_coexist *btcoexist, + bool dec_bt_pwr) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (dec_bt_pwr) + h2c_parameter[0] |= BIT1; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], decrease Bt Power : %s, FW write 0x62=0x%x\n", + (dec_bt_pwr ? "Yes!!" : "No!!"), h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter); +} + +static void btc8723b2ant_dec_bt_pwr(struct btc_coexist *btcoexist, + bool force_exec, bool dec_bt_pwr) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s Dec BT power = %s\n", + (force_exec ? "force to" : ""), (dec_bt_pwr ? "ON" : "OFF")); + coex_dm->cur_dec_bt_pwr = dec_bt_pwr; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], bPreDecBtPwr=%d, bCurDecBtPwr=%d\n", + coex_dm->pre_dec_bt_pwr, coex_dm->cur_dec_bt_pwr); + + if (coex_dm->pre_dec_bt_pwr == coex_dm->cur_dec_bt_pwr) + return; + } + btc8723b2ant_set_fw_dec_bt_pwr(btcoexist, coex_dm->cur_dec_bt_pwr); + + coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr; +} + +static void btc8723b2ant_fw_dac_swing_lvl(struct btc_coexist *btcoexist, + bool force_exec, u8 fw_dac_swing_lvl) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s set FW Dac Swing level = %d\n", + (force_exec ? "force to" : ""), fw_dac_swing_lvl); + coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], preFwDacSwingLvl=%d, " + "curFwDacSwingLvl=%d\n", + coex_dm->pre_fw_dac_swing_lvl, + coex_dm->cur_fw_dac_swing_lvl); + + if (coex_dm->pre_fw_dac_swing_lvl == + coex_dm->cur_fw_dac_swing_lvl) + return; + } + + btc8723b2ant_set_fw_dac_swing_level(btcoexist, + coex_dm->cur_fw_dac_swing_lvl); + coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl; +} + +static void btc8723b2ant_set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist, + bool rx_rf_shrink_on) +{ + if (rx_rf_shrink_on) { + /* Shrink RF Rx LPF corner */ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Shrink RF Rx LPF corner!!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff, 0xffffc); + } else { + /* Resume RF Rx LPF corner */ + /* After initialized, we can use coex_dm->btRf0x1eBackup */ + if (btcoexist->initilized) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Resume RF Rx LPF corner!!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff, + coex_dm->bt_rf0x1e_backup); + } + } +} + +static void btc8723b2ant_rf_shrink(struct btc_coexist *btcoexist, + bool force_exec, bool rx_rf_shrink_on) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn Rx RF Shrink = %s\n", + (force_exec ? "force to" : ""), (rx_rf_shrink_on ? + "ON" : "OFF")); + coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], bPreRfRxLpfShrink=%d, " + "bCurRfRxLpfShrink=%d\n", + coex_dm->pre_rf_rx_lpf_shrink, + coex_dm->cur_rf_rx_lpf_shrink); + + if (coex_dm->pre_rf_rx_lpf_shrink == + coex_dm->cur_rf_rx_lpf_shrink) + return; + } + btc8723b2ant_set_sw_rf_rx_lpf_corner(btcoexist, + coex_dm->cur_rf_rx_lpf_shrink); + + coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink; +} + +static void btc8723b_set_penalty_txrate(struct btc_coexist *btcoexist, + bool low_penalty_ra) +{ + u8 h2c_parameter[6] = {0}; + + h2c_parameter[0] = 0x6; /* opCode, 0x6= Retry_Penalty*/ + + if (low_penalty_ra) { + h2c_parameter[1] |= BIT0; + /*normal rate except MCS7/6/5, OFDM54/48/36*/ + h2c_parameter[2] = 0x00; + h2c_parameter[3] = 0xf7; /*MCS7 or OFDM54*/ + h2c_parameter[4] = 0xf8; /*MCS6 or OFDM48*/ + h2c_parameter[5] = 0xf9; /*MCS5 or OFDM36*/ + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], set WiFi Low-Penalty Retry: %s", + (low_penalty_ra ? "ON!!" : "OFF!!")); + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +} + +static void btc8723b2ant_low_penalty_ra(struct btc_coexist *btcoexist, + bool force_exec, bool low_penalty_ra) +{ + /*return; */ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn LowPenaltyRA = %s\n", + (force_exec ? "force to" : ""), (low_penalty_ra ? + "ON" : "OFF")); + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], bPreLowPenaltyRa=%d, " + "bCurLowPenaltyRa=%d\n", + coex_dm->pre_low_penalty_ra, + coex_dm->cur_low_penalty_ra); + + if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + btc8723b_set_penalty_txrate(btcoexist, coex_dm->cur_low_penalty_ra); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +static void btc8723b2ant_set_dac_swing_reg(struct btc_coexist *btcoexist, + u32 level) +{ + u8 val = (u8) level; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Write SwDacSwing = 0x%x\n", level); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x883, 0x3e, val); +} + +static void btc8723b2ant_set_sw_fulltime_dac_swing(struct btc_coexist *btcoex, + bool sw_dac_swing_on, + u32 sw_dac_swing_lvl) +{ + if (sw_dac_swing_on) + btc8723b2ant_set_dac_swing_reg(btcoex, sw_dac_swing_lvl); + else + btc8723b2ant_set_dac_swing_reg(btcoex, 0x18); +} + + +static void btc8723b2ant_dac_swing(struct btc_coexist *btcoexist, + bool force_exec, bool dac_swing_on, + u32 dac_swing_lvl) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn DacSwing=%s, dac_swing_lvl=0x%x\n", + (force_exec ? "force to" : ""), + (dac_swing_on ? "ON" : "OFF"), dac_swing_lvl); + coex_dm->cur_dac_swing_on = dac_swing_on; + coex_dm->cur_dac_swing_lvl = dac_swing_lvl; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl=0x%x," + " bCurDacSwingOn=%d, curDacSwingLvl=0x%x\n", + coex_dm->pre_dac_swing_on, coex_dm->pre_dac_swing_lvl, + coex_dm->cur_dac_swing_on, + coex_dm->cur_dac_swing_lvl); + + if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) && + (coex_dm->pre_dac_swing_lvl == coex_dm->cur_dac_swing_lvl)) + return; + } + mdelay(30); + btc8723b2ant_set_sw_fulltime_dac_swing(btcoexist, dac_swing_on, + dac_swing_lvl); + + coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on; + coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl; +} + +static void btc8723b2ant_set_agc_table(struct btc_coexist *btcoexist, + bool agc_table_en) +{ + u8 rssi_adjust_val = 0; + + /* BB AGC Gain Table */ + if (agc_table_en) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], BB Agc Table On!\n"); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6e1A0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6d1B0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6c1C0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6b1D0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6a1E0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x691F0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x68200001); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], BB Agc Table Off!\n"); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xaa1A0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa91B0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa81C0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa71D0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa61E0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa51F0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa4200001); + } + + + /* RF Gain */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000); + if (agc_table_en) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Agc Table On!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, + 0xfffff, 0x38fff); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, + 0xfffff, 0x38ffe); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Agc Table Off!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, + 0xfffff, 0x380c3); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, + 0xfffff, 0x28ce6); + } + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xed, 0xfffff, 0x1); + + if (agc_table_en) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Agc Table On!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, + 0xfffff, 0x38fff); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, + 0xfffff, 0x38ffe); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Agc Table Off!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, + 0xfffff, 0x380c3); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, + 0xfffff, 0x28ce6); + } + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xed, 0xfffff, 0x0); + + /* set rssiAdjustVal for wifi module. */ + if (agc_table_en) + rssi_adjust_val = 8; + btcoexist->btc_set(btcoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, + &rssi_adjust_val); +} + +static void btc8723b2ant_agc_table(struct btc_coexist *btcoexist, + bool force_exec, bool agc_table_en) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s %s Agc Table\n", + (force_exec ? "force to" : ""), + (agc_table_en ? "Enable" : "Disable")); + coex_dm->cur_agc_table_en = agc_table_en; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], bPreAgcTableEn=%d, bCurAgcTableEn=%d\n", + coex_dm->pre_agc_table_en, coex_dm->cur_agc_table_en); + + if (coex_dm->pre_agc_table_en == coex_dm->cur_agc_table_en) + return; + } + btc8723b2ant_set_agc_table(btcoexist, agc_table_en); + + coex_dm->pre_agc_table_en = coex_dm->cur_agc_table_en; +} + +static void btc8723b2ant_set_coex_table(struct btc_coexist *btcoexist, + u32 val0x6c0, u32 val0x6c4, + u32 val0x6c8, u8 val0x6cc) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0); + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c4=0x%x\n", val0x6c4); + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8); + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc); + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +static void btc8723b2ant_coex_table(struct btc_coexist *btcoexist, + bool force_exec, u32 val0x6c0, + u32 val0x6c4, u32 val0x6c8, + u8 val0x6cc) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s write Coex Table 0x6c0=0x%x," + " 0x6c4=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", + (force_exec ? "force to" : ""), val0x6c0, + val0x6c4, val0x6c8, val0x6cc); + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], preVal0x6c0=0x%x, " + "preVal0x6c4=0x%x, preVal0x6c8=0x%x, " + "preVal0x6cc=0x%x !!\n", + coex_dm->pre_val0x6c0, coex_dm->pre_val0x6c4, + coex_dm->pre_val0x6c8, coex_dm->pre_val0x6cc); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], curVal0x6c0=0x%x, " + "curVal0x6c4=0x%x, curVal0x6c8=0x%x, " + "curVal0x6cc=0x%x !!\n", + coex_dm->cur_val0x6c0, coex_dm->cur_val0x6c4, + coex_dm->cur_val0x6c8, coex_dm->cur_val0x6cc); + + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + btc8723b2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, + val0x6c8, val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +static void btc8723b_coex_tbl_type(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + switch (type) { + case 0: + btc8723b2ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x55555555, 0xffff, 0x3); + break; + case 1: + btc8723b2ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x5afa5afa, 0xffff, 0x3); + break; + case 2: + btc8723b2ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, + 0x5a5a5a5a, 0xffff, 0x3); + break; + case 3: + btc8723b2ant_coex_table(btcoexist, force_exec, 0xaaaaaaaa, + 0xaaaaaaaa, 0xffff, 0x3); + break; + case 4: + btc8723b2ant_coex_table(btcoexist, force_exec, 0xffffffff, + 0xffffffff, 0xffff, 0x3); + break; + case 5: + btc8723b2ant_coex_table(btcoexist, force_exec, 0x5fff5fff, + 0x5fff5fff, 0xffff, 0x3); + break; + case 6: + btc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff, + 0x5a5a5a5a, 0xffff, 0x3); + break; + case 7: + btc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff, + 0x5afa5afa, 0xffff, 0x3); + break; + case 8: + btc8723b2ant_coex_table(btcoexist, force_exec, 0x5aea5aea, + 0x5aea5aea, 0xffff, 0x3); + break; + case 9: + btc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff, + 0x5aea5aea, 0xffff, 0x3); + break; + case 10: + btc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff, + 0x5aff5aff, 0xffff, 0x3); + break; + case 11: + btc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff, + 0x5a5f5a5f, 0xffff, 0x3); + break; + case 12: + btc8723b2ant_coex_table(btcoexist, force_exec, 0x55ff55ff, + 0x5f5f5f5f, 0xffff, 0x3); + break; + default: + break; + } +} + +static void btc8723b2ant_set_fw_ignore_wlan_act(struct btc_coexist *btcoexist, + bool enable) +{ + u8 h2c_parameter[1] = {0}; + + if (enable) + h2c_parameter[0] |= BIT0;/* function enable*/ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], set FW for BT Ignore Wlan_Act, " + "FW write 0x63=0x%x\n", h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +static void btc8723b2ant_ignore_wlan_act(struct btc_coexist *btcoexist, + bool force_exec, bool enable) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s turn Ignore WlanAct %s\n", + (force_exec ? "force to" : ""), (enable ? "ON" : "OFF")); + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], bPreIgnoreWlanAct = %d, " + "bCurIgnoreWlanAct = %d!!\n", + coex_dm->pre_ignore_wlan_act, + coex_dm->cur_ignore_wlan_act); + + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + btc8723b2ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +static void btc8723b2ant_set_fw_ps_tdma(struct btc_coexist *btcoexist, u8 byte1, + u8 byte2, u8 byte3, u8 byte4, u8 byte5) +{ + u8 h2c_parameter[5]; + + h2c_parameter[0] = byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = byte5; + + coex_dm->ps_tdma_para[0] = byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = byte5; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], FW write 0x60(5bytes)=0x%x%08x\n", + h2c_parameter[0], + h2c_parameter[1] << 24 | h2c_parameter[2] << 16 | + h2c_parameter[3] << 8 | h2c_parameter[4]); + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +static void btc8723b2ant_sw_mechanism1(struct btc_coexist *btcoexist, + bool shrink_rx_lpf, bool low_penalty_ra, + bool limited_dig, bool bt_lna_constrain) +{ + btc8723b2ant_rf_shrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf); + btc8723b2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); +} + +static void btc8723b2ant_sw_mechanism2(struct btc_coexist *btcoexist, + bool agc_table_shift, bool adc_backoff, + bool sw_dac_swing, u32 dac_swing_lvl) +{ + btc8723b2ant_agc_table(btcoexist, NORMAL_EXEC, agc_table_shift); + btc8723b2ant_dac_swing(btcoexist, NORMAL_EXEC, sw_dac_swing, + dac_swing_lvl); +} + +static void btc8723b2ant_ps_tdma(struct btc_coexist *btcoexist, bool force_exec, + bool turn_on, u8 type) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s turn %s PS TDMA, type=%d\n", + (force_exec ? "force to" : ""), + (turn_on ? "ON" : "OFF"), type); + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n", + coex_dm->pre_ps_tdma_on, coex_dm->cur_ps_tdma_on); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n", + coex_dm->pre_ps_tdma, coex_dm->cur_ps_tdma); + + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + if (turn_on) { + switch (type) { + case 1: + default: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0xe1, 0x90); + break; + case 2: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x12, + 0x12, 0xe1, 0x90); + break; + case 3: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1c, + 0x3, 0xf1, 0x90); + break; + case 4: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x10, + 0x03, 0xf1, 0x90); + break; + case 5: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0x60, 0x90); + break; + case 6: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x12, + 0x12, 0x60, 0x90); + break; + case 7: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1c, + 0x3, 0x70, 0x90); + break; + case 8: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xa3, 0x10, + 0x3, 0x70, 0x90); + break; + case 9: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0xe1, 0x90); + break; + case 10: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x12, + 0x12, 0xe1, 0x90); + break; + case 11: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa, + 0xa, 0xe1, 0x90); + break; + case 12: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x5, + 0x5, 0xe1, 0x90); + break; + case 13: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0x60, 0x90); + break; + case 14: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x12, + 0x12, 0x60, 0x90); + break; + case 15: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa, + 0xa, 0x60, 0x90); + break; + case 16: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x5, + 0x5, 0x60, 0x90); + break; + case 17: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xa3, 0x2f, + 0x2f, 0x60, 0x90); + break; + case 18: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x5, + 0x5, 0xe1, 0x90); + break; + case 19: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25, + 0x25, 0xe1, 0x90); + break; + case 20: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25, + 0x25, 0x60, 0x90); + break; + case 21: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x15, + 0x03, 0x70, 0x90); + break; + case 71: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0xe1, 0x90); + break; + } + } else { + /* disable PS tdma */ + switch (type) { + case 0: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, 0x0, + 0x40, 0x0); + break; + case 1: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, 0x0, + 0x48, 0x0); + break; + default: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, 0x0, + 0x40, 0x0); + break; + } + } + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +static void btc8723b2ant_coex_alloff(struct btc_coexist *btcoexist) +{ + /* fw all off */ + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + /* sw all off */ + btc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + + /* hw all off */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 0); +} + +static void btc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism*/ + + btc8723b2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1); + btc8723b2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6); + btc8723b2ant_dec_bt_pwr(btcoexist, FORCE_EXEC, false); + + btc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); +} + +static void btc8723b2ant_action_bt_inquiry(struct btc_coexist *btcoexist) +{ + bool wifi_connected = false; + bool low_pwr_disable = true; + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + if (wifi_connected) { + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7); + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); + } else { + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 0); + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + } + btc8723b2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6); + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + + coex_dm->need_recover_0x948 = true; + coex_dm->backup_0x948 = btcoexist->btc_read_2byte(btcoexist, 0x948); + + btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280); +} + +static bool btc8723b2ant_is_common_action(struct btc_coexist *btcoexist) +{ + bool common = false, wifi_connected = false; + bool wifi_busy = false; + bool bt_hs_on = false, low_pwr_disable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!wifi_connected) { + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi non-connected idle!!\n"); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x0); + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 0); + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btc8723b2ant_sw_mechanism1(btcoexist, false, false, false, + false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + + common = true; + } else { + if (BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi connected + " + "BT non connected-idle!!\n"); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x0); + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 0); + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 0xb); + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, + false); + + btc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + common = true; + } else if (BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status) { + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + if (bt_hs_on) + return false; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi connected + " + "BT connected-idle!!\n"); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x0); + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 0); + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 0xb); + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, + false); + + btc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + common = true; + } else { + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + if (wifi_busy) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi Connected-Busy + " + "BT Busy!!\n"); + common = false; + } else { + if (bt_hs_on) + return false; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi Connected-Idle + " + "BT Busy!!\n"); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, + 0x1, 0xfffff, 0x0); + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, + 7); + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 21); + btc8723b2ant_fw_dac_swing_lvl(btcoexist, + NORMAL_EXEC, + 0xb); + if (btc8723b_need_dec_pwr(btcoexist)) + btc8723b2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, + true); + else + btc8723b2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, + false); + btc8723b2ant_sw_mechanism1(btcoexist, false, + false, false, + false); + btc8723b2ant_sw_mechanism2(btcoexist, false, + false, false, + 0x18); + common = true; + } + } + } + + return common; +} + +static void set_tdma_int1(struct btc_coexist *btcoexist, bool tx_pause, + s32 result) +{ + /* Set PS TDMA for max interval == 1 */ + if (tx_pause) { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 1\n"); + + if (coex_dm->cur_ps_tdma == 71) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + coex_dm->tdma_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 1) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + coex_dm->tdma_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->tdma_adj_type = 8; + } else if (coex_dm->cur_ps_tdma == 9) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 13); + coex_dm->tdma_adj_type = 13; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->tdma_adj_type = 16; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->tdma_adj_type = 8; + } else if (coex_dm->cur_ps_tdma == 13) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->tdma_adj_type = 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + coex_dm->tdma_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 16) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 13); + coex_dm->tdma_adj_type = 13; + } + } + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 0\n"); + if (coex_dm->cur_ps_tdma == 5) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 71); + coex_dm->tdma_adj_type = 71; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4); + coex_dm->tdma_adj_type = 4; + } else if (coex_dm->cur_ps_tdma == 13) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); + coex_dm->tdma_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 12); + coex_dm->tdma_adj_type = 12; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 71) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->tdma_adj_type = 1; + } else if (coex_dm->cur_ps_tdma == 1) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->tdma_adj_type = 4; + } else if (coex_dm->cur_ps_tdma == 9) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->tdma_adj_type = 12; + } + } else if (result == 1) { + int tmp = coex_dm->cur_ps_tdma; + switch (tmp) { + case 4: + case 3: + case 2: + case 12: + case 11: + case 10: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, tmp - 1); + coex_dm->tdma_adj_type = tmp - 1; + break; + case 1: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 71); + coex_dm->tdma_adj_type = 71; + break; + } + } + } +} + +static void set_tdma_int2(struct btc_coexist *btcoexist, bool tx_pause, + s32 result) +{ + /* Set PS TDMA for max interval == 2 */ + if (tx_pause) { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 1\n"); + if (coex_dm->cur_ps_tdma == 1) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 8); + coex_dm->tdma_adj_type = 8; + } else if (coex_dm->cur_ps_tdma == 9) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 16); + coex_dm->tdma_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->tdma_adj_type = 8; + } else if (coex_dm->cur_ps_tdma == 13) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->tdma_adj_type = 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 16) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } + } + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 0\n"); + if (coex_dm->cur_ps_tdma == 5) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4); + coex_dm->tdma_adj_type = 4; + } else if (coex_dm->cur_ps_tdma == 13) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 12); + coex_dm->tdma_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->tdma_adj_type = 4; + } else if (coex_dm->cur_ps_tdma == 9) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->tdma_adj_type = 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 12) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } + } + } +} + +static void set_tdma_int3(struct btc_coexist *btcoexist, bool tx_pause, + s32 result) +{ + /* Set PS TDMA for max interval == 3 */ + if (tx_pause) { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 1\n"); + if (coex_dm->cur_ps_tdma == 1) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 8); + coex_dm->tdma_adj_type = 8; + } else if (coex_dm->cur_ps_tdma == 9) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 16); + coex_dm->tdma_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->tdma_adj_type = 8; + } else if (coex_dm->cur_ps_tdma == 13) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->tdma_adj_type = 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 16) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } + } + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 0\n"); + switch (coex_dm->cur_ps_tdma) { + case 5: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); + coex_dm->tdma_adj_type = 3; + break; + case 6: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); + coex_dm->tdma_adj_type = 3; + break; + case 7: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); + coex_dm->tdma_adj_type = 3; + break; + case 8: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4); + coex_dm->tdma_adj_type = 4; + break; + case 13: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); + coex_dm->tdma_adj_type = 11; + break; + case 14: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); + coex_dm->tdma_adj_type = 11; + break; + case 15: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); + coex_dm->tdma_adj_type = 11; + break; + case 16: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 12); + coex_dm->tdma_adj_type = 12; + break; + } + if (result == -1) { + switch (coex_dm->cur_ps_tdma) { + case 1: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + break; + case 2: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + break; + case 3: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->tdma_adj_type = 4; + break; + case 9: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + break; + case 10: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + break; + case 11: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->tdma_adj_type = 12; + break; + } + } else if (result == 1) { + switch (coex_dm->cur_ps_tdma) { + case 4: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + break; + case 3: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + break; + case 2: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + break; + case 12: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + break; + case 11: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + break; + case 10: + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } + } + } +} + +static void btc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, + bool sco_hid, bool tx_pause, + u8 max_interval) +{ + static s32 up, dn, m, n, wait_count; + /*0: no change, +1: increase WiFi duration, -1: decrease WiFi duration*/ + s32 result; + u8 retry_count = 0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], TdmaDurationAdjust()\n"); + + if (!coex_dm->auto_tdma_adjust) { + coex_dm->auto_tdma_adjust = true; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], first run TdmaDurationAdjust()!!\n"); + if (sco_hid) { + if (tx_pause) { + if (max_interval == 1) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 13); + coex_dm->tdma_adj_type = 13; + } else if (max_interval == 2) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (max_interval == 3) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } + } else { + if (max_interval == 1) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + } else if (max_interval == 2) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (max_interval == 3) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } + } + } else { + if (tx_pause) { + if (max_interval == 1) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 5); + coex_dm->tdma_adj_type = 5; + } else if (max_interval == 2) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (max_interval == 3) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } + } else { + if (max_interval == 1) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 1); + coex_dm->tdma_adj_type = 1; + } else if (max_interval == 2) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (max_interval == 3) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } + } + } + + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } else { + /*accquire the BT TRx retry count from BT_Info byte2*/ + retry_count = coex_sta->bt_retry_cnt; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], retry_count = %d\n", retry_count); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], up=%d, dn=%d, m=%d, n=%d, wait_count=%d\n", + up, dn, m, n, wait_count); + result = 0; + wait_count++; + /* no retry in the last 2-second duration*/ + if (retry_count == 0) { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { + wait_count = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], Increase wifi " + "duration!!\n"); + } /* <=3 retry in the last 2-second duration*/ + } else if (retry_count <= 3) { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) { + if (wait_count <= 2) + m++; + else + m = 1; + + if (m >= 20) + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], Decrease wifi duration " + "for retry_counter<3!!\n"); + } + } else { + if (wait_count == 1) + m++; + else + m = 1; + + if (m >= 20) + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], Decrease wifi duration " + "for retry_counter>3!!\n"); + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], max Interval = %d\n", max_interval); + if (max_interval == 1) + set_tdma_int1(btcoexist, tx_pause, result); + else if (max_interval == 2) + set_tdma_int2(btcoexist, tx_pause, result); + else if (max_interval == 3) + set_tdma_int3(btcoexist, tx_pause, result); + } + + /*if current PsTdma not match with the recorded one (when scan, dhcp..), + *then we have to adjust it back to the previous recorded one. + */ + if (coex_dm->cur_ps_tdma != coex_dm->tdma_adj_type) { + bool scan = false, link = false, roam = false; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], PsTdma type dismatch!!!, " + "curPsTdma=%d, recordPsTdma=%d\n", + coex_dm->cur_ps_tdma, coex_dm->tdma_adj_type); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (!scan && !link && !roam) + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + coex_dm->tdma_adj_type); + else + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], roaming/link/scan is under" + " progress, will adjust next time!!!\n"); + } +} + +/* SCO only or SCO+PAN(HS) */ +static void btc8723b2ant_action_sco(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 4); + + if (btc8723b_need_dec_pwr(btcoexist)) + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + /*for SCO quality at 11b/g mode*/ + if (BTC_WIFI_BW_LEGACY == wifi_bw) + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 2); + else /*for SCO quality & wifi performance balance at 11n mode*/ + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 8); + + /*for voice quality */ + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + true, 0x4); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + true, 0x4); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + true, 0x4); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + true, 0x4); + } + } +} + +static void btc8723b2ant_action_hid(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (btc8723b_need_dec_pwr(btcoexist)) + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (BTC_WIFI_BW_LEGACY == wifi_bw) /*/for HID at 11b/g mode*/ + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7); + else /*for HID quality & wifi performance balance at 11n mode*/ + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 9); + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); + else + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/*A2DP only / PAN(EDR) only/ A2DP+PAN(HS)*/ +static void btc8723b2ant_action_a2dp(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (btc8723b_need_dec_pwr(btcoexist)) + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7); + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) + btc8723b2ant_tdma_duration_adjust(btcoexist, false, + false, 1); + else + btc8723b2ant_tdma_duration_adjust(btcoexist, false, true, 1); + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +static void btc8723b2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (btc8723b_need_dec_pwr(btcoexist)) + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7); + + btc8723b2ant_tdma_duration_adjust(btcoexist, false, true, 2); + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, + BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +static void btc8723b2ant_action_pan_edr(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (btc8723b_need_dec_pwr(btcoexist)) + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 10); + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1); + else + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/*PAN(HS) only*/ +static void btc8723b2ant_action_pan_hs(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7); + + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/*PAN(EDR)+A2DP*/ +static void btc8723b2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (btc8723b_need_dec_pwr(btcoexist)) + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 12); + if (BTC_WIFI_BW_HT40 == wifi_bw) + btc8723b2ant_tdma_duration_adjust(btcoexist, false, + true, 3); + else + btc8723b2ant_tdma_duration_adjust(btcoexist, false, + false, 3); + } else { + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7); + btc8723b2ant_tdma_duration_adjust(btcoexist, false, true, 3); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +static void btc8723b2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (btc8723b_need_dec_pwr(btcoexist)) + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + if (BTC_WIFI_BW_HT40 == wifi_bw) { + btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 3); + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 11); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x780); + } else { + btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 6); + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x0); + } + btc8723b2ant_tdma_duration_adjust(btcoexist, true, false, 2); + } else { + btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 11); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x0); + btc8723b2ant_tdma_duration_adjust(btcoexist, true, true, 2); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* HID+A2DP+PAN(EDR) */ +static void btc8723b2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (btc8723b_need_dec_pwr(btcoexist)) + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7); + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + if (BTC_WIFI_BW_HT40 == wifi_bw) + btc8723b2ant_tdma_duration_adjust(btcoexist, true, + true, 2); + else + btc8723b2ant_tdma_duration_adjust(btcoexist, true, + false, 3); + } else { + btc8723b2ant_tdma_duration_adjust(btcoexist, true, true, 3); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +static void btc8723b2ant_action_hid_a2dp(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (btc8723b_need_dec_pwr(btcoexist)) + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 7); + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) + btc8723b2ant_tdma_duration_adjust(btcoexist, true, false, 2); + else + btc8723b2ant_tdma_duration_adjust(btcoexist, true, true, 2); + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +static void btc8723b2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) +{ + u8 algorithm = 0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], RunCoexistMechanism()===>\n"); + + if (btcoexist->manual_control) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], RunCoexistMechanism(), " + "return for Manual CTRL <===\n"); + return; + } + + if (coex_sta->under_ips) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], wifi is under IPS !!!\n"); + return; + } + + algorithm = btc8723b2ant_action_algorithm(btcoexist); + if (coex_sta->c2h_bt_inquiry_page && + (BT_8723B_2ANT_COEX_ALGO_PANHS != algorithm)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT is under inquiry/page scan !!\n"); + btc8723b2ant_action_bt_inquiry(btcoexist); + return; + } else { + if (coex_dm->need_recover_0x948) { + coex_dm->need_recover_0x948 = false; + btcoexist->btc_write_2byte(btcoexist, 0x948, + coex_dm->backup_0x948); + } + } + + coex_dm->cur_algorithm = algorithm; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], Algorithm = %d\n", + coex_dm->cur_algorithm); + + if (btc8723b2ant_is_common_action(btcoexist)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant common.\n"); + coex_dm->auto_tdma_adjust = false; + } else { + if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], preAlgorithm=%d, " + "curAlgorithm=%d\n", coex_dm->pre_algorithm, + coex_dm->cur_algorithm); + coex_dm->auto_tdma_adjust = false; + } + switch (coex_dm->cur_algorithm) { + case BT_8723B_2ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, algorithm = SCO.\n"); + btc8723b2ant_action_sco(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, algorithm = HID.\n"); + btc8723b2ant_action_hid(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, " + "algorithm = A2DP.\n"); + btc8723b2ant_action_a2dp(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, " + "algorithm = A2DP+PAN(HS).\n"); + btc8723b2ant_action_a2dp_pan_hs(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, " + "algorithm = PAN(EDR).\n"); + btc8723b2ant_action_pan_edr(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, " + "algorithm = HS mode.\n"); + btc8723b2ant_action_pan_hs(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, " + "algorithm = PAN+A2DP.\n"); + btc8723b2ant_action_pan_edr_a2dp(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, " + "algorithm = PAN(EDR)+HID.\n"); + btc8723b2ant_action_pan_edr_hid(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, " + "algorithm = HID+A2DP+PAN.\n"); + btc8723b2ant_action_hid_a2dp_pan_edr(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, " + "algorithm = HID+A2DP.\n"); + btc8723b2ant_action_hid_a2dp(btcoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, " + "algorithm = coexist All Off!!\n"); + btc8723b2ant_coex_alloff(btcoexist); + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + + + +/********************************************************************* + * work around function start with wa_btc8723b2ant_ + *********************************************************************/ +/********************************************************************* + * extern function start with EXbtc8723b2ant_ + *********************************************************************/ +void ex_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u32 u32tmp = 0, fw_ver; + u8 u8tmp = 0; + u8 h2c_parameter[2] = {0}; + + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], 2Ant Init HW Config!!\n"); + + /* backup rf 0x1e value */ + coex_dm->bt_rf0x1e_backup = btcoexist->btc_get_rf_reg(btcoexist, + BTC_RF_A, 0x1e, + 0xfffff); + + /* 0x4c[23]=0, 0x4c[24]=1 Antenna control by WL/BT */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp &= ~BIT23; + u32tmp |= BIT24; + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3); + btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1); + + /* Antenna switch control parameter */ + /* btcoexist->btc_write_4byte(btcoexist, 0x858, 0x55555555);*/ + + /*Force GNT_BT to low*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0); + btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0); + + /* 0x790[5:0]=0x5 */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); + u8tmp &= 0xc0; + u8tmp |= 0x5; + btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + + + /*Antenna config */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + + /*ext switch for fw ver < 0xc */ + if (fw_ver < 0xc00) { + if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, + 0x3, 0x1); + /*Main Ant to BT for IPS case 0x4c[23]=1*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, + 0x1); + + /*tell firmware "no antenna inverse"*/ + h2c_parameter[0] = 0; + h2c_parameter[1] = 1; /* ext switch type */ + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } else { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, + 0x3, 0x2); + /*Aux Ant to BT for IPS case 0x4c[23]=1*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, + 0x0); + + /*tell firmware "antenna inverse"*/ + h2c_parameter[0] = 1; + h2c_parameter[1] = 1; /*ext switch type*/ + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } + } else { + /*ext switch always at s1 (if exist) */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, 0x3, 0x1); + /*Main Ant to BT for IPS case 0x4c[23]=1*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, 0x1); + + if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { + /*tell firmware "no antenna inverse"*/ + h2c_parameter[0] = 0; + h2c_parameter[1] = 0; /*ext switch type*/ + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } else { + /*tell firmware "antenna inverse"*/ + h2c_parameter[0] = 1; + h2c_parameter[1] = 0; /*ext switch type*/ + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } + } + + /* PTA parameter */ + btc8723b_coex_tbl_type(btcoexist, FORCE_EXEC, 0); + + /* Enable counter statistics */ + /*0x76e[3] =1, WLAN_Act control by PTA*/ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); +} + +void ex_halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], Coex Mechanism Init!!\n"); + btc8723b2ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; + u32 u32tmp[4]; + bool roam = false, scan = false; + bool link = false, wifi_under_5g = false; + bool bt_hs_on = false, wifi_busy = false; + s32 wifi_rssi = 0, bt_hs_rssi = 0; + u32 wifi_bw, wifi_traffic_dir, fa_ofdm, fa_cck; + u8 wifi_dot11_chnl, wifi_hs_chnl; + u32 fw_ver = 0, bt_patch_ver = 0; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ==========[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + if (!board_info->bt_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cli_buf); + return; + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + "Ant PG number/ Ant mechanism:", + board_info->pg_ant_num, board_info->btdm_ant_num); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", + "BT stack/ hci ext ver", + ((stack_info->profile_notified) ? "Yes" : "No"), + stack_info->hci_version); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", + "CoexVer/ FwVer/ PatchVer", + glcoex_ver_date_8723b_2ant, glcoex_ver_8723b_2ant, + fw_ver, bt_patch_ver, bt_patch_ver); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL, + &wifi_dot11_chnl); + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", + "Dot11 channel / HsChnl(HsMode)", + wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "H2C Wifi inform bt chnl Info", coex_dm->wifi_chnl_info[0], + coex_dm->wifi_chnl_info[1], coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "Wifi rssi/ HS rssi", wifi_rssi, bt_hs_rssi); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + "Wifi link/ roam/ scan", link, roam, scan); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, + &wifi_traffic_dir); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", + "Wifi status", (wifi_under_5g ? "5G" : "2.4G"), + ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" : + (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))), + ((!wifi_busy) ? "idle" : + ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? + "uplink" : "downlink"))); + CL_PRINTF(cli_buf); + + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", + "SCO/HID/PAN/A2DP", + bt_link_info->sco_exist, bt_link_info->hid_exist, + bt_link_info->pan_exist, bt_link_info->a2dp_exist); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + + bt_info_ext = coex_sta->bt_info_ext; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "BT Info A2DP rate", + (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate"); + CL_PRINTF(cli_buf); + + for (i = 0; i < BT_INFO_SRC_8723B_2ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x " + "%02x %02x %02x %02x(%d)", + glbt_info_src_8723b_2ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s", + "PS state, IPS/LPS", + ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")), + ((coex_sta->under_lps ? "LPS ON" : "LPS OFF"))); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + /* Sw mechanism */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s", "============[Sw mechanism]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + "SM1[ShRf/ LpRA/ LimDig]", coex_dm->cur_rf_rx_lpf_shrink, + coex_dm->cur_low_penalty_ra, coex_dm->limited_dig); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", + "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", + coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off, + coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl); + CL_PRINTF(cli_buf); + + /* Fw mechanism */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Fw mechanism]============"); + CL_PRINTF(cli_buf); + + ps_tdma_case = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", + "PS TDMA", coex_dm->ps_tdma_para[0], + coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2], + coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4], + ps_tdma_case, coex_dm->auto_tdma_adjust); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + "DecBtPwr/ IgnWlanAct", coex_dm->cur_dec_bt_pwr, + coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", + "RF-A, 0x1e initVal", coex_dm->bt_rf0x1e_backup); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x880); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x778/0x880[29:25]", u8tmp[0], + (u32tmp[0]&0x3e000000) >> 25); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x765); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x948/ 0x67[5] / 0x765", + u32tmp[0], ((u8tmp[0]&0x20) >> 5), u8tmp[1]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x92c); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x930); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x944); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]", + u32tmp[0]&0x3, u32tmp[1]&0xff, u32tmp[2]&0x3); + CL_PRINTF(cli_buf); + + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x39); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x38[11]/0x40/0x4c[24:23]/0x64[0]", + ((u8tmp[0] & 0x8)>>3), u8tmp[1], + ((u32tmp[0]&0x01800000)>>23), u8tmp[2]&0x1); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x49c); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0xc50(dig)/0x49c(null-drop)", u32tmp[0]&0xff, u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xda0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xda4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0xda8); + u32tmp[3] = btcoexist->btc_read_4byte(btcoexist, 0xcf0); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5b); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c); + + fa_ofdm = ((u32tmp[0]&0xffff0000) >> 16) + + ((u32tmp[1]&0xffff0000) >> 16) + + (u32tmp[1] & 0xffff) + + (u32tmp[2] & 0xffff) + + ((u32tmp[3]&0xffff0000) >> 16) + + (u32tmp[3] & 0xffff); + fa_cck = (u8tmp[0] << 8) + u8tmp[1]; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "OFDM-CCA/OFDM-FA/CCK-FA", + u32tmp[0]&0xffff, fa_ofdm, fa_cck); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", + u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770(high-pri rx/tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(low-pri rx/tx)", coex_sta->low_priority_rx, + coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); +#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 1) + btc8723b2ant_monitor_bt_ctr(btcoexist); +#endif + btcoexist->btc_disp_dbg_msg(btcoexist, + BTC_DBG_DISP_COEX_STATISTICS); +} + + +void ex_halbtc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_IPS_ENTER == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], IPS ENTER notify\n"); + coex_sta->under_ips = true; + btc8723b2ant_coex_alloff(btcoexist); + } else if (BTC_IPS_LEAVE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], IPS LEAVE notify\n"); + coex_sta->under_ips = false; + } +} + +void ex_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_LPS_ENABLE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], LPS ENABLE notify\n"); + coex_sta->under_lps = true; + } else if (BTC_LPS_DISABLE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], LPS DISABLE notify\n"); + coex_sta->under_lps = false; + } +} + +void ex_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_SCAN_START == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], SCAN START notify\n"); + else if (BTC_SCAN_FINISH == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], SCAN FINISH notify\n"); +} + +void ex_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_ASSOCIATE_START == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], CONNECT START notify\n"); + else if (BTC_ASSOCIATE_FINISH == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], CONNECT FINISH notify\n"); +} + +void btc8723b_med_stat_notify(struct btc_coexist *btcoexist, + u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + + if (BTC_MEDIA_CONNECT == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], MEDIA connect notify\n"); + else + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], MEDIA disconnect notify\n"); + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, + BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifi_central_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_central_chnl <= 14)) { + h2c_parameter[0] = 0x1; + h2c_parameter[1] = wifi_central_chnl; + btcoexist->btc_get(btcoexist, + BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], FW write 0x66=0x%x\n", + h2c_parameter[0] << 16 | h2c_parameter[1] << 8 | + h2c_parameter[2]); + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +void ex_halbtc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type) +{ + if (type == BTC_PACKET_DHCP) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], DHCP Packet notify\n"); +} + +void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmpbuf, u8 length) +{ + u8 bt_info = 0; + u8 i, rsp_source = 0; + bool bt_busy = false, limited_dig = false; + bool wifi_connected = false; + + coex_sta->c2h_bt_info_req_sent = false; + + rsp_source = tmpbuf[0]&0xf; + if (rsp_source >= BT_INFO_SRC_8723B_2ANT_MAX) + rsp_source = BT_INFO_SRC_8723B_2ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], Bt info[%d], length=%d, hex data=[", + rsp_source, length); + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmpbuf[i]; + if (i == 1) + bt_info = tmpbuf[i]; + if (i == length-1) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "0x%02x]\n", tmpbuf[i]); + else + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "0x%02x, ", tmpbuf[i]); + } + + if (btcoexist->manual_control) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), " + "return for Manual CTRL<===\n"); + return; + } + + if (BT_INFO_SRC_8723B_2ANT_WIFI_FW != rsp_source) { + coex_sta->bt_retry_cnt = /* [3:0]*/ + coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + + coex_sta->bt_rssi = + coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10; + + coex_sta->bt_info_ext = + coex_sta->bt_info_c2h[rsp_source][4]; + + /* Here we need to resend some wifi info to BT + * because bt is reset and loss of the info. + */ + if ((coex_sta->bt_info_ext & BIT1)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT ext info bit1 check," + " send wifi BW&Chnl to BT!!\n"); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (wifi_connected) + btc8723b_med_stat_notify(btcoexist, + BTC_MEDIA_CONNECT); + else + btc8723b_med_stat_notify(btcoexist, + BTC_MEDIA_DISCONNECT); + } + + if ((coex_sta->bt_info_ext & BIT3)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT ext info bit3 check, " + "set BT NOT to ignore Wlan active!!\n"); + btc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, + false); + } else { + /* BT already NOT ignore Wlan active, do nothing here.*/ + } +#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 0) + if ((coex_sta->bt_info_ext & BIT4)) { + /* BT auto report already enabled, do nothing*/ + } else { + btc8723b2ant_bt_auto_report(btcoexist, FORCE_EXEC, + true); + } +#endif + } + + /* check BIT2 first ==> check if bt is under inquiry or page scan*/ + if (bt_info & BT_INFO_8723B_2ANT_B_INQ_PAGE) + coex_sta->c2h_bt_inquiry_page = true; + else + coex_sta->c2h_bt_inquiry_page = false; + + /* set link exist status*/ + if (!(bt_info & BT_INFO_8723B_2ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (bt_info & BT_INFO_8723B_2ANT_B_FTP) + coex_sta->pan_exist = true; + else + coex_sta->pan_exist = false; + if (bt_info & BT_INFO_8723B_2ANT_B_A2DP) + coex_sta->a2dp_exist = true; + else + coex_sta->a2dp_exist = false; + if (bt_info & BT_INFO_8723B_2ANT_B_HID) + coex_sta->hid_exist = true; + else + coex_sta->hid_exist = false; + if (bt_info & BT_INFO_8723B_2ANT_B_SCO_ESCO) + coex_sta->sco_exist = true; + else + coex_sta->sco_exist = false; + } + + btc8723b2ant_update_bt_link_info(btcoexist); + + if (!(bt_info & BT_INFO_8723B_2ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), " + "BT Non-Connected idle!!!\n"); + /* connection exists but no busy */ + } else if (bt_info == BT_INFO_8723B_2ANT_B_CONNECTION) { + coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + } else if ((bt_info & BT_INFO_8723B_2ANT_B_SCO_ESCO) || + (bt_info & BT_INFO_8723B_2ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_SCO_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + } else if (bt_info & BT_INFO_8723B_2ANT_B_ACL_BUSY) { + coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_ACL_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + } else { + coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_MAX; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), " + "BT Non-Defined state!!!\n"); + } + + if ((BT_8723B_2ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8723B_2ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) { + bt_busy = true; + limited_dig = true; + } else { + bt_busy = false; + limited_dig = false; + } + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + coex_dm->limited_dig = limited_dig; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); + + btc8723b2ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8723b2ant_stack_operation_notify(struct btc_coexist *btcoexist, + u8 type) +{ + if (BTC_STACK_OP_INQ_PAGE_PAIR_START == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex],StackOP Inquiry/page/pair start notify\n"); + else if (BTC_STACK_OP_INQ_PAGE_PAIR_FINISH == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex],StackOP Inquiry/page/pair finish notify\n"); +} + +void ex_halbtc8723b2ant_halt_notify(struct btc_coexist *btcoexist) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n"); + + btc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + btc8723b_med_stat_notify(btcoexist, BTC_MEDIA_DISCONNECT); +} + +void ex_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + static u8 dis_ver_info_cnt; + u32 fw_ver = 0, bt_patch_ver = 0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], ==========================" + "Periodical===========================\n"); + + if (dis_ver_info_cnt <= 5) { + dis_ver_info_cnt += 1; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], ****************************" + "************************************\n"); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], Ant PG Num/ Ant Mech/ " + "Ant Pos = %d/ %d/ %d\n", board_info->pg_ant_num, + board_info->btdm_ant_num, board_info->btdm_ant_pos); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], BT stack/ hci ext ver = %s / %d\n", + ((stack_info->profile_notified) ? "Yes" : "No"), + stack_info->hci_version); + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, + &bt_patch_ver); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], CoexVer/ FwVer/ PatchVer = " + "%d_%x/ 0x%x/ 0x%x(%d)\n", + glcoex_ver_date_8723b_2ant, glcoex_ver_8723b_2ant, + fw_ver, bt_patch_ver, bt_patch_ver); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], *****************************" + "***********************************\n"); + } + +#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 0) + btc8723b2ant_query_bt_info(btcoexist); + btc8723b2ant_monitor_bt_ctr(btcoexist); + btc8723b2ant_monitor_bt_enable_disable(btcoexist); +#else + if (btc8723b2ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) + btc8723b2ant_run_coexist_mechanism(btcoexist); +#endif +} diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h new file mode 100644 index 000000000000..e0ad8e545f82 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h @@ -0,0 +1,173 @@ +/****************************************************************************** + * + * Copyright(c) 2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#ifndef _HAL8723B_2_ANT +#define _HAL8723B_2_ANT + +/************************************************************************ + * The following is for 8723B 2Ant BT Co-exist definition + ************************************************************************/ +#define BT_AUTO_REPORT_ONLY_8723B_2ANT 1 + +#define BT_INFO_8723B_2ANT_B_FTP BIT7 +#define BT_INFO_8723B_2ANT_B_A2DP BIT6 +#define BT_INFO_8723B_2ANT_B_HID BIT5 +#define BT_INFO_8723B_2ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8723B_2ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8723B_2ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8723B_2ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8723B_2ANT_B_CONNECTION BIT0 + +#define BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT 2 + +enum BT_INFO_SRC_8723B_2ANT { + BT_INFO_SRC_8723B_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8723B_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8723B_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8723B_2ANT_MAX +}; + +enum BT_8723B_2ANT_BT_STATUS { + BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8723B_2ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8723B_2ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8723B_2ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8723B_2ANT_BT_STATUS_MAX +}; + +enum BT_8723B_2ANT_COEX_ALGO { + BT_8723B_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8723B_2ANT_COEX_ALGO_SCO = 0x1, + BT_8723B_2ANT_COEX_ALGO_HID = 0x2, + BT_8723B_2ANT_COEX_ALGO_A2DP = 0x3, + BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8723B_2ANT_COEX_ALGO_PANEDR = 0x5, + BT_8723B_2ANT_COEX_ALGO_PANHS = 0x6, + BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8723B_2ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8723B_2ANT_COEX_ALGO_MAX = 0xb, +}; + +struct coex_dm_8723b_2ant { + /* fw mechanism */ + bool pre_dec_bt_pwr; + bool cur_dec_bt_pwr; + u8 pre_fw_dac_swing_lvl; + u8 cur_fw_dac_swing_lvl; + bool cur_ignore_wlan_act; + bool pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 tdma_adj_type; + bool reset_tdma_adjust; + bool auto_tdma_adjust; + bool pre_ps_tdma_on; + bool cur_ps_tdma_on; + bool pre_bt_auto_report; + bool cur_bt_auto_report; + + /* sw mechanism */ + bool pre_rf_rx_lpf_shrink; + bool cur_rf_rx_lpf_shrink; + u32 bt_rf0x1e_backup; + bool pre_low_penalty_ra; + bool cur_low_penalty_ra; + bool pre_dac_swing_on; + u32 pre_dac_swing_lvl; + bool cur_dac_swing_on; + u32 cur_dac_swing_lvl; + bool pre_adc_back_off; + bool cur_adc_back_off; + bool pre_agc_table_en; + bool cur_agc_table_en; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + bool limited_dig; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + bool need_recover_0x948; + u16 backup_0x948; +}; + +struct coex_sta_8723b_2ant { + bool bt_link_exist; + bool sco_exist; + bool a2dp_exist; + bool hid_exist; + bool pan_exist; + + bool under_lps; + bool under_ips; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + u8 bt_rssi; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + bool c2h_bt_info_req_sent; + u8 bt_info_c2h[BT_INFO_SRC_8723B_2ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8723B_2ANT_MAX]; + bool c2h_bt_inquiry_page; + u8 bt_retry_cnt; + u8 bt_info_ext; +}; + +/********************************************************************* + * The following is interface which will notify coex module. + *********************************************************************/ +void ex_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist); +void ex_halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex_halbtc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type); +void btc8723b_med_stat_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmpbuf, u8 length); +void ex_halbtc8723b2ant_stack_operation_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_halbtc8723b2ant_halt_notify(struct btc_coexist *btcoexist); +void ex_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist); +void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist); + +#endif diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c new file mode 100644 index 000000000000..9e1217f2c966 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c @@ -0,0 +1,1011 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2013 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + ******************************************************************************/ + +#include "halbt_precomp.h" + +/*********************************************** + * Global variables + ***********************************************/ + +struct btc_coexist gl_bt_coexist; + +u32 btc_dbg_type[BTC_MSG_MAX]; +static u8 btc_dbg_buf[100]; + +/*************************************************** + * Debug related function + ***************************************************/ +static bool halbtc_is_bt_coexist_available(struct btc_coexist *btcoexist) +{ + if (!btcoexist->binded || NULL == btcoexist->adapter) + return false; + + return true; +} + +static bool halbtc_is_wifi_busy(struct rtl_priv *rtlpriv) +{ + if (rtlpriv->link_info.busytraffic) + return true; + else + return false; +} + +static void halbtc_dbg_init(void) +{ + u8 i; + + for (i = 0; i < BTC_MSG_MAX; i++) + btc_dbg_type[i] = 0; + + btc_dbg_type[BTC_MSG_INTERFACE] = +/* INTF_INIT | */ +/* INTF_NOTIFY | */ + 0; + + btc_dbg_type[BTC_MSG_ALGORITHM] = +/* ALGO_BT_RSSI_STATE | */ +/* ALGO_WIFI_RSSI_STATE | */ +/* ALGO_BT_MONITOR | */ +/* ALGO_TRACE | */ +/* ALGO_TRACE_FW | */ +/* ALGO_TRACE_FW_DETAIL | */ +/* ALGO_TRACE_FW_EXEC | */ +/* ALGO_TRACE_SW | */ +/* ALGO_TRACE_SW_DETAIL | */ +/* ALGO_TRACE_SW_EXEC | */ + 0; +} + +static bool halbtc_is_bt40(struct rtl_priv *adapter) +{ + struct rtl_priv *rtlpriv = adapter; + struct rtl_phy *rtlphy = &(rtlpriv->phy); + bool is_ht40 = true; + enum ht_channel_width bw = rtlphy->current_chan_bw; + + if (bw == HT_CHANNEL_WIDTH_20) + is_ht40 = false; + else if (bw == HT_CHANNEL_WIDTH_20_40) + is_ht40 = true; + + return is_ht40; +} + +static bool halbtc_legacy(struct rtl_priv *adapter) +{ + struct rtl_priv *rtlpriv = adapter; + struct rtl_mac *mac = rtl_mac(rtlpriv); + + bool is_legacy = false; + + if ((mac->mode == WIRELESS_MODE_B) || (mac->mode == WIRELESS_MODE_B)) + is_legacy = true; + + return is_legacy; +} + +bool halbtc_is_wifi_uplink(struct rtl_priv *adapter) +{ + struct rtl_priv *rtlpriv = adapter; + + if (rtlpriv->link_info.tx_busy_traffic) + return true; + else + return false; +} + +static u32 halbtc_get_wifi_bw(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = + (struct rtl_priv *)btcoexist->adapter; + u32 wifi_bw = BTC_WIFI_BW_HT20; + + if (halbtc_is_bt40(rtlpriv)) { + wifi_bw = BTC_WIFI_BW_HT40; + } else { + if (halbtc_legacy(rtlpriv)) + wifi_bw = BTC_WIFI_BW_LEGACY; + else + wifi_bw = BTC_WIFI_BW_HT20; + } + return wifi_bw; +} + +static u8 halbtc_get_wifi_central_chnl(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 chnl = 1; + + if (rtlphy->current_channel != 0) + chnl = rtlphy->current_channel; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "static halbtc_get_wifi_central_chnl:%d\n", chnl); + return chnl; +} + +static void halbtc_leave_lps(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv; + struct rtl_ps_ctl *ppsc; + bool ap_enable = false; + + rtlpriv = btcoexist->adapter; + ppsc = rtl_psc(rtlpriv); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + pr_info("halbtc_leave_lps()<--dont leave lps under AP mode\n"); + return; + } + + btcoexist->bt_info.bt_ctrl_lps = true; + btcoexist->bt_info.bt_lps_on = false; +} + +static void halbtc_enter_lps(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv; + struct rtl_ps_ctl *ppsc; + bool ap_enable = false; + + rtlpriv = btcoexist->adapter; + ppsc = rtl_psc(rtlpriv); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + pr_info("halbtc_enter_lps()<--dont enter lps under AP mode\n"); + return; + } + + btcoexist->bt_info.bt_ctrl_lps = true; + btcoexist->bt_info.bt_lps_on = false; +} + +static void halbtc_normal_lps(struct btc_coexist *btcoexist) +{ + if (btcoexist->bt_info.bt_ctrl_lps) { + btcoexist->bt_info.bt_lps_on = false; + btcoexist->bt_info.bt_ctrl_lps = false; + } +} + +static void halbtc_leave_low_power(void) +{ +} + +static void halbtc_nomal_low_power(void) +{ +} + +static void halbtc_disable_low_power(void) +{ +} + +static void halbtc_aggregation_check(void) +{ +} + +static u32 halbtc_get_bt_patch_version(struct btc_coexist *btcoexist) +{ + return 0; +} + +static s32 halbtc_get_wifi_rssi(struct rtl_priv *adapter) +{ + struct rtl_priv *rtlpriv = adapter; + s32 undec_sm_pwdb = 0; + + if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) + undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb; + else /* associated entry pwdb */ + undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb; + return undec_sm_pwdb; +} + +static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)void_btcoexist; + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtlpriv); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + bool *bool_tmp = (bool *)out_buf; + int *s32_tmp = (int *)out_buf; + u32 *u32_tmp = (u32 *)out_buf; + u8 *u8_tmp = (u8 *)out_buf; + bool tmp = false; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return false; + + switch (get_type) { + case BTC_GET_BL_HS_OPERATION: + *bool_tmp = false; + break; + case BTC_GET_BL_HS_CONNECTING: + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_CONNECTED: + if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) + tmp = true; + *bool_tmp = tmp; + break; + case BTC_GET_BL_WIFI_BUSY: + if (halbtc_is_wifi_busy(rtlpriv)) + *bool_tmp = true; + else + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_SCAN: + if (mac->act_scanning) + *bool_tmp = true; + else + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_LINK: + if (mac->link_state == MAC80211_LINKING) + *bool_tmp = true; + else + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_ROAM: /*TODO*/ + if (mac->link_state == MAC80211_LINKING) + *bool_tmp = true; + else + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_4_WAY_PROGRESS: /*TODO*/ + *bool_tmp = false; + + break; + case BTC_GET_BL_WIFI_UNDER_5G: + *bool_tmp = false; /*TODO*/ + + case BTC_GET_BL_WIFI_DHCP: /*TODO*/ + break; + case BTC_GET_BL_WIFI_SOFTAP_IDLE: + *bool_tmp = true; + break; + case BTC_GET_BL_WIFI_SOFTAP_LINKING: + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_IN_EARLY_SUSPEND: + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_AP_MODE_ENABLE: + *bool_tmp = false; + break; + case BTC_GET_BL_WIFI_ENABLE_ENCRYPTION: + if (NO_ENCRYPTION == rtlpriv->sec.pairwise_enc_algorithm) + *bool_tmp = false; + else + *bool_tmp = true; + break; + case BTC_GET_BL_WIFI_UNDER_B_MODE: + *bool_tmp = false; /*TODO*/ + break; + case BTC_GET_BL_EXT_SWITCH: + *bool_tmp = false; + break; + case BTC_GET_S4_WIFI_RSSI: + *s32_tmp = halbtc_get_wifi_rssi(rtlpriv); + break; + case BTC_GET_S4_HS_RSSI: /*TODO*/ + *s32_tmp = halbtc_get_wifi_rssi(rtlpriv); + break; + case BTC_GET_U4_WIFI_BW: + *u32_tmp = halbtc_get_wifi_bw(btcoexist); + break; + case BTC_GET_U4_WIFI_TRAFFIC_DIRECTION: + if (halbtc_is_wifi_uplink(rtlpriv)) + *u32_tmp = BTC_WIFI_TRAFFIC_TX; + else + *u32_tmp = BTC_WIFI_TRAFFIC_RX; + break; + case BTC_GET_U4_WIFI_FW_VER: + *u32_tmp = rtlhal->fw_version; + break; + case BTC_GET_U4_BT_PATCH_VER: + *u32_tmp = halbtc_get_bt_patch_version(btcoexist); + break; + case BTC_GET_U1_WIFI_DOT11_CHNL: + *u8_tmp = rtlphy->current_channel; + break; + case BTC_GET_U1_WIFI_CENTRAL_CHNL: + *u8_tmp = halbtc_get_wifi_central_chnl(btcoexist); + break; + case BTC_GET_U1_WIFI_HS_CHNL: + *u8_tmp = 1;/*BT_OperateChnl(rtlpriv);*/ + break; + case BTC_GET_U1_MAC_PHY_MODE: + *u8_tmp = BTC_MP_UNKNOWN; + break; + + /************* 1Ant **************/ + case BTC_GET_U1_LPS_MODE: + *u8_tmp = btcoexist->pwr_mode_val[0]; + break; + + default: + break; + } + + return true; +} + +static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)void_btcoexist; + bool *bool_tmp = (bool *)in_buf; + u8 *u8_tmp = (u8 *)in_buf; + u32 *u32_tmp = (u32 *)in_buf; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return false; + + switch (set_type) { + /* set some bool type variables. */ + case BTC_SET_BL_BT_DISABLE: + btcoexist->bt_info.bt_disabled = *bool_tmp; + break; + case BTC_SET_BL_BT_TRAFFIC_BUSY: + btcoexist->bt_info.bt_busy = *bool_tmp; + break; + case BTC_SET_BL_BT_LIMITED_DIG: + btcoexist->bt_info.limited_dig = *bool_tmp; + break; + case BTC_SET_BL_FORCE_TO_ROAM: + btcoexist->bt_info.force_to_roam = *bool_tmp; + break; + case BTC_SET_BL_TO_REJ_AP_AGG_PKT: + btcoexist->bt_info.reject_agg_pkt = *bool_tmp; + break; + case BTC_SET_BL_BT_CTRL_AGG_SIZE: + btcoexist->bt_info.b_bt_ctrl_buf_size = *bool_tmp; + break; + case BTC_SET_BL_INC_SCAN_DEV_NUM: + btcoexist->bt_info.increase_scan_dev_num = *bool_tmp; + break; + /* set some u1Byte type variables. */ + case BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON: + btcoexist->bt_info.rssi_adjust_for_agc_table_on = *u8_tmp; + break; + case BTC_SET_U1_AGG_BUF_SIZE: + btcoexist->bt_info.agg_buf_size = *u8_tmp; + break; + /* the following are some action which will be triggered */ + case BTC_SET_ACT_GET_BT_RSSI: + /*BTHCI_SendGetBtRssiEvent(rtlpriv);*/ + break; + case BTC_SET_ACT_AGGREGATE_CTRL: + halbtc_aggregation_check(); + break; + + /* 1Ant */ + case BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE: + btcoexist->bt_info.rssi_adjust_for_1ant_coex_type = *u8_tmp; + break; + case BTC_SET_UI_SCAN_SIG_COMPENSATION: + /* rtlpriv->mlmepriv.scan_compensation = *u8_tmp; */ + break; + case BTC_SET_U1_1ANT_LPS: + btcoexist->bt_info.lps_1ant = *u8_tmp; + break; + case BTC_SET_U1_1ANT_RPWM: + btcoexist->bt_info.rpwm_1ant = *u8_tmp; + break; + /* the following are some action which will be triggered */ + case BTC_SET_ACT_LEAVE_LPS: + halbtc_leave_lps(btcoexist); + break; + case BTC_SET_ACT_ENTER_LPS: + halbtc_enter_lps(btcoexist); + break; + case BTC_SET_ACT_NORMAL_LPS: + halbtc_normal_lps(btcoexist); + break; + case BTC_SET_ACT_DISABLE_LOW_POWER: + halbtc_disable_low_power(); + break; + case BTC_SET_ACT_UPDATE_ra_mask: + btcoexist->bt_info.ra_mask = *u32_tmp; + break; + case BTC_SET_ACT_SEND_MIMO_PS: + break; + case BTC_SET_ACT_INC_FORCE_EXEC_PWR_CMD_CNT: + btcoexist->bt_info.force_exec_pwr_cmd_cnt++; + break; + case BTC_SET_ACT_CTRL_BT_INFO: /*wait for 8812/8821*/ + break; + case BTC_SET_ACT_CTRL_BT_COEX: + break; + default: + break; + } + + return true; +} + +static void halbtc_display_coex_statistics(struct btc_coexist *btcoexist) +{ +} + +static void halbtc_display_bt_link_info(struct btc_coexist *btcoexist) +{ +} + +static void halbtc_display_bt_fw_info(struct btc_coexist *btcoexist) +{ +} + +static void halbtc_display_fw_pwr_mode_cmd(struct btc_coexist *btcoexist) +{ +} + +/************************************************************ + * IO related function + ************************************************************/ +static u8 halbtc_read_1byte(void *bt_context, u32 reg_addr) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + return rtl_read_byte(rtlpriv, reg_addr); +} + +static u16 halbtc_read_2byte(void *bt_context, u32 reg_addr) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + return rtl_read_word(rtlpriv, reg_addr); +} + +static u32 halbtc_read_4byte(void *bt_context, u32 reg_addr) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + return rtl_read_dword(rtlpriv, reg_addr); +} + +static void halbtc_write_1byte(void *bt_context, u32 reg_addr, u8 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtl_write_byte(rtlpriv, reg_addr, data); +} + +static void halbtc_bitmask_write_1byte(void *bt_context, u32 reg_addr, + u32 bit_mask, u8 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 original_value, bit_shift = 0; + u8 i; + + if (bit_mask != MASKDWORD) {/*if not "double word" write*/ + original_value = rtl_read_byte(rtlpriv, reg_addr); + for (i = 0; i <= 7; i++) { + if ((bit_mask>>i) & 0x1) + break; + } + bit_shift = i; + data = (original_value & (~bit_mask)) | + ((data << bit_shift) & bit_mask); + } + rtl_write_byte(rtlpriv, reg_addr, data); +} + +static void halbtc_write_2byte(void *bt_context, u32 reg_addr, u16 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtl_write_word(rtlpriv, reg_addr, data); +} + +static void halbtc_write_4byte(void *bt_context, u32 reg_addr, u32 data) +{ + struct btc_coexist *btcoexist = + (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtl_write_dword(rtlpriv, reg_addr, data); +} + +static void halbtc_set_bbreg(void *bt_context, u32 reg_addr, u32 bit_mask, + u32 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtl_set_bbreg(rtlpriv->mac80211.hw, reg_addr, bit_mask, data); +} + +static u32 halbtc_get_bbreg(void *bt_context, u32 reg_addr, u32 bit_mask) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + return rtl_get_bbreg(rtlpriv->mac80211.hw, reg_addr, bit_mask); +} + +static void halbtc_set_rfreg(void *bt_context, u8 rf_path, u32 reg_addr, + u32 bit_mask, u32 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtl_set_rfreg(rtlpriv->mac80211.hw, rf_path, reg_addr, bit_mask, data); +} + +static u32 halbtc_get_rfreg(void *bt_context, u8 rf_path, u32 reg_addr, + u32 bit_mask) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + return rtl_get_rfreg(rtlpriv->mac80211.hw, rf_path, reg_addr, bit_mask); +} + +static void halbtc_fill_h2c_cmd(void *bt_context, u8 element_id, + u32 cmd_len, u8 *cmd_buf) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtlpriv->cfg->ops->fill_h2c_cmd(rtlpriv->mac80211.hw, element_id, + cmd_len, cmd_buf); +} + +static void halbtc_display_dbg_msg(void *bt_context, u8 disp_type) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; + switch (disp_type) { + case BTC_DBG_DISP_COEX_STATISTICS: + halbtc_display_coex_statistics(btcoexist); + break; + case BTC_DBG_DISP_BT_LINK_INFO: + halbtc_display_bt_link_info(btcoexist); + break; + case BTC_DBG_DISP_BT_FW_VER: + halbtc_display_bt_fw_info(btcoexist); + break; + case BTC_DBG_DISP_FW_PWR_MODE_CMD: + halbtc_display_fw_pwr_mode_cmd(btcoexist); + break; + default: + break; + } +} + +/***************************************************************** + * Extern functions called by other module + *****************************************************************/ +bool exhalbtc_initlize_variables(struct rtl_priv *adapter) +{ + struct btc_coexist *btcoexist = &gl_bt_coexist; + + btcoexist->statistics.cnt_bind++; + + halbtc_dbg_init(); + + if (btcoexist->binded) + return false; + else + btcoexist->binded = true; + +#if (defined(CONFIG_PCI_HCI)) + btcoexist->chip_interface = BTC_INTF_PCI; +#elif (defined(CONFIG_USB_HCI)) + btcoexist->chip_interface = BTC_INTF_USB; +#elif (defined(CONFIG_SDIO_HCI)) + btcoexist->chip_interface = BTC_INTF_SDIO; +#elif (defined(CONFIG_GSPI_HCI)) + btcoexist->chip_interface = BTC_INTF_GSPI; +#else + btcoexist->chip_interface = BTC_INTF_UNKNOWN; +#endif + + if (NULL == btcoexist->adapter) + btcoexist->adapter = adapter; + + btcoexist->stack_info.profile_notified = false; + + btcoexist->btc_read_1byte = halbtc_read_1byte; + btcoexist->btc_write_1byte = halbtc_write_1byte; + btcoexist->btc_write_1byte_bitmask = halbtc_bitmask_write_1byte; + btcoexist->btc_read_2byte = halbtc_read_2byte; + btcoexist->btc_write_2byte = halbtc_write_2byte; + btcoexist->btc_read_4byte = halbtc_read_4byte; + btcoexist->btc_write_4byte = halbtc_write_4byte; + + btcoexist->btc_set_bb_reg = halbtc_set_bbreg; + btcoexist->btc_get_bb_reg = halbtc_get_bbreg; + + btcoexist->btc_set_rf_reg = halbtc_set_rfreg; + btcoexist->btc_get_rf_reg = halbtc_get_rfreg; + + btcoexist->btc_fill_h2c = halbtc_fill_h2c_cmd; + btcoexist->btc_disp_dbg_msg = halbtc_display_dbg_msg; + + btcoexist->btc_get = halbtc_get; + btcoexist->btc_set = halbtc_set; + + btcoexist->cli_buf = &btc_dbg_buf[0]; + + btcoexist->bt_info.b_bt_ctrl_buf_size = false; + btcoexist->bt_info.agg_buf_size = 5; + + btcoexist->bt_info.increase_scan_dev_num = false; + return true; +} + +void exhalbtc_init_hw_config(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->statistics.cnt_init_hw_config++; + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) + ex_halbtc8723b2ant_init_hwconfig(btcoexist); +} + +void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->statistics.cnt_init_coex_dm++; + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) + ex_halbtc8723b2ant_init_coex_dm(btcoexist); + + btcoexist->initilized = true; +} + +void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 ips_type; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_ips_notify++; + if (btcoexist->manual_control) + return; + + if (ERFOFF == type) + ips_type = BTC_IPS_ENTER; + else + ips_type = BTC_IPS_LEAVE; + + halbtc_leave_low_power(); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) + ex_halbtc8723b2ant_ips_notify(btcoexist, ips_type); + + halbtc_nomal_low_power(); +} + +void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 lps_type; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_lps_notify++; + if (btcoexist->manual_control) + return; + + if (EACTIVE == type) + lps_type = BTC_LPS_DISABLE; + else + lps_type = BTC_LPS_ENABLE; + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) + ex_halbtc8723b2ant_lps_notify(btcoexist, lps_type); +} + +void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 scan_type; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_scan_notify++; + if (btcoexist->manual_control) + return; + + if (type) + scan_type = BTC_SCAN_START; + else + scan_type = BTC_SCAN_FINISH; + + halbtc_leave_low_power(); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) + ex_halbtc8723b2ant_scan_notify(btcoexist, scan_type); + + halbtc_nomal_low_power(); +} + +void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 asso_type; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_connect_notify++; + if (btcoexist->manual_control) + return; + + if (action) + asso_type = BTC_ASSOCIATE_START; + else + asso_type = BTC_ASSOCIATE_FINISH; + + halbtc_leave_low_power(); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) + ex_halbtc8723b2ant_connect_notify(btcoexist, asso_type); +} + +void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist, + enum _RT_MEDIA_STATUS media_status) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 status; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_media_status_notify++; + if (btcoexist->manual_control) + return; + + if (RT_MEDIA_CONNECT == media_status) + status = BTC_MEDIA_CONNECT; + else + status = BTC_MEDIA_DISCONNECT; + + halbtc_leave_low_power(); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) + btc8723b_med_stat_notify(btcoexist, status); + + halbtc_nomal_low_power(); +} + +void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 packet_type; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_special_packet_notify++; + if (btcoexist->manual_control) + return; + + packet_type = BTC_PACKET_DHCP; + + halbtc_leave_low_power(); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) + ex_halbtc8723b2ant_special_packet_notify(btcoexist, + packet_type); + + halbtc_nomal_low_power(); +} + +void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmp_buf, u8 length) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_bt_info_notify++; + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) + ex_halbtc8723b2ant_bt_info_notify(btcoexist, tmp_buf, length); +} + +void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 stack_op_type; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_stack_operation_notify++; + if (btcoexist->manual_control) + return; + + stack_op_type = BTC_STACK_OP_NONE; + + halbtc_leave_low_power(); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) + ex_halbtc8723b2ant_stack_operation_notify(btcoexist, + stack_op_type); + + halbtc_nomal_low_power(); +} + +void exhalbtc_halt_notify(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) + ex_halbtc8723b2ant_halt_notify(btcoexist); +} + +void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; +} + +void exhalbtc_periodical(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_periodical++; + + halbtc_leave_low_power(); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) + ex_halbtc8723b2ant_periodical(btcoexist); + + halbtc_nomal_low_power(); +} + +void exhalbtc_dbg_control(struct btc_coexist *btcoexist, + u8 code, u8 len, u8 *data) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_dbg_ctrl++; +} + +void exhalbtc_stack_update_profile_info(void) +{ +} + +void exhalbtc_update_min_bt_rssi(char bt_rssi) +{ + struct btc_coexist *btcoexist = &gl_bt_coexist; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->stack_info.min_bt_rssi = bt_rssi; +} + +void exhalbtc_set_hci_version(u16 hci_version) +{ + struct btc_coexist *btcoexist = &gl_bt_coexist; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->stack_info.hci_version = hci_version; +} + +void exhalbtc_set_bt_patch_version(u16 bt_hci_version, u16 bt_patch_version) +{ + struct btc_coexist *btcoexist = &gl_bt_coexist; + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->bt_info.bt_real_fw_ver = bt_patch_version; + btcoexist->bt_info.bt_hci_ver = bt_hci_version; +} + +void exhalbtc_set_bt_exist(bool bt_exist) +{ + gl_bt_coexist.board_info.bt_exist = bt_exist; +} + +void exhalbtc_set_chip_type(u8 chip_type) +{ + switch (chip_type) { + default: + case BT_2WIRE: + case BT_ISSC_3WIRE: + case BT_ACCEL: + case BT_RTL8756: + gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_UNDEF; + break; + case BT_CSR_BC4: + gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_CSR_BC4; + break; + case BT_CSR_BC8: + gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_CSR_BC8; + break; + case BT_RTL8723A: + gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_RTL8723A; + break; + case BT_RTL8821: + gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_RTL8821; + break; + case BT_RTL8723B: + gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_RTL8723B; + break; + } +} + +void exhalbtc_set_ant_num(u8 type, u8 ant_num) +{ + if (BT_COEX_ANT_TYPE_PG == type) { + gl_bt_coexist.board_info.pg_ant_num = ant_num; + gl_bt_coexist.board_info.btdm_ant_num = ant_num; + } else if (BT_COEX_ANT_TYPE_ANTDIV == type) { + gl_bt_coexist.board_info.btdm_ant_num = ant_num; + } +} + +void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) + ex_halbtc8723b2ant_display_coex_info(btcoexist); +} diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h new file mode 100644 index 000000000000..871fc3c6d559 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h @@ -0,0 +1,559 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2012 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#ifndef __HALBTC_OUT_SRC_H__ +#define __HALBTC_OUT_SRC_H__ + +#include "../wifi.h" + +#define NORMAL_EXEC false +#define FORCE_EXEC true + +#define BTC_RF_A RF90_PATH_A +#define BTC_RF_B RF90_PATH_B +#define BTC_RF_C RF90_PATH_C +#define BTC_RF_D RF90_PATH_D + +#define BTC_SMSP SINGLEMAC_SINGLEPHY +#define BTC_DMDP DUALMAC_DUALPHY +#define BTC_DMSP DUALMAC_SINGLEPHY +#define BTC_MP_UNKNOWN 0xff + +#define IN +#define OUT + +#define BT_TMP_BUF_SIZE 100 + +#define BT_COEX_ANT_TYPE_PG 0 +#define BT_COEX_ANT_TYPE_ANTDIV 1 +#define BT_COEX_ANT_TYPE_DETECTED 2 + +#define BTC_MIMO_PS_STATIC 0 +#define BTC_MIMO_PS_DYNAMIC 1 + +#define BTC_RATE_DISABLE 0 +#define BTC_RATE_ENABLE 1 + +#define BTC_ANT_PATH_WIFI 0 +#define BTC_ANT_PATH_BT 1 +#define BTC_ANT_PATH_PTA 2 + +enum btc_chip_interface { + BTC_INTF_UNKNOWN = 0, + BTC_INTF_PCI = 1, + BTC_INTF_USB = 2, + BTC_INTF_SDIO = 3, + BTC_INTF_GSPI = 4, + BTC_INTF_MAX +}; + +enum BTC_CHIP_TYPE { + BTC_CHIP_UNDEF = 0, + BTC_CHIP_CSR_BC4 = 1, + BTC_CHIP_CSR_BC8 = 2, + BTC_CHIP_RTL8723A = 3, + BTC_CHIP_RTL8821 = 4, + BTC_CHIP_RTL8723B = 5, + BTC_CHIP_MAX +}; + +enum BTC_MSG_TYPE { + BTC_MSG_INTERFACE = 0x0, + BTC_MSG_ALGORITHM = 0x1, + BTC_MSG_MAX +}; +extern u32 btc_dbg_type[]; + +/* following is for BTC_MSG_INTERFACE */ +#define INTF_INIT BIT0 +#define INTF_NOTIFY BIT2 + +/* following is for BTC_ALGORITHM */ +#define ALGO_BT_RSSI_STATE BIT0 +#define ALGO_WIFI_RSSI_STATE BIT1 +#define ALGO_BT_MONITOR BIT2 +#define ALGO_TRACE BIT3 +#define ALGO_TRACE_FW BIT4 +#define ALGO_TRACE_FW_DETAIL BIT5 +#define ALGO_TRACE_FW_EXEC BIT6 +#define ALGO_TRACE_SW BIT7 +#define ALGO_TRACE_SW_DETAIL BIT8 +#define ALGO_TRACE_SW_EXEC BIT9 + +#define BT_COEX_ANT_TYPE_PG 0 +#define BT_COEX_ANT_TYPE_ANTDIV 1 +#define BT_COEX_ANT_TYPE_DETECTED 2 +#define BTC_MIMO_PS_STATIC 0 +#define BTC_MIMO_PS_DYNAMIC 1 +#define BTC_RATE_DISABLE 0 +#define BTC_RATE_ENABLE 1 +#define BTC_ANT_PATH_WIFI 0 +#define BTC_ANT_PATH_BT 1 +#define BTC_ANT_PATH_PTA 2 + + +#define CL_SPRINTF snprintf +#define CL_PRINTF printk + +#define BTC_PRINT(dbgtype, dbgflag, printstr, ...) \ + do { \ + if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) {\ + printk(printstr, ##__VA_ARGS__); \ + } \ + } while (0) + +#define BTC_PRINT_F(dbgtype, dbgflag, printstr, ...) \ + do { \ + if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) {\ + pr_info("%s: ", __func__); \ + printk(printstr, ##__VA_ARGS__); \ + } \ + } while (0) + +#define BTC_PRINT_ADDR(dbgtype, dbgflag, printstr, _ptr) \ + do { \ + if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) { \ + int __i; \ + u8 *__ptr = (u8 *)_ptr; \ + printk printstr; \ + for (__i = 0; __i < 6; __i++) \ + printk("%02X%s", __ptr[__i], (__i == 5) ? \ + "" : "-"); \ + pr_info("\n"); \ + } \ + } while (0) + +#define BTC_PRINT_DATA(dbgtype, dbgflag, _titlestring, _hexdata, _hexdatalen) \ + do { \ + if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) { \ + int __i; \ + u8 *__ptr = (u8 *)_hexdata; \ + printk(_titlestring); \ + for (__i = 0; __i < (int)_hexdatalen; __i++) { \ + printk("%02X%s", __ptr[__i], (((__i + 1) % 4) \ + == 0) ? " " : " ");\ + if (((__i + 1) % 16) == 0) \ + printk("\n"); \ + } \ + pr_debug("\n"); \ + } \ + } while (0) + +#define BTC_ANT_PATH_WIFI 0 +#define BTC_ANT_PATH_BT 1 +#define BTC_ANT_PATH_PTA 2 + +enum btc_power_save_type { + BTC_PS_WIFI_NATIVE = 0, + BTC_PS_LPS_ON = 1, + BTC_PS_LPS_OFF = 2, + BTC_PS_LPS_MAX +}; + +struct btc_board_info { + /* The following is some board information */ + u8 bt_chip_type; + u8 pg_ant_num; /* pg ant number */ + u8 btdm_ant_num; /* ant number for btdm */ + u8 btdm_ant_pos; + bool bt_exist; +}; + +enum btc_dbg_opcode { + BTC_DBG_SET_COEX_NORMAL = 0x0, + BTC_DBG_SET_COEX_WIFI_ONLY = 0x1, + BTC_DBG_SET_COEX_BT_ONLY = 0x2, + BTC_DBG_MAX +}; + +enum btc_rssi_state { + BTC_RSSI_STATE_HIGH = 0x0, + BTC_RSSI_STATE_MEDIUM = 0x1, + BTC_RSSI_STATE_LOW = 0x2, + BTC_RSSI_STATE_STAY_HIGH = 0x3, + BTC_RSSI_STATE_STAY_MEDIUM = 0x4, + BTC_RSSI_STATE_STAY_LOW = 0x5, + BTC_RSSI_MAX +}; + +enum btc_wifi_role { + BTC_ROLE_STATION = 0x0, + BTC_ROLE_AP = 0x1, + BTC_ROLE_IBSS = 0x2, + BTC_ROLE_HS_MODE = 0x3, + BTC_ROLE_MAX +}; + +enum btc_wifi_bw_mode { + BTC_WIFI_BW_LEGACY = 0x0, + BTC_WIFI_BW_HT20 = 0x1, + BTC_WIFI_BW_HT40 = 0x2, + BTC_WIFI_BW_MAX +}; + +enum btc_wifi_traffic_dir { + BTC_WIFI_TRAFFIC_TX = 0x0, + BTC_WIFI_TRAFFIC_RX = 0x1, + BTC_WIFI_TRAFFIC_MAX +}; + +enum btc_wifi_pnp { + BTC_WIFI_PNP_WAKE_UP = 0x0, + BTC_WIFI_PNP_SLEEP = 0x1, + BTC_WIFI_PNP_MAX +}; + + +enum btc_get_type { + /* type bool */ + BTC_GET_BL_HS_OPERATION, + BTC_GET_BL_HS_CONNECTING, + BTC_GET_BL_WIFI_CONNECTED, + BTC_GET_BL_WIFI_BUSY, + BTC_GET_BL_WIFI_SCAN, + BTC_GET_BL_WIFI_LINK, + BTC_GET_BL_WIFI_DHCP, + BTC_GET_BL_WIFI_SOFTAP_IDLE, + BTC_GET_BL_WIFI_SOFTAP_LINKING, + BTC_GET_BL_WIFI_IN_EARLY_SUSPEND, + BTC_GET_BL_WIFI_ROAM, + BTC_GET_BL_WIFI_4_WAY_PROGRESS, + BTC_GET_BL_WIFI_UNDER_5G, + BTC_GET_BL_WIFI_AP_MODE_ENABLE, + BTC_GET_BL_WIFI_ENABLE_ENCRYPTION, + BTC_GET_BL_WIFI_UNDER_B_MODE, + BTC_GET_BL_EXT_SWITCH, + + /* type s4Byte */ + BTC_GET_S4_WIFI_RSSI, + BTC_GET_S4_HS_RSSI, + + /* type u32 */ + BTC_GET_U4_WIFI_BW, + BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, + BTC_GET_U4_WIFI_FW_VER, + BTC_GET_U4_BT_PATCH_VER, + + /* type u1Byte */ + BTC_GET_U1_WIFI_DOT11_CHNL, + BTC_GET_U1_WIFI_CENTRAL_CHNL, + BTC_GET_U1_WIFI_HS_CHNL, + BTC_GET_U1_MAC_PHY_MODE, + + /* for 1Ant */ + BTC_GET_U1_LPS_MODE, + BTC_GET_BL_BT_SCO_BUSY, + + /* for test mode */ + BTC_GET_DRIVER_TEST_CFG, + BTC_GET_MAX +}; + + +enum btc_set_type { + /* type bool */ + BTC_SET_BL_BT_DISABLE, + BTC_SET_BL_BT_TRAFFIC_BUSY, + BTC_SET_BL_BT_LIMITED_DIG, + BTC_SET_BL_FORCE_TO_ROAM, + BTC_SET_BL_TO_REJ_AP_AGG_PKT, + BTC_SET_BL_BT_CTRL_AGG_SIZE, + BTC_SET_BL_INC_SCAN_DEV_NUM, + + /* type u1Byte */ + BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, + BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, + BTC_SET_UI_SCAN_SIG_COMPENSATION, + BTC_SET_U1_AGG_BUF_SIZE, + + /* type trigger some action */ + BTC_SET_ACT_GET_BT_RSSI, + BTC_SET_ACT_AGGREGATE_CTRL, + + /********* for 1Ant **********/ + /* type bool */ + BTC_SET_BL_BT_SCO_BUSY, + /* type u1Byte */ + BTC_SET_U1_1ANT_LPS, + BTC_SET_U1_1ANT_RPWM, + /* type trigger some action */ + BTC_SET_ACT_LEAVE_LPS, + BTC_SET_ACT_ENTER_LPS, + BTC_SET_ACT_NORMAL_LPS, + BTC_SET_ACT_INC_FORCE_EXEC_PWR_CMD_CNT, + BTC_SET_ACT_DISABLE_LOW_POWER, + BTC_SET_ACT_UPDATE_ra_mask, + BTC_SET_ACT_SEND_MIMO_PS, + /* BT Coex related */ + BTC_SET_ACT_CTRL_BT_INFO, + BTC_SET_ACT_CTRL_BT_COEX, + /***************************/ + BTC_SET_MAX +}; + +enum btc_dbg_disp_type { + BTC_DBG_DISP_COEX_STATISTICS = 0x0, + BTC_DBG_DISP_BT_LINK_INFO = 0x1, + BTC_DBG_DISP_BT_FW_VER = 0x2, + BTC_DBG_DISP_FW_PWR_MODE_CMD = 0x3, + BTC_DBG_DISP_MAX +}; + +enum btc_notify_type_ips { + BTC_IPS_LEAVE = 0x0, + BTC_IPS_ENTER = 0x1, + BTC_IPS_MAX +}; + +enum btc_notify_type_lps { + BTC_LPS_DISABLE = 0x0, + BTC_LPS_ENABLE = 0x1, + BTC_LPS_MAX +}; + +enum btc_notify_type_scan { + BTC_SCAN_FINISH = 0x0, + BTC_SCAN_START = 0x1, + BTC_SCAN_MAX +}; + +enum btc_notify_type_associate { + BTC_ASSOCIATE_FINISH = 0x0, + BTC_ASSOCIATE_START = 0x1, + BTC_ASSOCIATE_MAX +}; + +enum btc_notify_type_media_status { + BTC_MEDIA_DISCONNECT = 0x0, + BTC_MEDIA_CONNECT = 0x1, + BTC_MEDIA_MAX +}; + +enum btc_notify_type_special_packet { + BTC_PACKET_UNKNOWN = 0x0, + BTC_PACKET_DHCP = 0x1, + BTC_PACKET_ARP = 0x2, + BTC_PACKET_EAPOL = 0x3, + BTC_PACKET_MAX +}; + +enum btc_notify_type_stack_operation { + BTC_STACK_OP_NONE = 0x0, + BTC_STACK_OP_INQ_PAGE_PAIR_START = 0x1, + BTC_STACK_OP_INQ_PAGE_PAIR_FINISH = 0x2, + BTC_STACK_OP_MAX +}; + + +typedef u8 (*bfp_btc_r1)(void *btc_context, u32 reg_addr); + +typedef u16 (*bfp_btc_r2)(void *btc_context, u32 reg_addr); + +typedef u32 (*bfp_btc_r4)(void *btc_context, u32 reg_addr); + +typedef void (*bfp_btc_w1)(void *btc_context, u32 reg_addr, u8 data); + +typedef void (*bfp_btc_w1_bit_mak)(void *btc_context, u32 reg_addr, + u32 bit_mask, u8 data1b); + +typedef void (*bfp_btc_w2)(void *btc_context, u32 reg_addr, u16 data); + +typedef void (*bfp_btc_w4)(void *btc_context, u32 reg_addr, u32 data); + +typedef void (*bfp_btc_wr_1byte_bit_mask)(void *btc_context, u32 reg_addr, + u8 bit_mask, u8 data); + +typedef void (*bfp_btc_set_bb_reg)(void *btc_context, u32 reg_addr, + u32 bit_mask, u32 data); + +typedef u32 (*bfp_btc_get_bb_reg)(void *btc_context, u32 reg_addr, + u32 bit_mask); + +typedef void (*bfp_btc_set_rf_reg)(void *btc_context, u8 rf_path, u32 reg_addr, + u32 bit_mask, u32 data); + +typedef u32 (*bfp_btc_get_rf_reg)(void *btc_context, u8 rf_path, + u32 reg_addr, u32 bit_mask); + +typedef void (*bfp_btc_fill_h2c)(void *btc_context, u8 element_id, + u32 cmd_len, u8 *cmd_buffer); + +typedef bool (*bfp_btc_get)(void *btcoexist, u8 get_type, void *out_buf); + +typedef bool (*bfp_btc_set)(void *btcoexist, u8 set_type, void *in_buf); + +typedef void (*bfp_btc_disp_dbg_msg)(void *btcoexist, u8 disp_type); + +struct btc_bt_info { + bool bt_disabled; + u8 rssi_adjust_for_agc_table_on; + u8 rssi_adjust_for_1ant_coex_type; + bool bt_busy; + u8 agg_buf_size; + bool limited_dig; + bool reject_agg_pkt; + bool b_bt_ctrl_buf_size; + bool increase_scan_dev_num; + u16 bt_hci_ver; + u16 bt_real_fw_ver; + u8 bt_fw_ver; + + /* the following is for 1Ant solution */ + bool bt_ctrl_lps; + bool bt_pwr_save_mode; + bool bt_lps_on; + bool force_to_roam; + u8 force_exec_pwr_cmd_cnt; + u8 lps_1ant; + u8 rpwm_1ant; + u32 ra_mask; +}; + +struct btc_stack_info { + bool profile_notified; + u16 hci_version; /* stack hci version */ + u8 num_of_link; + bool bt_link_exist; + bool sco_exist; + bool acl_exist; + bool a2dp_exist; + bool hid_exist; + u8 num_of_hid; + bool pan_exist; + bool unknown_acl_exist; + char min_bt_rssi; +}; + +struct btc_statistics { + u32 cnt_bind; + u32 cnt_init_hw_config; + u32 cnt_init_coex_dm; + u32 cnt_ips_notify; + u32 cnt_lps_notify; + u32 cnt_scan_notify; + u32 cnt_connect_notify; + u32 cnt_media_status_notify; + u32 cnt_special_packet_notify; + u32 cnt_bt_info_notify; + u32 cnt_periodical; + u32 cnt_stack_operation_notify; + u32 cnt_dbg_ctrl; +}; + +struct btc_bt_link_info { + bool bt_link_exist; + bool sco_exist; + bool sco_only; + bool a2dp_exist; + bool a2dp_only; + bool hid_exist; + bool hid_only; + bool pan_exist; + bool pan_only; +}; + +enum btc_antenna_pos { + BTC_ANTENNA_AT_MAIN_PORT = 0x1, + BTC_ANTENNA_AT_AUX_PORT = 0x2, +}; + +struct btc_coexist { + /* make sure only one adapter can bind the data context */ + bool binded; + /* default adapter */ + void *adapter; + struct btc_board_info board_info; + /* some bt info referenced by non-bt module */ + struct btc_bt_info bt_info; + struct btc_stack_info stack_info; + enum btc_chip_interface chip_interface; + struct btc_bt_link_info bt_link_info; + + bool initilized; + bool stop_coex_dm; + bool manual_control; + u8 *cli_buf; + struct btc_statistics statistics; + u8 pwr_mode_val[10]; + + /* function pointers - io related */ + bfp_btc_r1 btc_read_1byte; + bfp_btc_w1 btc_write_1byte; + bfp_btc_w1_bit_mak btc_write_1byte_bitmask; + bfp_btc_r2 btc_read_2byte; + bfp_btc_w2 btc_write_2byte; + bfp_btc_r4 btc_read_4byte; + bfp_btc_w4 btc_write_4byte; + + bfp_btc_set_bb_reg btc_set_bb_reg; + bfp_btc_get_bb_reg btc_get_bb_reg; + + + bfp_btc_set_rf_reg btc_set_rf_reg; + bfp_btc_get_rf_reg btc_get_rf_reg; + + bfp_btc_fill_h2c btc_fill_h2c; + + bfp_btc_disp_dbg_msg btc_disp_dbg_msg; + + bfp_btc_get btc_get; + bfp_btc_set btc_set; +}; + +bool halbtc_is_wifi_uplink(struct rtl_priv *adapter); + +extern struct btc_coexist gl_bt_coexist; + +bool exhalbtc_initlize_variables(struct rtl_priv *adapter); +void exhalbtc_init_hw_config(struct btc_coexist *btcoexist); +void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist); +void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type); +void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type); +void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type); +void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action); +void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist, + enum _RT_MEDIA_STATUS media_status); +void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type); +void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf, + u8 length); +void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type); +void exhalbtc_halt_notify(struct btc_coexist *btcoexist); +void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state); +void exhalbtc_periodical(struct btc_coexist *btcoexist); +void exhalbtc_dbg_control(struct btc_coexist *btcoexist, u8 code, u8 len, + u8 *data); +void exhalbtc_stack_update_profile_info(void); +void exhalbtc_set_hci_version(u16 hci_version); +void exhalbtc_set_bt_patch_version(u16 bt_hci_version, u16 bt_patch_version); +void exhalbtc_update_min_bt_rssi(char bt_rssi); +void exhalbtc_set_bt_exist(bool bt_exist); +void exhalbtc_set_chip_type(u8 chip_type); +void exhalbtc_set_ant_num(u8 type, u8 ant_num); +void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist); +void exhalbtc_signal_compensation(struct btc_coexist *btcoexist, + u8 *rssi_wifi, u8 *rssi_bt); +void exhalbtc_lps_leave(struct btc_coexist *btcoexist); +void exhalbtc_low_wifi_traffic_notify(struct btc_coexist *btcoexist); + +#endif diff --git a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c new file mode 100644 index 000000000000..0ab94fe4cbbe --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c @@ -0,0 +1,218 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2013 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "rtl_btc.h" +#include "halbt_precomp.h" + +#include +#include + +static struct rtl_btc_ops rtl_btc_operation = { + .btc_init_variables = rtl_btc_init_variables, + .btc_init_hal_vars = rtl_btc_init_hal_vars, + .btc_init_hw_config = rtl_btc_init_hw_config, + .btc_ips_notify = rtl_btc_ips_notify, + .btc_scan_notify = rtl_btc_scan_notify, + .btc_connect_notify = rtl_btc_connect_notify, + .btc_mediastatus_notify = rtl_btc_mediastatus_notify, + .btc_periodical = rtl_btc_periodical, + .btc_halt_notify = rtl_btc_halt_notify, + .btc_btinfo_notify = rtl_btc_btinfo_notify, + .btc_is_limited_dig = rtl_btc_is_limited_dig, + .btc_is_disable_edca_turbo = rtl_btc_is_disable_edca_turbo, + .btc_is_bt_disabled = rtl_btc_is_bt_disabled, +}; + +void rtl_btc_init_variables(struct rtl_priv *rtlpriv) +{ + exhalbtc_initlize_variables(rtlpriv); +} + +void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv) +{ + u8 ant_num; + u8 bt_exist; + u8 bt_type; + + ant_num = rtl_get_hwpg_ant_num(rtlpriv); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "%s, antNum is %d\n", __func__, ant_num); + + bt_exist = rtl_get_hwpg_bt_exist(rtlpriv); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "%s, bt_exist is %d\n", __func__, bt_exist); + exhalbtc_set_bt_exist(bt_exist); + + bt_type = rtl_get_hwpg_bt_type(rtlpriv); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "%s, bt_type is %d\n", + __func__, bt_type); + exhalbtc_set_chip_type(bt_type); + + exhalbtc_set_ant_num(BT_COEX_ANT_TYPE_PG, ant_num); +} + +void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv) +{ + exhalbtc_init_hw_config(&gl_bt_coexist); + exhalbtc_init_coex_dm(&gl_bt_coexist); +} + +void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type) +{ + exhalbtc_ips_notify(&gl_bt_coexist, type); +} + +void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype) +{ + exhalbtc_scan_notify(&gl_bt_coexist, scantype); +} + +void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action) +{ + exhalbtc_connect_notify(&gl_bt_coexist, action); +} + +void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv, + enum _RT_MEDIA_STATUS mstatus) +{ + exhalbtc_mediastatus_notify(&gl_bt_coexist, mstatus); +} + +void rtl_btc_periodical(struct rtl_priv *rtlpriv) +{ + exhalbtc_periodical(&gl_bt_coexist); +} + +void rtl_btc_halt_notify(void) +{ + exhalbtc_halt_notify(&gl_bt_coexist); +} + +void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length) +{ + exhalbtc_bt_info_notify(&gl_bt_coexist, tmp_buf, length); +} + +bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv) +{ + return gl_bt_coexist.bt_info.limited_dig; +} + +bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv) +{ + bool bt_change_edca = false; + u32 cur_edca_val; + u32 edca_bt_hs_uplink = 0x5ea42b, edca_bt_hs_downlink = 0x5ea42b; + u32 edca_hs; + u32 edca_addr = 0x504; + + cur_edca_val = rtl_read_dword(rtlpriv, edca_addr); + if (halbtc_is_wifi_uplink(rtlpriv)) { + if (cur_edca_val != edca_bt_hs_uplink) { + edca_hs = edca_bt_hs_uplink; + bt_change_edca = true; + } + } else { + if (cur_edca_val != edca_bt_hs_downlink) { + edca_hs = edca_bt_hs_downlink; + bt_change_edca = true; + } + } + + if (bt_change_edca) + rtl_write_dword(rtlpriv, edca_addr, edca_hs); + + return true; +} + +bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv) +{ + if (gl_bt_coexist.bt_info.bt_disabled) + return true; + else + return false; +} + +struct rtl_btc_ops *rtl_btc_get_ops_pointer(void) +{ + return &rtl_btc_operation; +} +EXPORT_SYMBOL(rtl_btc_get_ops_pointer); + +u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv) +{ + u8 num; + + if (rtlpriv->btcoexist.btc_info.ant_num == ANT_X2) + num = 2; + else + num = 1; + + return num; +} + +enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + enum _RT_MEDIA_STATUS m_status = RT_MEDIA_DISCONNECT; + + u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0; + + if (bibss || rtlpriv->mac80211.link_state >= MAC80211_LINKED) + m_status = RT_MEDIA_CONNECT; + + return m_status; +} + +u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv) +{ + return rtlpriv->btcoexist.btc_info.btcoexist; +} + +u8 rtl_get_hwpg_bt_type(struct rtl_priv *rtlpriv) +{ + return rtlpriv->btcoexist.btc_info.bt_type; +} + +MODULE_AUTHOR("Page He "); +MODULE_AUTHOR("Realtek WlanFAE "); +MODULE_AUTHOR("Larry Finger "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core"); + +static int __init rtl_btcoexist_module_init(void) +{ + return 0; +} + +static void __exit rtl_btcoexist_module_exit(void) +{ + return; +} + +module_init(rtl_btcoexist_module_init); +module_exit(rtl_btcoexist_module_exit); diff --git a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h new file mode 100644 index 000000000000..805b22cc8fc8 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h @@ -0,0 +1,52 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL_BTC_H__ +#define __RTL_BTC_H__ + +#include "halbt_precomp.h" + +void rtl_btc_init_variables(struct rtl_priv *rtlpriv); +void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv); +void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv); +void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type); +void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype); +void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action); +void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv, + enum _RT_MEDIA_STATUS mstatus); +void rtl_btc_periodical(struct rtl_priv *rtlpriv); +void rtl_btc_halt_notify(void); +void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmpbuf, u8 length); +bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv); +bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv); +bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv); + +struct rtl_btc_ops *rtl_btc_get_ops_pointer(void); + +u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv); +u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv); +u8 rtl_get_hwpg_bt_type(struct rtl_priv *rtlpriv); +enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c new file mode 100644 index 000000000000..83ca4e25ee50 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c @@ -0,0 +1,849 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "fw_common.h" +#include + +#define BEACON_PG 0 /* ->1 */ +#define PSPOLL_PG 2 +#define NULL_PG 3 +#define PROBERSP_PG 4 /* ->5 */ + +#define TOTAL_RESERVED_PKT_LEN 768 + +static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = { + /* page 0 beacon */ + 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78, + 0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x10, 0x04, 0x00, 0x05, 0x54, 0x65, + 0x73, 0x74, 0x32, 0x01, 0x08, 0x82, 0x84, 0x0B, + 0x16, 0x24, 0x30, 0x48, 0x6C, 0x03, 0x01, 0x06, + 0x06, 0x02, 0x00, 0x00, 0x2A, 0x01, 0x02, 0x32, + 0x04, 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, + 0x09, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3D, 0x00, 0xDD, 0x07, 0x00, 0xE0, 0x4C, + 0x02, 0x02, 0x00, 0x00, 0xDD, 0x18, 0x00, 0x50, + 0xF2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, + 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, 0x01, 0x00, + + /* page 1 beacon */ + 0x00, 0x50, 0xF2, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 2 ps-poll */ + 0xA4, 0x10, 0x01, 0xC0, 0xEC, 0x1A, 0x59, 0x0B, + 0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 3 null */ + 0x48, 0x01, 0x00, 0x00, 0xEC, 0x1A, 0x59, 0x0B, + 0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78, + 0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x72, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 4 probe_resp */ + 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, + 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, + 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, + 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00, + 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69, + 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C, + 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96, + 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A, + 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C, + 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02, + 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 5 probe_resp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +void rtl8723_enable_fw_download(struct ieee80211_hw *hw, bool enable) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp; + + if (enable) { + tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04); + + tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); + rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01); + + tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2); + rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7); + } else { + tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); + rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe); + + rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00); + } +} +EXPORT_SYMBOL_GPL(rtl8723_enable_fw_download); + +void rtl8723_fw_block_write(struct ieee80211_hw *hw, + const u8 *buffer, u32 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 blocksize = sizeof(u32); + u8 *bufferptr = (u8 *)buffer; + u32 *pu4byteptr = (u32 *)buffer; + u32 i, offset, blockcount, remainsize; + + blockcount = size / blocksize; + remainsize = size % blocksize; + + for (i = 0; i < blockcount; i++) { + offset = i * blocksize; + rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset), + *(pu4byteptr + i)); + } + if (remainsize) { + offset = blockcount * blocksize; + bufferptr += offset; + for (i = 0; i < remainsize; i++) { + rtl_write_byte(rtlpriv, + (FW_8192C_START_ADDRESS + offset + i), + *(bufferptr + i)); + } + } +} +EXPORT_SYMBOL_GPL(rtl8723_fw_block_write); + +void rtl8723_fw_page_write(struct ieee80211_hw *hw, + u32 page, const u8 *buffer, u32 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 value8; + u8 u8page = (u8) (page & 0x07); + + value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page; + + rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8); + rtl8723_fw_block_write(hw, buffer, size); +} +EXPORT_SYMBOL_GPL(rtl8723_fw_page_write); + +static void rtl8723_fill_dummy(u8 *pfwbuf, u32 *pfwlen) +{ + u32 fwlen = *pfwlen; + u8 remain = (u8) (fwlen % 4); + + remain = (remain == 0) ? 0 : (4 - remain); + + while (remain > 0) { + pfwbuf[fwlen] = 0; + fwlen++; + remain--; + } + *pfwlen = fwlen; +} + +void rtl8723_write_fw(struct ieee80211_hw *hw, + enum version_8723be version, + u8 *buffer, u32 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 *bufferptr = (u8 *)buffer; + u32 pagenums, remainsize; + u32 page, offset; + + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "FW size is %d bytes,\n", size); + + _rtl8723be_fill_dummy(bufferptr, &size); + + pagenums = size / FW_8192C_PAGE_SIZE; + remainsize = size % FW_8192C_PAGE_SIZE; + + if (pagenums > 8) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Page numbers should not greater then 8\n"); + } + for (page = 0; page < pagenums; page++) { + offset = page * FW_8192C_PAGE_SIZE; + rtl8723_fw_page_write(hw, page, (bufferptr + offset), + FW_8192C_PAGE_SIZE); + } + if (remainsize) { + offset = pagenums * FW_8192C_PAGE_SIZE; + page = pagenums; + rtl8723_fw_page_write(hw, page, (bufferptr + offset), + remainsize); + } +} +EXPORT_SYMBOL_GPL(rtl8723_write_fw); + +void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw) +{ + u8 u1tmp; + u8 delay = 100; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20); + u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + + while (u1tmp & BIT(2)) { + delay--; + if (delay == 0) + break; + udelay(50); + u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + } + if (delay == 0) { + u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, u1tmp&(~BIT(2))); + } +} +EXPORT_SYMBOL_GPL(rtl8723ae_firmware_selfreset); + +void rtl8723be_firmware_selfreset(struct ieee80211_hw *hw) +{ + u8 u1b_tmp; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1); + rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0)))); + + u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2)))); + udelay(50); + + u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1); + rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp | BIT(0))); + + u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp | BIT(2))); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + " _8051Reset8723be(): 8051 reset success .\n"); +} +EXPORT_SYMBOL_GPL(rtl8723be_firmware_selfreset); + +int rtl8723_fw_free_to_go(struct ieee80211_hw *hw, bool is_8723be) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int err = -EIO; + u32 counter = 0; + u32 value32; + + do { + value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); + } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) && + (!(value32 & FWDL_CHKSUM_RPT))); + + if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "chksum report faill ! REG_MCUFWDL:0x%08x .\n", + value32); + goto exit; + } + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32); + + value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); + value32 |= MCUFWDL_RDY; + value32 &= ~WINTINI_RDY; + rtl_write_dword(rtlpriv, REG_MCUFWDL, value32); + + if (is_8723be) + rtl8723be_firmware_selfreset(hw); + counter = 0; + + do { + value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); + if (value32 & WINTINI_RDY) { + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + "Polling FW ready success!! " + "REG_MCUFWDL:0x%08x .\n", + value32); + err = 0; + goto exit; + } + udelay(FW_8192C_POLLING_DELAY); + + } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT); + + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", + value32); + +exit: + return err; +} +EXPORT_SYMBOL_GPL(rtl8723_fw_free_to_go); + +int rtl8723_download_fw(struct ieee80211_hw *hw, + bool is_8723be) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl92c_firmware_header *pfwheader; + u8 *pfwdata; + u32 fwsize; + int err; + enum version_8723e version = rtlhal->version; + + if (!rtlhal->pfirmware) + return 1; + + pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware; + pfwdata = (u8 *)rtlhal->pfirmware; + fwsize = rtlhal->fwsize; + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, + "normal Firmware SIZE %d\n", fwsize); + + if (IS_FW_HEADER_EXIST(pfwheader)) { + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, + "Firmware Version(%d), Signature(%#x), Size(%d)\n", + pfwheader->version, pfwheader->signature, + (int)sizeof(struct rtl92c_firmware_header)); + + pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header); + fwsize = fwsize - sizeof(struct rtl92c_firmware_header); + } + if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) { + rtl_write_byte(rtlpriv, REG_MCUFWDL, 0); + if (is_8723be) + rtl8723be_firmware_selfreset(hw); + else + rtl8723ae_firmware_selfreset(hw); + } + rtl8723_enable_fw_download(hw, is_8723be); + rtl8723_write_fw(hw, version, pfwdata, fwsize); + rtl8723_enable_fw_download(hw, is_8723be); + + err = rtl8723_fw_free_to_go(hw, is_8723be); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Firmware is not ready to run!\n"); + } else { + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, + "Firmware is ready to run!\n"); + } + return 0; +} +EXPORT_SYMBOL_GPL(rtl8723_download_fw); + +bool rtl8723_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 val_hmetfr, val_mcutst_1; + bool result = false; + + val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR); + val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum)); + + if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0) + result = true; + return result; +} +EXPORT_SYMBOL_GPL(rtl8723_check_fw_read_last_h2c); + +void rtl8723_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id, + u32 cmd_len, u8 *p_cmdbuffer) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 boxnum; + u16 box_reg = 0, box_extreg = 0; + u8 u1b_tmp; + bool isfw_read = false; + u8 buf_index = 0; + bool bwrite_sucess = false; + u8 wait_h2c_limit = 100; + u8 wait_writeh2c_limit = 100; + u8 boxcontent[4], boxextcontent[4]; + u32 h2c_waitcounter = 0; + unsigned long flag; + u8 idx; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n"); + + while (true) { + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); + if (rtlhal->h2c_setinprogress) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "H2C set in progress! Wait to set.." + "element_id(%d).\n", element_id); + + while (rtlhal->h2c_setinprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, + flag); + h2c_waitcounter++; + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Wait 100 us (%d times)...\n", + h2c_waitcounter); + udelay(100); + + if (h2c_waitcounter > 1000) + return; + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, + flag); + } + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + } else { + rtlhal->h2c_setinprogress = true; + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + break; + } + } + while (!bwrite_sucess) { + wait_writeh2c_limit--; + if (wait_writeh2c_limit == 0) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Write H2C fail because no trigger " + "for FW INT!\n"); + break; + } + boxnum = rtlhal->last_hmeboxnum; + switch (boxnum) { + case 0: + box_reg = REG_HMEBOX_0; + box_extreg = REG_HMEBOX_EXT_0; + break; + case 1: + box_reg = REG_HMEBOX_1; + box_extreg = REG_HMEBOX_EXT_1; + break; + case 2: + box_reg = REG_HMEBOX_2; + box_extreg = REG_HMEBOX_EXT_2; + break; + case 3: + box_reg = REG_HMEBOX_3; + box_extreg = REG_HMEBOX_EXT_3; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + isfw_read = rtl8723_check_fw_read_last_h2c(hw, boxnum); + while (!isfw_read) { + wait_h2c_limit--; + if (wait_h2c_limit == 0) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Waiting too long for FW read " + "clear HMEBox(%d)!\n", boxnum); + break; + } + udelay(10); + + isfw_read = rtl8723_check_fw_read_last_h2c(hw, + boxnum); + } + if (!isfw_read) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Write H2C register BOX[%d] fail!!!!! " + "Fw do not read.\n", boxnum); + break; + } + memset(boxcontent, 0, sizeof(boxcontent)); + memset(boxextcontent, 0, sizeof(boxextcontent)); + boxcontent[0] = element_id; + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Write element_id box_reg(%4x) = %2x\n", + box_reg, element_id); + + switch (cmd_len) { + case 1: + case 2: + case 3: + /*boxcontent[0] &= ~(BIT(7));*/ + memcpy((u8 *)(boxcontent) + 1, + p_cmdbuffer + buf_index, cmd_len); + + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + } + break; + case 4: + case 5: + case 6: + case 7: + /*boxcontent[0] |= (BIT(7));*/ + memcpy((u8 *)(boxextcontent), + p_cmdbuffer + buf_index+3, cmd_len-3); + memcpy((u8 *)(boxcontent) + 1, + p_cmdbuffer + buf_index, 3); + + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_extreg + idx, + boxextcontent[idx]); + } + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + } + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not process\n"); + break; + } + bwrite_sucess = true; + + rtlhal->last_hmeboxnum = boxnum + 1; + if (rtlhal->last_hmeboxnum == 4) + rtlhal->last_hmeboxnum = 0; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "pHalData->last_hmeboxnum = %d\n", + rtlhal->last_hmeboxnum); + } + if (!rtlpriv) { + pr_err("rtlpriv bad\n"); + return; + } + if (!rtlhal) { + pr_err("rtlhal bad\n"); + return; + } + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); + rtlhal->h2c_setinprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n"); +} +EXPORT_SYMBOL_GPL(rtl8723_fill_h2c_command); + +void rtl8723_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, + u32 cmd_len, u8 *p_cmdbuffer) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 tmp_cmdbuf[2]; + + if (!rtlhal->fw_ready) { + RT_ASSERT(false, + "return H2C cmd because of Fw download fail!!!\n"); + return; + } + memset(tmp_cmdbuf, 0, 8); + memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len); + rtl8723_fill_h2c_command(hw, element_id, cmd_len, + (u8 *)&tmp_cmdbuf); + return; +} +EXPORT_SYMBOL_GPL(rtl8723_fill_h2c_cmd); + +void rtl8723_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus) +{ + u8 u1_joinbssrpt_parm[1] = { 0 }; + + SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus); + + rtl8723_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm); +} +EXPORT_SYMBOL_GPL(rtl8723_set_fw_joinbss_report_cmd); + +bool rtl8723_cmd_send_packet(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring; + struct rtl_tx_desc *pdesc; + struct sk_buff *pskb = NULL; + u8 own; + unsigned long flags; + + ring = &rtlpci->tx_ring[BEACON_QUEUE]; + + pskb = __skb_dequeue(&ring->queue); + if (pskb) + kfree_skb(pskb); + + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + + pdesc = &ring->desc[0]; + own = (u8) rtlpriv->cfg->ops->get_desc((u8 *)pdesc, true, HW_DESC_OWN); + + rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb); + + __skb_queue_tail(&ring->queue, skb); + + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE); + + return true; +} +EXPORT_SYMBOL_GPL(rtl8723_cmd_send_packet); + +void rtl8723_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct sk_buff *skb = NULL; + + u32 totalpacketlen; + bool rtstatus; + u8 u1rsvdpageloc[5] = { 0 }; + bool dlok = false; + + u8 *beacon; + u8 *p_pspoll; + u8 *nullfunc; + u8 *p_probersp; + /*--------------------------------------------------------- + * (1) beacon + *--------------------------------------------------------- + */ + beacon = &reserved_page_packet[BEACON_PG * 128]; + SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr); + SET_80211_HDR_ADDRESS3(beacon, mac->bssid); + + /*------------------------------------------------------- + * (2) ps-poll + *------------------------------------------------------- + */ + p_pspoll = &reserved_page_packet[PSPOLL_PG * 128]; + SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000)); + SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid); + SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr); + + SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG); + + /*-------------------------------------------------------- + * (3) null data + *-------------------------------------------------------- + */ + nullfunc = &reserved_page_packet[NULL_PG * 128]; + SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid); + SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr); + SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid); + + SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG); + + /*--------------------------------------------------------- + * (4) probe response + *--------------------------------------------------------- + */ + p_probersp = &reserved_page_packet[PROBERSP_PG * 128]; + SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid); + SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr); + SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid); + + SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG); + + totalpacketlen = TOTAL_RESERVED_PKT_LEN; + + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, + "rtl8723be_set_fw_rsvdpagepkt(): " + "HW_VAR_SET_TX_CMD: ALL\n", + &reserved_page_packet[0], totalpacketlen); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "rtl8723be_set_fw_rsvdpagepkt(): " + "HW_VAR_SET_TX_CMD: ALL\n", u1rsvdpageloc, 3); + + + skb = dev_alloc_skb(totalpacketlen); + memcpy((u8 *)skb_put(skb, totalpacketlen), + &reserved_page_packet, totalpacketlen); + + rtstatus = rtl8723_cmd_send_packet(hw, skb); + + if (rtstatus) + dlok = true; + + if (dlok) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Set RSVD page location to Fw.\n"); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, "H2C_RSVDPAGE:\n", + u1rsvdpageloc, 3); + rtl8723_fill_h2c_cmd(hw, H2C_88E_RSVDPAGE, + sizeof(u1rsvdpageloc), u1rsvdpageloc); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Set RSVD page location to Fw FAIL!!!!!!.\n"); + } +} +EXPORT_SYMBOL_GPL(rtl8723_set_fw_rsvdpagepkt); + +/*Should check FW support p2p or not.*/ +void rtl8723_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow) +{ + u8 u1_ctwindow_period[1] = {ctwindow}; + + rtl8723_fill_h2c_cmd(hw, H2C_88E_P2P_PS_CTW_CMD, 1, + u1_ctwindow_period); +} +EXPORT_SYMBOL_GPL(rtl8723_set_p2p_ctw_period_cmd); + +void rtl8723_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info); + struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload; + u8 i; + u16 ctwindow; + u32 start_time, tsf_low; + + switch (p2p_ps_state) { + case P2P_PS_DISABLE: + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n"); + memset(p2p_ps_offload, 0, sizeof(struct p2p_ps_offload_t *)); + break; + case P2P_PS_ENABLE: + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n"); + /* update CTWindow value. */ + if (p2pinfo->ctwindow > 0) { + p2p_ps_offload->ctwindow_en = 1; + ctwindow = p2pinfo->ctwindow; + rtl8723_set_p2p_ctw_period_cmd(hw, ctwindow); + } + /* hw only support 2 set of NoA */ + for (i = 0; i < p2pinfo->noa_num; i++) { + /* To control the register setting + * for which NOA + */ + rtl_write_byte(rtlpriv, 0x5cf, (i << 4)); + if (i == 0) + p2p_ps_offload->noa0_en = 1; + else + p2p_ps_offload->noa1_en = 1; + + /* config P2P NoA Descriptor Register */ + rtl_write_dword(rtlpriv, 0x5E0, + p2pinfo->noa_duration[i]); + rtl_write_dword(rtlpriv, 0x5E4, + p2pinfo->noa_interval[i]); + + /*Get Current TSF value */ + tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR); + + start_time = p2pinfo->noa_start_time[i]; + if (p2pinfo->noa_count_type[i] != 1) { + while (start_time <= (tsf_low + (50 * 1024))) { + start_time += p2pinfo->noa_interval[i]; + if (p2pinfo->noa_count_type[i] != 255) + p2pinfo->noa_count_type[i]--; + } + } + rtl_write_dword(rtlpriv, 0x5E8, start_time); + rtl_write_dword(rtlpriv, 0x5EC, + p2pinfo->noa_count_type[i]); + } + if ((p2pinfo->opp_ps == 1) || + (p2pinfo->noa_num > 0)) { + /* rst p2p circuit */ + rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4)); + + p2p_ps_offload->offload_en = 1; + + if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) { + p2p_ps_offload->role = 1; + p2p_ps_offload->allstasleep = 0; + } else { + p2p_ps_offload->role = 0; + } + p2p_ps_offload->discovery = 0; + } + break; + case P2P_PS_SCAN: + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n"); + p2p_ps_offload->discovery = 1; + break; + case P2P_PS_SCAN_DONE: + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n"); + p2p_ps_offload->discovery = 0; + p2pinfo->p2p_ps_state = P2P_PS_ENABLE; + break; + default: + break; + } + rtl8723_fill_h2c_cmd(hw, H2C_88E_P2P_PS_OFFLOAD, 1, + (u8 *)p2p_ps_offload); +} +EXPORT_SYMBOL_GPL(rtl8723_set_p2p_ps_offload_cmd); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h new file mode 100644 index 000000000000..0890e5deddfa --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h @@ -0,0 +1,50 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __FW_COMMON_H__ +#define __FW_COMMON_H__#endif + +void rtl8723_enable_fw_download(struct ieee80211_hw *hw, bool enable); +void rtl8723_fw_block_write(struct ieee80211_hw *hw, + const u8 *buffer, u32 size); +void rtl8723_fw_page_write(struct ieee80211_hw *hw, + u32 page, const u8 *buffer, u32 size); +void rtl8723_write_fw(struct ieee80211_hw *hw, + enum version_8723be version, + u8 *buffer, u32 size); +int rtl8723_fw_free_to_go(struct ieee80211_hw *hw, bool is_8723be); +int rtl8723_download_fw(struct ieee80211_hw *hw, + bool buse_wake_on_wlan_fw, bool is_8723be); +bool rtl8723_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum); +void rtl8723_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id, + u32 cmd_len, u8 *p_cmdbuffer); +void rtl8723_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, + u32 cmd_len, u8 *p_cmdbuffer); +void rtl8723_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); +bool rtl8723_cmd_send_packet(struct ieee80211_hw *hw, + struct sk_buff *skb); +void rtl8723_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished); +void rtl8723_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow); +void rtl8723_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state); diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.h b/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.h new file mode 100644 index 000000000000..8f451d0584df --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.h @@ -0,0 +1,75 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __PHY_COMMON__ +#define __PHY_COMMON__ + +u32 rtl8723_phy_query_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask); +void rtl8723_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, + u32 bitmask, u32 data); +u32 rtl8723_phy_calculate_bit_shift(u32 bitmask); +u32 rtl8723_phy_rf_serial_read(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset); +void rtl8723_phy_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, + u32 offset, u32 data); +u32 rtl8723_phy_query_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask); +u32 rtl8723_phy_calculate_bit_shift(u32 bitmask); +void rtl8723_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, + u32 bitmask, u32 data); +long rtl8723_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw, + enum wireless_mode wirelessmode, + u8 txpwridx); +void rtl8723_phy_init_bb_rf_reg_def(struct ieee80211_hw *hw); +bool rtl8723_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, + u32 cmdtableidx, + u32 cmdtablesz, + enum swchnlcmd_id cmdid, + u32 para1, u32 para2, + u32 msdelay); +void rtl8723_phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw, + bool iqk_ok, + long result[][8], + u8 final_candidate, + bool btxonly); +void rtl8723_save_adda_registers(struct ieee80211_hw *hw, u32 *addareg, + u32 *addabackup, u32 registernum); +static void rtl8723_phy_save_mac_registers(struct ieee80211_hw *hw, + u32 *macreg, u32 *macbackup); +void rtl8723_phy_reload_adda_registers(struct ieee80211_hw *hw, + u32 *addareg, u32 *addabackup, + u32 regiesternum); +void rtl8723_phy_reload_mac_registers(struct ieee80211_hw *hw, + u32 *macreg, u32 *macbackup); +void rtl8723_phy_path_adda_on(struct ieee80211_hw *hw, u32 *addareg, + bool is_patha_on, bool is2t); +void rtl8723_phy_mac_setting_calibration(struct ieee80211_hw *hw, + u32 *macreg, u32 *macbackup); +void rtl8723_phy_path_a_standby(struct ieee80211_hw *hw); +void rtl8723_phy_pi_mode_switch(struct ieee80211_hw *hw, bool pi_mode); + +#endif diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 8c647391bedf..de91c82f87fd 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -49,6 +49,7 @@ #define IQK_ADDA_REG_NUM 16 #define IQK_MAC_REG_NUM 4 +#define IQK_THRESHOLD 8 #define MAX_KEY_LEN 61 #define KEY_BUF_SIZE 5 @@ -96,6 +97,7 @@ #define CHANNEL_MAX_NUMBER_2G 14 #define AVG_THERMAL_NUM 8 #define AVG_THERMAL_NUM_88E 4 +#define AVG_THERMAL_NUM_8723BE 4 #define MAX_TID_COUNT 9 /* for early mode */ @@ -115,6 +117,8 @@ struct txpower_info_2g { u8 ofdm_diff[MAX_RF_PATH][MAX_TX_COUNT]; u8 bw20_diff[MAX_RF_PATH][MAX_TX_COUNT]; u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw80_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw160_diff[MAX_RF_PATH][MAX_TX_COUNT]; }; struct txpower_info_5g { @@ -158,6 +162,7 @@ enum hardware_type { HARDWARE_TYPE_RTL8192DU, HARDWARE_TYPE_RTL8723AE, HARDWARE_TYPE_RTL8723U, + HARDWARE_TYPE_RTL8723BE, HARDWARE_TYPE_RTL8188EE, /* keep it last */ @@ -1986,6 +1991,44 @@ struct rtl_global_var { spinlock_t glb_list_lock; }; +struct rtl_btc_info { + u8 bt_type; + u8 btcoexist; + u8 ant_num; +}; + +struct rtl_bt_coexist { + struct rtl_btc_ops *btc_ops; + struct rtl_btc_info btc_info; +}; + +struct rtl_btc_ops { + void (*btc_init_variables) (struct rtl_priv *rtlpriv); + void (*btc_init_hal_vars) (struct rtl_priv *rtlpriv); + void (*btc_init_hw_config) (struct rtl_priv *rtlpriv); + void (*btc_ips_notify) (struct rtl_priv *rtlpriv, u8 type); + void (*btc_scan_notify) (struct rtl_priv *rtlpriv, u8 scantype); + void (*btc_connect_notify) (struct rtl_priv *rtlpriv, u8 action); + void (*btc_mediastatus_notify) (struct rtl_priv *rtlpriv, + enum _RT_MEDIA_STATUS mstatus); + void (*btc_periodical) (struct rtl_priv *rtlpriv); + void (*btc_halt_notify) (void); + void (*btc_btinfo_notify) (struct rtl_priv *rtlpriv, + u8 *tmp_buf, u8 length); + bool (*btc_is_limited_dig) (struct rtl_priv *rtlpriv); + bool (*btc_is_disable_edca_turbo) (struct rtl_priv *rtlpriv); + bool (*btc_is_bt_disabled) (struct rtl_priv *rtlpriv); +}; + +struct proxim { + bool proxim_on; + + void *proximity_priv; + int (*proxim_rx)(struct ieee80211_hw *hw, struct rtl_stats *status, + struct sk_buff *skb); + u8 (*proxim_get_var)(struct ieee80211_hw *hw, u8 type); +}; + struct rtl_priv { struct ieee80211_hw *hw; struct completion firmware_loading_complete; @@ -2048,6 +2091,20 @@ struct rtl_priv { bool enter_ps; /* true when entering PS */ u8 rate_mask[5]; + /* intel Proximity, should be alloc mem + * in intel Proximity module and can only + * be used in intel Proximity mode + */ + struct proxim proximity; + + /*for bt coexist use*/ + struct rtl_bt_coexist btcoexist; + + /* separate 92ee from other ICs, + * 92ee use new trx flow. + */ + bool use_new_trx_flow; + /*This must be the last item so that it points to the data allocated beyond this structure like: @@ -2079,6 +2136,9 @@ enum bt_co_type { BT_CSR_BC8 = 4, BT_RTL8756 = 5, BT_RTL8723A = 6, + BT_RTL8821 = 7, + BT_RTL8723B = 8, + BT_RTL8192E = 9, }; enum bt_cur_state { From 2cddad3c737a35118151ec930fb43a710b3646d2 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 28 Feb 2014 15:16:46 -0600 Subject: [PATCH 390/414] rtlwifi: Prepare existing drivers for new driver A driver for the RTL8723BE will soon be added. This patch adds the necessary parts to the common headers, and modifies the existing drivers for those changes. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/core.c | 12 +- drivers/net/wireless/rtlwifi/pci.c | 2 +- drivers/net/wireless/rtlwifi/pci.h | 4 + drivers/net/wireless/rtlwifi/rtl8188ee/dm.c | 6 +- drivers/net/wireless/rtlwifi/rtl8188ee/hw.c | 18 +- drivers/net/wireless/rtlwifi/rtl8188ee/phy.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | 12 +- drivers/net/wireless/rtlwifi/rtl8192cu/hw.c | 12 +- drivers/net/wireless/rtlwifi/rtl8192de/hw.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192se/hw.c | 2 +- drivers/net/wireless/rtlwifi/rtl8723ae/hw.c | 28 +-- drivers/net/wireless/rtlwifi/rtl8723ae/trx.h | 6 - drivers/net/wireless/rtlwifi/usb.c | 2 +- drivers/net/wireless/rtlwifi/wifi.h | 250 ++++++++++++------- 14 files changed, 215 insertions(+), 143 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 6df4df090b73..724b830fe429 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -746,6 +746,11 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, rtlpriv->cfg->ops->linked_set_reg(hw); rcu_read_lock(); sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid); + if (!sta) { + pr_err("ieee80211_find_sta returned NULL\n"); + rcu_read_unlock(); + goto out; + } if (vif->type == NL80211_IFTYPE_STATION && sta) rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); @@ -900,7 +905,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, mac->basic_rates = basic_rates; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, - (u8 *) (&basic_rates)); + (u8 *)(&basic_rates)); } rcu_read_unlock(); } @@ -914,6 +919,11 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, if (bss_conf->assoc) { if (ppsc->fwctrl_lps) { u8 mstatus = RT_MEDIA_CONNECT; + u8 keep_alive = 10; + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_KEEP_ALIVE, + (u8 *)(&keep_alive)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_JOINBSSRPT, &mstatus); diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index d7aa165fe677..257726860a43 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -1066,7 +1066,7 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw, mac->current_ampdu_factor = 3; /*QOS*/ - rtlpci->acm_method = eAcmWay2_SW; + rtlpci->acm_method = EACMWAY2_SW; /*task */ tasklet_init(&rtlpriv->works.irq_tasklet, diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h index d3262ec45d23..2a3333523ac4 100644 --- a/drivers/net/wireless/rtlwifi/pci.h +++ b/drivers/net/wireless/rtlwifi/pci.h @@ -199,6 +199,10 @@ struct rtl_pci { u16 shortretry_limit; u16 longretry_limit; + + /* MSI support */ + bool msi_support; + bool using_msi; }; struct mp_adapter { diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c index a6184b6e1d57..97bc9aa5e1d1 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c @@ -235,7 +235,7 @@ void rtl88e_dm_txpower_track_adjust(struct ieee80211_hw *hw, u8 pwr_val = 0; u8 cck_base = rtldm->swing_idx_cck_base; u8 cck_val = rtldm->swing_idx_cck; - u8 ofdm_base = rtldm->swing_idx_ofdm_base; + u8 ofdm_base = rtldm->swing_idx_ofdm_base[0]; u8 ofdm_val = rtlpriv->dm.swing_idx_ofdm[RF90_PATH_A]; if (type == 0) { @@ -726,7 +726,7 @@ static void rtl88e_dm_pwdb_monitor(struct ieee80211_hw *hw) static u64 last_rx; long tmp_entry_max_pwdb = 0, tmp_entry_min_pwdb = 0xff; - if (rtlhal->oem_id == RT_CID_819x_HP) { + if (rtlhal->oem_id == RT_CID_819X_HP) { u64 cur_txok_cnt = 0; u64 cur_rxok_cnt = 0; cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok; @@ -912,7 +912,7 @@ static void rtl88e_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw for (i = 0; i < OFDM_TABLE_LENGTH; i++) { if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) { ofdm_old[0] = (u8) i; - rtldm->swing_idx_ofdm_base = (u8)i; + rtldm->swing_idx_ofdm_base[0] = (u8)i; RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "Initial pathA ele_d reg0x%x = 0x%lx, ofdm_index = 0x%x\n", ROFDM0_XATXIQIMBAL, diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c index ce2226cd2e4f..d608d75ff6ff 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c @@ -509,7 +509,7 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) u8 e_aci = *((u8 *)val); rtl88e_dm_init_edca_turbo(hw); - if (rtlpci->acm_method != eAcmWay2_SW) + if (rtlpci->acm_method != EACMWAY2_SW) rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL, (u8 *)(&e_aci)); break; } @@ -1097,7 +1097,7 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw) if (ppsc->rfpwr_state == ERFON) { if ((rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV) || ((rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) && - (rtlhal->oem_id == RT_CID_819x_HP))) { + (rtlhal->oem_id == RT_CID_819X_HP))) { rtl88e_phy_set_rfpath_switch(hw, true); rtlpriv->dm.fat_table.rx_idle_ant = MAIN_ANT; } else { @@ -1873,15 +1873,15 @@ static void _rtl88ee_read_adapter_info(struct ieee80211_hw *hw) case EEPROM_CID_DEFAULT: if (rtlefuse->eeprom_did == 0x8179) { if (rtlefuse->eeprom_svid == 0x1025) { - rtlhal->oem_id = RT_CID_819x_Acer; + rtlhal->oem_id = RT_CID_819X_ACER; } else if ((rtlefuse->eeprom_svid == 0x10EC && rtlefuse->eeprom_smid == 0x0179) || (rtlefuse->eeprom_svid == 0x17AA && rtlefuse->eeprom_smid == 0x0179)) { - rtlhal->oem_id = RT_CID_819x_Lenovo; + rtlhal->oem_id = RT_CID_819X_LENOVO; } else if (rtlefuse->eeprom_svid == 0x103c && rtlefuse->eeprom_smid == 0x197d) { - rtlhal->oem_id = RT_CID_819x_HP; + rtlhal->oem_id = RT_CID_819X_HP; } else { rtlhal->oem_id = RT_CID_DEFAULT; } @@ -1893,7 +1893,7 @@ static void _rtl88ee_read_adapter_info(struct ieee80211_hw *hw) rtlhal->oem_id = RT_CID_TOSHIBA; break; case EEPROM_CID_QMI: - rtlhal->oem_id = RT_CID_819x_QMI; + rtlhal->oem_id = RT_CID_819X_QMI; break; case EEPROM_CID_WHQL: default: @@ -1912,14 +1912,14 @@ static void _rtl88ee_hal_customized_behavior(struct ieee80211_hw *hw) pcipriv->ledctl.led_opendrain = true; switch (rtlhal->oem_id) { - case RT_CID_819x_HP: + case RT_CID_819X_HP: pcipriv->ledctl.led_opendrain = true; break; - case RT_CID_819x_Lenovo: + case RT_CID_819X_LENOVO: case RT_CID_DEFAULT: case RT_CID_TOSHIBA: case RT_CID_CCX: - case RT_CID_819x_Acer: + case RT_CID_819X_ACER: case RT_CID_WHQL: default: break; diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c index d67f9c731cc4..54d4ec2dc26b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c @@ -1002,7 +1002,7 @@ bool rtl88e_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, } } - if (rtlhal->oem_id == RT_CID_819x_HP) + if (rtlhal->oem_id == RT_CID_819X_HP) rtl88_config_s(hw, 0x52, 0x7E4BD); break; diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index b5b513404376..c6a38201ac81 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -319,7 +319,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) u8 e_aci = *(val); rtl92c_dm_init_edca_turbo(hw); - if (rtlpci->acm_method != eAcmWay2_SW) + if (rtlpci->acm_method != EACMWAY2_SW) rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL, (&e_aci)); @@ -1736,7 +1736,7 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw) if (rtlefuse->eeprom_did == 0x8176) { if ((rtlefuse->eeprom_svid == 0x103C && rtlefuse->eeprom_smid == 0x1629)) - rtlhal->oem_id = RT_CID_819x_HP; + rtlhal->oem_id = RT_CID_819X_HP; else rtlhal->oem_id = RT_CID_DEFAULT; } else { @@ -1747,7 +1747,7 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw) rtlhal->oem_id = RT_CID_TOSHIBA; break; case EEPROM_CID_QMI: - rtlhal->oem_id = RT_CID_819x_QMI; + rtlhal->oem_id = RT_CID_819X_QMI; break; case EEPROM_CID_WHQL: default: @@ -1766,14 +1766,14 @@ static void _rtl92ce_hal_customized_behavior(struct ieee80211_hw *hw) struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); switch (rtlhal->oem_id) { - case RT_CID_819x_HP: + case RT_CID_819X_HP: pcipriv->ledctl.led_opendrain = true; break; - case RT_CID_819x_Lenovo: + case RT_CID_819X_LENOVO: case RT_CID_DEFAULT: case RT_CID_TOSHIBA: case RT_CID_CCX: - case RT_CID_819x_Acer: + case RT_CID_819X_ACER: case RT_CID_WHQL: default: break; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 49ad10668078..db7df7f83a02 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -394,7 +394,7 @@ static void _rtl92cu_read_adapter_info(struct ieee80211_hw *hw) if (rtlefuse->eeprom_did == 0x8176) { if ((rtlefuse->eeprom_svid == 0x103C && rtlefuse->eeprom_smid == 0x1629)) - rtlhal->oem_id = RT_CID_819x_HP; + rtlhal->oem_id = RT_CID_819X_HP; else rtlhal->oem_id = RT_CID_DEFAULT; } else { @@ -405,7 +405,7 @@ static void _rtl92cu_read_adapter_info(struct ieee80211_hw *hw) rtlhal->oem_id = RT_CID_TOSHIBA; break; case EEPROM_CID_QMI: - rtlhal->oem_id = RT_CID_819x_QMI; + rtlhal->oem_id = RT_CID_819X_QMI; break; case EEPROM_CID_WHQL: default: @@ -423,14 +423,14 @@ static void _rtl92cu_hal_customized_behavior(struct ieee80211_hw *hw) struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); switch (rtlhal->oem_id) { - case RT_CID_819x_HP: + case RT_CID_819X_HP: usb_priv->ledctl.led_opendrain = true; break; - case RT_CID_819x_Lenovo: + case RT_CID_819X_LENOVO: case RT_CID_DEFAULT: case RT_CID_TOSHIBA: case RT_CID_CCX: - case RT_CID_819x_Acer: + case RT_CID_819X_ACER: case RT_CID_WHQL: default: break; @@ -1797,7 +1797,7 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) e_aci); break; } - if (rtlusb->acm_method != eAcmWay2_SW) + if (rtlusb->acm_method != EACMWAY2_SW) rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL, &e_aci); break; diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c index c16aa6b59527..c9f6ee7e1765 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c @@ -318,7 +318,7 @@ void rtl92de_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) case HW_VAR_AC_PARAM: { u8 e_aci = *val; rtl92d_dm_init_edca_turbo(hw); - if (rtlpci->acm_method != eAcmWay2_SW) + if (rtlpci->acm_method != EACMWAY2_SW) rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL, &e_aci); break; diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c index 5aa39ef42eba..7c4b39cc5dbf 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c @@ -251,7 +251,7 @@ void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) u8 e_aci = *val; rtl92s_dm_init_edca_turbo(hw); - if (rtlpci->acm_method != eAcmWay2_SW) + if (rtlpci->acm_method != EACMWAY2_SW) rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL, &e_aci); diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c index 4680816f9597..914b36f72d55 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c @@ -306,7 +306,7 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) u8 e_aci = *((u8 *) val); rtl8723ae_dm_init_edca_turbo(hw); - if (rtlpci->acm_method != eAcmWay2_SW) + if (rtlpci->acm_method != EACMWAY2_SW) rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL, (u8 *) (&e_aci)); @@ -1656,7 +1656,7 @@ static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw, CHK_SVID_SMID(0x10EC, 0x9185)) rtlhal->oem_id = RT_CID_TOSHIBA; else if (rtlefuse->eeprom_svid == 0x1025) - rtlhal->oem_id = RT_CID_819x_Acer; + rtlhal->oem_id = RT_CID_819X_ACER; else if (CHK_SVID_SMID(0x10EC, 0x6191) || CHK_SVID_SMID(0x10EC, 0x6192) || CHK_SVID_SMID(0x10EC, 0x6193) || @@ -1666,7 +1666,7 @@ static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw, CHK_SVID_SMID(0x10EC, 0x8191) || CHK_SVID_SMID(0x10EC, 0x8192) || CHK_SVID_SMID(0x10EC, 0x8193)) - rtlhal->oem_id = RT_CID_819x_SAMSUNG; + rtlhal->oem_id = RT_CID_819X_SAMSUNG; else if (CHK_SVID_SMID(0x10EC, 0x8195) || CHK_SVID_SMID(0x10EC, 0x9195) || CHK_SVID_SMID(0x10EC, 0x7194) || @@ -1674,24 +1674,24 @@ static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw, CHK_SVID_SMID(0x10EC, 0x8201) || CHK_SVID_SMID(0x10EC, 0x8202) || CHK_SVID_SMID(0x10EC, 0x9200)) - rtlhal->oem_id = RT_CID_819x_Lenovo; + rtlhal->oem_id = RT_CID_819X_LENOVO; else if (CHK_SVID_SMID(0x10EC, 0x8197) || CHK_SVID_SMID(0x10EC, 0x9196)) - rtlhal->oem_id = RT_CID_819x_CLEVO; + rtlhal->oem_id = RT_CID_819X_CLEVO; else if (CHK_SVID_SMID(0x1028, 0x8194) || CHK_SVID_SMID(0x1028, 0x8198) || CHK_SVID_SMID(0x1028, 0x9197) || CHK_SVID_SMID(0x1028, 0x9198)) - rtlhal->oem_id = RT_CID_819x_DELL; + rtlhal->oem_id = RT_CID_819X_DELL; else if (CHK_SVID_SMID(0x103C, 0x1629)) - rtlhal->oem_id = RT_CID_819x_HP; + rtlhal->oem_id = RT_CID_819X_HP; else if (CHK_SVID_SMID(0x1A32, 0x2315)) - rtlhal->oem_id = RT_CID_819x_QMI; + rtlhal->oem_id = RT_CID_819X_QMI; else if (CHK_SVID_SMID(0x10EC, 0x8203)) - rtlhal->oem_id = RT_CID_819x_PRONETS; + rtlhal->oem_id = RT_CID_819X_PRONETS; else if (CHK_SVID_SMID(0x1043, 0x84B5)) rtlhal->oem_id = - RT_CID_819x_Edimax_ASUS; + RT_CID_819X_EDIMAX_ASUS; else rtlhal->oem_id = RT_CID_DEFAULT; } else if (rtlefuse->eeprom_did == 0x8178) { @@ -1713,12 +1713,12 @@ static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw, CHK_SVID_SMID(0x10EC, 0x9185)) rtlhal->oem_id = RT_CID_TOSHIBA; else if (rtlefuse->eeprom_svid == 0x1025) - rtlhal->oem_id = RT_CID_819x_Acer; + rtlhal->oem_id = RT_CID_819X_ACER; else if (CHK_SVID_SMID(0x10EC, 0x8186)) - rtlhal->oem_id = RT_CID_819x_PRONETS; + rtlhal->oem_id = RT_CID_819X_PRONETS; else if (CHK_SVID_SMID(0x1043, 0x8486)) rtlhal->oem_id = - RT_CID_819x_Edimax_ASUS; + RT_CID_819X_EDIMAX_ASUS; else rtlhal->oem_id = RT_CID_DEFAULT; } else { @@ -1732,7 +1732,7 @@ static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw, rtlhal->oem_id = RT_CID_CCX; break; case EEPROM_CID_QMI: - rtlhal->oem_id = RT_CID_819x_QMI; + rtlhal->oem_id = RT_CID_819X_QMI; break; case EEPROM_CID_WHQL: break; diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h index ad05b54bc0f1..c75bfe8d570c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h @@ -521,12 +521,6 @@ do { \ memset(__pdesc, 0, _size); \ } while (0) -#define RTL8723E_RX_HAL_IS_CCK_RATE(rxmcs) \ - ((rxmcs) == DESC92_RATE1M || \ - (rxmcs) == DESC92_RATE2M || \ - (rxmcs) == DESC92_RATE5_5M || \ - (rxmcs) == DESC92_RATE11M) - struct rx_fwinfo_8723e { u8 gain_trsw[4]; u8 pwdb_all; diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 4933f02ce1d5..4e2a726cdb16 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -410,7 +410,7 @@ static void rtl_usb_init_sw(struct ieee80211_hw *hw) mac->current_ampdu_factor = 3; /* QOS */ - rtlusb->acm_method = eAcmWay2_SW; + rtlusb->acm_method = EACMWAY2_SW; /* IRQ */ /* HIMR - turn all on */ diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index de91c82f87fd..3f52bf8abe00 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -109,6 +109,19 @@ #define MAX_CHNL_GROUP_24G 6 #define MAX_CHNL_GROUP_5G 14 +#define TX_PWR_BY_RATE_NUM_BAND 2 +#define TX_PWR_BY_RATE_NUM_RF 4 +#define TX_PWR_BY_RATE_NUM_SECTION 12 +#define MAX_BASE_NUM_IN_PHY_REG_PG_24G 6 +#define MAX_BASE_NUM_IN_PHY_REG_PG_5G 5 + +enum rf_tx_num { + RF_1TX = 0, + RF_2TX, + RF_MAX_TX_NUM, + RF_TX_NUM_NONIMPLEMENT, +}; + struct txpower_info_2g { u8 index_cck_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G]; u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G]; @@ -129,6 +142,15 @@ struct txpower_info_5g { u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT]; }; +enum rate_section { + CCK = 0, + OFDM, + HT_MCS0_MCS7, + HT_MCS8_MCS15, + VHT_1SSMCS0_1SSMCS9, + VHT_2SSMCS0_2SSMCS9, +}; + enum intf_type { INTF_PCI = 0, INTF_USB = 1, @@ -200,6 +222,12 @@ enum hardware_type { _pdesc->rxmcs == DESC92_RATE5_5M || \ _pdesc->rxmcs == DESC92_RATE11M) +#define RTL8723E_RX_HAL_IS_CCK_RATE(rxmcs) \ + ((rxmcs) == DESC92_RATE1M || \ + (rxmcs) == DESC92_RATE2M || \ + (rxmcs) == DESC92_RATE5_5M || \ + (rxmcs) == DESC92_RATE11M) + enum scan_operation_backup_opt { SCAN_OPT_BACKUP = 0, SCAN_OPT_RESTORE, @@ -335,6 +363,7 @@ enum hw_variables { HAL_DEF_WOWLAN, HW_VAR_MRC, + HW_VAR_KEEP_ALIVE, HW_VAR_MGT_FILTER, HW_VAR_CTRL_FILTER, @@ -353,34 +382,34 @@ enum rt_oem_id { RT_CID_8187_HW_LED = 3, RT_CID_8187_NETGEAR = 4, RT_CID_WHQL = 5, - RT_CID_819x_CAMEO = 6, - RT_CID_819x_RUNTOP = 7, - RT_CID_819x_Senao = 8, + RT_CID_819X_CAMEO = 6, + RT_CID_819X_RUNTOP = 7, + RT_CID_819X_SENAO = 8, RT_CID_TOSHIBA = 9, - RT_CID_819x_Netcore = 10, - RT_CID_Nettronix = 11, + RT_CID_819X_NETCORE = 10, + RT_CID_NETTRONIX = 11, RT_CID_DLINK = 12, RT_CID_PRONET = 13, RT_CID_COREGA = 14, - RT_CID_819x_ALPHA = 15, - RT_CID_819x_Sitecom = 16, + RT_CID_819X_ALPHA = 15, + RT_CID_819X_SITECOM = 16, RT_CID_CCX = 17, - RT_CID_819x_Lenovo = 18, - RT_CID_819x_QMI = 19, - RT_CID_819x_Edimax_Belkin = 20, - RT_CID_819x_Sercomm_Belkin = 21, - RT_CID_819x_CAMEO1 = 22, - RT_CID_819x_MSI = 23, - RT_CID_819x_Acer = 24, - RT_CID_819x_HP = 27, - RT_CID_819x_CLEVO = 28, - RT_CID_819x_Arcadyan_Belkin = 29, - RT_CID_819x_SAMSUNG = 30, - RT_CID_819x_WNC_COREGA = 31, - RT_CID_819x_Foxcoon = 32, - RT_CID_819x_DELL = 33, - RT_CID_819x_PRONETS = 34, - RT_CID_819x_Edimax_ASUS = 35, + RT_CID_819X_LENOVO = 18, + RT_CID_819X_QMI = 19, + RT_CID_819X_EDIMAX_BELKIN = 20, + RT_CID_819X_SERCOMM_BELKIN = 21, + RT_CID_819X_CAMEO1 = 22, + RT_CID_819X_MSI = 23, + RT_CID_819X_ACER = 24, + RT_CID_819X_HP = 27, + RT_CID_819X_CLEVO = 28, + RT_CID_819X_ARCADYAN_BELKIN = 29, + RT_CID_819X_SAMSUNG = 30, + RT_CID_819X_WNC_COREGA = 31, + RT_CID_819X_FOXCOON = 32, + RT_CID_819X_DELL = 33, + RT_CID_819X_PRONETS = 34, + RT_CID_819X_EDIMAX_ASUS = 35, RT_CID_NETGEAR = 36, RT_CID_PLANEX = 37, RT_CID_CC_C = 38, @@ -613,7 +642,7 @@ enum rtl_led_pin { enum acm_method { eAcmWay0_SwAndHw = 0, eAcmWay1_HW = 1, - eAcmWay2_SW = 2, + EACMWAY2_SW = 2, }; enum macphy_mode { @@ -822,9 +851,9 @@ struct rate_adaptive { u32 high_rssi_thresh_for_ra; u32 high2low_rssi_thresh_for_ra; u8 low2high_rssi_thresh_for_ra40m; - u32 low_rssi_thresh_for_ra40M; + u32 low_rssi_thresh_for_ra40m; u8 low2high_rssi_thresh_for_ra20m; - u32 low_rssi_thresh_for_ra20M; + u32 low_rssi_thresh_for_ra20m; u32 upper_rssi_threshold_ratr; u32 middleupper_rssi_threshold_ratr; u32 middle_rssi_threshold_ratr; @@ -991,6 +1020,13 @@ struct rtl_phy { u8 cck_high_power; /* MAX_PG_GROUP groups of pwr diff by rates */ u32 mcs_offset[MAX_PG_GROUP][16]; + u32 tx_power_by_rate_offset[TX_PWR_BY_RATE_NUM_BAND] + [TX_PWR_BY_RATE_NUM_RF] + [TX_PWR_BY_RATE_NUM_RF] + [TX_PWR_BY_RATE_NUM_SECTION]; + u8 txpwr_by_rate_base_24g[TX_PWR_BY_RATE_NUM_RF] + [TX_PWR_BY_RATE_NUM_RF] + [MAX_BASE_NUM_IN_PHY_REG_PG_24G]; u8 default_initialgain[4]; /* the current Tx power level */ @@ -1218,6 +1254,7 @@ struct rtl_hal { bool being_init_adapter; bool bbrf_ready; bool mac_func_enable; + bool pre_edcca_enable; struct bt_coexist_8723 hal_coex_8723; enum intf_type interface; @@ -1326,6 +1363,16 @@ struct fast_ant_training { bool becomelinked; }; +struct dm_phy_dbg_info { + char rx_snrdb[4]; + u64 num_qry_phy_status; + u64 num_qry_phy_status_cck; + u64 num_qry_phy_status_ofdm; + u16 num_qry_beacon_pkt; + u16 num_non_be_pkt; + s32 rx_evm[4]; +}; + struct rtl_dm { /*PHY status for Dynamic Management */ long entry_min_undec_sm_pwdb; @@ -1367,14 +1414,28 @@ struct rtl_dm { bool disable_tx_int; char ofdm_index[2]; char cck_index; - char delta_power_index; - char delta_power_index_last; - char power_index_offset; + char delta_power_index[MAX_RF_PATH]; + char delta_power_index_last[MAX_RF_PATH]; + char power_index_offset[MAX_RF_PATH]; + + bool one_entry_only; + struct dm_phy_dbg_info dbginfo; + + /* Dynamic ATC switch */ + bool atc_status; + bool large_cfo_hit; + bool is_freeze; + int cfo_tail[2]; + int cfo_ave_pre; + int crystal_cap; + u8 cfo_threshold; + u32 packet_count; + u32 packet_count_pre; /*88e tx power tracking*/ u8 swing_idx_ofdm[2]; u8 swing_idx_ofdm_cur; - u8 swing_idx_ofdm_base; + u8 swing_idx_ofdm_base[MAX_RF_PATH]; bool swing_flag_ofdm; u8 swing_idx_cck; u8 swing_idx_cck_cur; @@ -1427,12 +1488,14 @@ struct rtl_efuse { u8 eeprom_tssi_5g[3][2]; /* for 5GL/5GM/5GH band. */ u8 eeprom_pwrlimit_ht20[CHANNEL_GROUP_MAX]; u8 eeprom_pwrlimit_ht40[CHANNEL_GROUP_MAX]; - u8 eeprom_chnlarea_txpwr_cck[2][CHANNEL_GROUP_MAX_2G]; - u8 eeprom_chnlarea_txpwr_ht40_1s[2][CHANNEL_GROUP_MAX]; - u8 eprom_chnl_txpwr_ht40_2sdf[2][CHANNEL_GROUP_MAX]; + u8 eeprom_chnlarea_txpwr_cck[MAX_RF_PATH][CHANNEL_GROUP_MAX_2G]; + u8 eeprom_chnlarea_txpwr_ht40_1s[MAX_RF_PATH][CHANNEL_GROUP_MAX]; + u8 eprom_chnl_txpwr_ht40_2sdf[MAX_RF_PATH][CHANNEL_GROUP_MAX]; u8 txpwrlevel_cck[2][CHANNEL_MAX_NUMBER_2G]; - u8 txpwrlevel_ht40_1s[2][CHANNEL_MAX_NUMBER]; /*For HT 40MHZ pwr */ - u8 txpwrlevel_ht40_2s[2][CHANNEL_MAX_NUMBER]; /*For HT 40MHZ pwr */ + /* For HT 40MHZ pwr */ + u8 txpwrlevel_ht40_1s[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + u8 txpwrlevel_ht40_2s[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + u8 txpwr_ht40diff[MAX_RF_PATH][MAX_TX_COUNT];/*BW40_24G_Diff*/ u8 internal_pa_5g[2]; /* pathA / pathB */ u8 eeprom_c9; @@ -1705,6 +1768,8 @@ struct rtl_hal_ops { enum led_ctl_mode ledaction); void (*set_desc) (u8 *pdesc, bool istx, u8 desc_name, u8 *val); u32 (*get_desc) (u8 *pdesc, bool istx, u8 desc_name); + bool (*is_tx_desc_closed) (struct ieee80211_hw *hw, + u8 hw_queue, u16 index); void (*tx_polling) (struct ieee80211_hw *hw, u8 hw_queue); void (*enable_hw_sec) (struct ieee80211_hw *hw); void (*set_key) (struct ieee80211_hw *hw, u32 key_index, @@ -1743,6 +1808,7 @@ struct rtl_hal_ops { void (*bt_coex_off_before_lps) (struct ieee80211_hw *hw); void (*fill_h2c_cmd) (struct ieee80211_hw *hw, u8 element_id, u32 cmd_len, u8 *p_cmdbuffer); + bool (*get_btc_status) (void); }; struct rtl_intf_ops { @@ -1920,6 +1986,7 @@ struct ps_t { u8 cur_ccasate; u8 pre_rfstate; u8 cur_rfstate; + u8 initialize; long rssi_val_min; }; @@ -1977,6 +2044,7 @@ struct dig_t { char backoffval_range_min; u8 dig_min_0; u8 dig_min_1; + u8 bt30_cur_igi; bool media_connect_0; bool media_connect_1; @@ -1997,9 +2065,61 @@ struct rtl_btc_info { u8 ant_num; }; -struct rtl_bt_coexist { +struct bt_coexist_info { struct rtl_btc_ops *btc_ops; struct rtl_btc_info btc_info; + /* EEPROM BT info. */ + u8 eeprom_bt_coexist; + u8 eeprom_bt_type; + u8 eeprom_bt_ant_num; + u8 eeprom_bt_ant_isol; + u8 eeprom_bt_radio_shared; + + u8 bt_coexistence; + u8 bt_ant_num; + u8 bt_coexist_type; + u8 bt_state; + u8 bt_cur_state; /* 0:on, 1:off */ + u8 bt_ant_isolation; /* 0:good, 1:bad */ + u8 bt_pape_ctrl; /* 0:SW, 1:SW/HW dynamic */ + u8 bt_service; + u8 bt_radio_shared_type; + u8 bt_rfreg_origin_1e; + u8 bt_rfreg_origin_1f; + u8 bt_rssi_state; + u32 ratio_tx; + u32 ratio_pri; + u32 bt_edca_ul; + u32 bt_edca_dl; + + bool init_set; + bool bt_busy_traffic; + bool bt_traffic_mode_set; + bool bt_non_traffic_mode_set; + + bool fw_coexist_all_off; + bool sw_coexist_all_off; + bool hw_coexist_all_off; + u32 cstate; + u32 previous_state; + u32 cstate_h; + u32 previous_state_h; + + u8 bt_pre_rssi_state; + u8 bt_pre_rssi_state1; + + u8 reg_bt_iso; + u8 reg_bt_sco; + bool balance_on; + u8 bt_active_zero_cnt; + bool cur_bt_disabled; + bool pre_bt_disabled; + + u8 bt_profile_case; + u8 bt_profile_action; + bool bt_busy; + bool hold_for_bt_operation; + u8 lps_counter; }; struct rtl_btc_ops { @@ -2098,7 +2218,7 @@ struct rtl_priv { struct proxim proximity; /*for bt coexist use*/ - struct rtl_bt_coexist btcoexist; + struct bt_coexist_info btcoexist; /* separate 92ee from other ICs, * 92ee use new trx flow. @@ -2164,62 +2284,6 @@ enum bt_radio_shared { BT_RADIO_INDIVIDUAL = 1, }; -struct bt_coexist_info { - - /* EEPROM BT info. */ - u8 eeprom_bt_coexist; - u8 eeprom_bt_type; - u8 eeprom_bt_ant_num; - u8 eeprom_bt_ant_isol; - u8 eeprom_bt_radio_shared; - - u8 bt_coexistence; - u8 bt_ant_num; - u8 bt_coexist_type; - u8 bt_state; - u8 bt_cur_state; /* 0:on, 1:off */ - u8 bt_ant_isolation; /* 0:good, 1:bad */ - u8 bt_pape_ctrl; /* 0:SW, 1:SW/HW dynamic */ - u8 bt_service; - u8 bt_radio_shared_type; - u8 bt_rfreg_origin_1e; - u8 bt_rfreg_origin_1f; - u8 bt_rssi_state; - u32 ratio_tx; - u32 ratio_pri; - u32 bt_edca_ul; - u32 bt_edca_dl; - - bool init_set; - bool bt_busy_traffic; - bool bt_traffic_mode_set; - bool bt_non_traffic_mode_set; - - bool fw_coexist_all_off; - bool sw_coexist_all_off; - bool hw_coexist_all_off; - u32 cstate; - u32 previous_state; - u32 cstate_h; - u32 previous_state_h; - - u8 bt_pre_rssi_state; - u8 bt_pre_rssi_state1; - - u8 reg_bt_iso; - u8 reg_bt_sco; - bool balance_on; - u8 bt_active_zero_cnt; - bool cur_bt_disabled; - bool pre_bt_disabled; - - u8 bt_profile_case; - u8 bt_profile_action; - bool bt_busy; - bool hold_for_bt_operation; - u8 lps_counter; -}; - /**************************************** mem access macro define start From 0a168b48cdf7c22cf0250f62df4dde20adebf74b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 28 Feb 2014 15:16:47 -0600 Subject: [PATCH 391/414] rtlwifi: rtl8723ae: rtl8723-common: Create new driver for common code The drivers for RTL8723AE and RTL8723BE have some code in common. This commit creates a driver for this code that will be shared, and copies those common routines from rtl8723ae's phy code. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/Kconfig | 6 + drivers/net/wireless/rtlwifi/Makefile | 1 + .../net/wireless/rtlwifi/rtl8723ae/hal_btc.c | 7 +- drivers/net/wireless/rtlwifi/rtl8723ae/phy.c | 482 ++---------------- drivers/net/wireless/rtlwifi/rtl8723ae/phy.h | 21 - drivers/net/wireless/rtlwifi/rtl8723ae/sw.c | 5 +- .../net/wireless/rtlwifi/rtl8723com/Makefile | 7 + .../net/wireless/rtlwifi/rtl8723com/main.c | 33 ++ .../wireless/rtlwifi/rtl8723com/phy_common.c | 434 ++++++++++++++++ .../wireless/rtlwifi/rtl8723com/phy_common.h | 28 +- 10 files changed, 555 insertions(+), 469 deletions(-) create mode 100644 drivers/net/wireless/rtlwifi/rtl8723com/Makefile create mode 100644 drivers/net/wireless/rtlwifi/rtl8723com/main.c create mode 100644 drivers/net/wireless/rtlwifi/rtl8723com/phy_common.c diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig index 29c6ce5c3371..9251e0d3685c 100644 --- a/drivers/net/wireless/rtlwifi/Kconfig +++ b/drivers/net/wireless/rtlwifi/Kconfig @@ -48,6 +48,7 @@ config RTL8723AE depends on PCI select RTLWIFI select RTLWIFI_PCI + select RTL8723_COMMON select RTLBTCOEXIST ---help--- This is the driver for Realtek RTL8723AE 802.11n PCIe @@ -102,6 +103,11 @@ config RTL8192C_COMMON depends on RTL8192CE || RTL8192CU default y +config RTL8723_COMMON + tristate + depends on RTL8723AE + default y + config RTLBTCOEXIST tristate depends on RTL8723AE diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile index f354c5f9aed5..d97d1b9d2427 100644 --- a/drivers/net/wireless/rtlwifi/Makefile +++ b/drivers/net/wireless/rtlwifi/Makefile @@ -26,5 +26,6 @@ obj-$(CONFIG_RTL8192DE) += rtl8192de/ obj-$(CONFIG_RTL8723AE) += rtl8723ae/ obj-$(CONFIG_RTL8188EE) += rtl8188ee/ obj-$(CONFIG_RTLBTCOEXIST) += btcoexist/ +obj-$(CONFIG_RTL8723_COMMON) += rtl8723com/ ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c index 68c28340f791..8b64b1cd3176 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c @@ -30,6 +30,7 @@ #include "hal_btc.h" #include "../pci.h" #include "phy.h" +#include "../rtl8723com/phy_common.h" #include "fw.h" #include "reg.h" #include "def.h" @@ -391,13 +392,13 @@ static void rtl8723ae_dm_bt_set_sw_full_time_dac_swing(struct ieee80211_hw *hw, if (sw_dac_swing_on) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, "[BTCoex], SwDacSwing = 0x%x\n", sw_dac_swing_lvl); - rtl8723ae_phy_set_bb_reg(hw, 0x880, 0xff000000, - sw_dac_swing_lvl); + rtl8723_phy_set_bb_reg(hw, 0x880, 0xff000000, + sw_dac_swing_lvl); rtlpcipriv->bt_coexist.sw_coexist_all_off = false; } else { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, "[BTCoex], SwDacSwing Off!\n"); - rtl8723ae_phy_set_bb_reg(hw, 0x880, 0xff000000, 0xc0); + rtl8723_phy_set_bb_reg(hw, 0x880, 0xff000000, 0xc0); } } diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c index 5d318a85eda4..4f8189d3bb44 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c @@ -36,6 +36,7 @@ #include "rf.h" #include "dm.h" #include "table.h" +#include "../rtl8723com/phy_common.h" /* static forward definitions */ static u32 _phy_fw_rf_serial_read(struct ieee80211_hw *hw, @@ -43,72 +44,17 @@ static u32 _phy_fw_rf_serial_read(struct ieee80211_hw *hw, static void _phy_fw_rf_serial_write(struct ieee80211_hw *hw, enum radio_path rfpath, u32 offset, u32 data); -static u32 _phy_rf_serial_read(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 offset); -static void _phy_rf_serial_write(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 offset, u32 data); -static u32 _phy_calculate_bit_shift(u32 bitmask); static bool _phy_bb8192c_config_parafile(struct ieee80211_hw *hw); static bool _phy_cfg_mac_w_header(struct ieee80211_hw *hw); static bool _phy_cfg_bb_w_header(struct ieee80211_hw *hw, u8 configtype); static bool _phy_cfg_bb_w_pgheader(struct ieee80211_hw *hw, u8 configtype); -static void _phy_init_bb_rf_reg_def(struct ieee80211_hw *hw); -static bool _phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, - u32 cmdtableidx, u32 cmdtablesz, - enum swchnlcmd_id cmdid, - u32 para1, u32 para2, - u32 msdelay); static bool _phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, u8 channel, u8 *stage, u8 *step, u32 *delay); static u8 _phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw, enum wireless_mode wirelessmode, long power_indbm); -static long _phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw, - enum wireless_mode wirelessmode, u8 txpwridx); static void rtl8723ae_phy_set_io(struct ieee80211_hw *hw); -u32 rtl8723ae_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, - u32 bitmask) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - u32 returnvalue, originalvalue, bitshift; - - RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, - "regaddr(%#x), bitmask(%#x)\n", regaddr, bitmask); - originalvalue = rtl_read_dword(rtlpriv, regaddr); - bitshift = _phy_calculate_bit_shift(bitmask); - returnvalue = (originalvalue & bitmask) >> bitshift; - - RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, - "BBR MASK=0x%x Addr[0x%x]=0x%x\n", bitmask, regaddr, - originalvalue); - - return returnvalue; -} - -void rtl8723ae_phy_set_bb_reg(struct ieee80211_hw *hw, - u32 regaddr, u32 bitmask, u32 data) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - u32 originalvalue, bitshift; - - RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, - "regaddr(%#x), bitmask(%#x), data(%#x)\n", regaddr, - bitmask, data); - - if (bitmask != MASKDWORD) { - originalvalue = rtl_read_dword(rtlpriv, regaddr); - bitshift = _phy_calculate_bit_shift(bitmask); - data = ((originalvalue & (~bitmask)) | (data << bitshift)); - } - - rtl_write_dword(rtlpriv, regaddr, data); - - RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, - "regaddr(%#x), bitmask(%#x), data(%#x)\n", - regaddr, bitmask, data); -} - u32 rtl8723ae_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, u32 regaddr, u32 bitmask) { @@ -124,11 +70,11 @@ u32 rtl8723ae_phy_query_rf_reg(struct ieee80211_hw *hw, spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); if (rtlphy->rf_mode != RF_OP_BY_FW) - original_value = _phy_rf_serial_read(hw, rfpath, regaddr); + original_value = rtl8723_phy_rf_serial_read(hw, rfpath, regaddr); else original_value = _phy_fw_rf_serial_read(hw, rfpath, regaddr); - bitshift = _phy_calculate_bit_shift(bitmask); + bitshift = rtl8723_phy_calculate_bit_shift(bitmask); readback_value = (original_value & bitmask) >> bitshift; spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); @@ -157,19 +103,19 @@ void rtl8723ae_phy_set_rf_reg(struct ieee80211_hw *hw, if (rtlphy->rf_mode != RF_OP_BY_FW) { if (bitmask != RFREG_OFFSET_MASK) { - original_value = _phy_rf_serial_read(hw, rfpath, - regaddr); - bitshift = _phy_calculate_bit_shift(bitmask); + original_value = rtl8723_phy_rf_serial_read(hw, rfpath, + regaddr); + bitshift = rtl8723_phy_calculate_bit_shift(bitmask); data = ((original_value & (~bitmask)) | (data << bitshift)); } - _phy_rf_serial_write(hw, rfpath, regaddr, data); + rtl8723_phy_rf_serial_write(hw, rfpath, regaddr, data); } else { if (bitmask != RFREG_OFFSET_MASK) { original_value = _phy_fw_rf_serial_read(hw, rfpath, regaddr); - bitshift = _phy_calculate_bit_shift(bitmask); + bitshift = rtl8723_phy_calculate_bit_shift(bitmask); data = ((original_value & (~bitmask)) | (data << bitshift)); } @@ -197,87 +143,6 @@ static void _phy_fw_rf_serial_write(struct ieee80211_hw *hw, RT_ASSERT(false, "deprecated!\n"); } -static u32 _phy_rf_serial_read(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 offset) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_phy *rtlphy = &(rtlpriv->phy); - struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; - u32 newoffset; - u32 tmplong, tmplong2; - u8 rfpi_enable = 0; - u32 retvalue; - - offset &= 0x3f; - newoffset = offset; - if (RT_CANNOT_IO(hw)) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "return all one\n"); - return 0xFFFFFFFF; - } - tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD); - if (rfpath == RF90_PATH_A) - tmplong2 = tmplong; - else - tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD); - tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) | - (newoffset << 23) | BLSSIREADEDGE; - rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, - tmplong & (~BLSSIREADEDGE)); - mdelay(1); - rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2); - mdelay(1); - rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, - tmplong | BLSSIREADEDGE); - mdelay(1); - if (rfpath == RF90_PATH_A) - rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1, - BIT(8)); - else if (rfpath == RF90_PATH_B) - rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1, - BIT(8)); - if (rfpi_enable) - retvalue = rtl_get_bbreg(hw, pphyreg->rf_rbpi, - BLSSIREADBACKDATA); - else - retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb, - BLSSIREADBACKDATA); - RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x]=0x%x\n", - rfpath, pphyreg->rf_rb, retvalue); - return retvalue; -} - -static void _phy_rf_serial_write(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 offset, u32 data) -{ - u32 data_and_addr; - u32 newoffset; - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_phy *rtlphy = &(rtlpriv->phy); - struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; - - if (RT_CANNOT_IO(hw)) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "stop\n"); - return; - } - offset &= 0x3f; - newoffset = offset; - data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff; - rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr); - RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFW-%d Addr[0x%x]=0x%x\n", - rfpath, pphyreg->rf3wire_offset, data_and_addr); -} - -static u32 _phy_calculate_bit_shift(u32 bitmask) -{ - u32 i; - - for (i = 0; i <= 31; i++) { - if (((bitmask >> i) & 0x1) == 1) - break; - } - return i; -} - static void _rtl8723ae_phy_bb_config_1t(struct ieee80211_hw *hw) { rtl_set_bbreg(hw, RFPGA0_TXINFO, 0x3, 0x2); @@ -307,7 +172,7 @@ bool rtl8723ae_phy_bb_config(struct ieee80211_hw *hw) u8 tmpu1b; u8 reg_hwparafile = 1; - _phy_init_bb_rf_reg_def(hw); + rtl8723_phy_init_bb_rf_reg_def(hw); /* 1. 0x28[1] = 1 */ tmpu1b = rtl_read_byte(rtlpriv, REG_AFE_PLL_CTRL); @@ -690,92 +555,6 @@ void rtl8723ae_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw) ROFDM0_RXDETECTOR3, rtlphy->framesync); } -static void _phy_init_bb_rf_reg_def(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_phy *rtlphy = &(rtlpriv->phy); - - rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW; - rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW; - rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW; - rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW; - - rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB; - rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB; - rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB; - rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB; - - rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE; - rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE; - - rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE; - rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE; - - rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset = - RFPGA0_XA_LSSIPARAMETER; - rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset = - RFPGA0_XB_LSSIPARAMETER; - - rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = rFPGA0_XAB_RFPARAMETER; - rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = rFPGA0_XAB_RFPARAMETER; - rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = rFPGA0_XCD_RFPARAMETER; - rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = rFPGA0_XCD_RFPARAMETER; - - rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE; - rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE; - rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE; - rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE; - - rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1; - rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1; - - rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2; - rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2; - - rtlphy->phyreg_def[RF90_PATH_A].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL; - rtlphy->phyreg_def[RF90_PATH_B].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL; - rtlphy->phyreg_def[RF90_PATH_C].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL; - rtlphy->phyreg_def[RF90_PATH_D].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL; - - rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1; - rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1; - rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1; - rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1; - - rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2; - rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2; - rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2; - rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2; - - rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbal = ROFDM0_XARXIQIMBALANCE; - rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbal = ROFDM0_XBRXIQIMBALANCE; - rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbal = ROFDM0_XCRXIQIMBANLANCE; - rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbal = ROFDM0_XDRXIQIMBALANCE; - - rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE; - rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE; - rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE; - rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE; - - rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbal = ROFDM0_XATXIQIMBALANCE; - rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbal = ROFDM0_XBTXIQIMBALANCE; - rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbal = ROFDM0_XCTXIQIMBALANCE; - rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbal = ROFDM0_XDTXIQIMBALANCE; - - rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE; - rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE; - rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTXAFE; - rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE; - - rtlphy->phyreg_def[RF90_PATH_A].rf_rb = RFPGA0_XA_LSSIREADBACK; - rtlphy->phyreg_def[RF90_PATH_B].rf_rb = RFPGA0_XB_LSSIREADBACK; - rtlphy->phyreg_def[RF90_PATH_C].rf_rb = RFPGA0_XC_LSSIREADBACK; - rtlphy->phyreg_def[RF90_PATH_D].rf_rb = RFPGA0_XD_LSSIREADBACK; - - rtlphy->phyreg_def[RF90_PATH_A].rf_rbpi = TRANSCEIVEA_HSPI_READBACK; - rtlphy->phyreg_def[RF90_PATH_B].rf_rbpi = TRANSCEIVEB_HSPI_READBACK; -} - void rtl8723ae_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -785,17 +564,17 @@ void rtl8723ae_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel) long txpwr_dbm; txpwr_level = rtlphy->cur_cck_txpwridx; - txpwr_dbm = _phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_B, txpwr_level); + txpwr_dbm = rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_B, txpwr_level); txpwr_level = rtlphy->cur_ofdm24g_txpwridx + rtlefuse->legacy_ht_txpowerdiff; - if (_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, txpwr_level) > txpwr_dbm) - txpwr_dbm = _phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, + if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, txpwr_level) > txpwr_dbm) + txpwr_dbm = rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, txpwr_level); txpwr_level = rtlphy->cur_ofdm24g_txpwridx; - if (_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, txpwr_level) > + if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, txpwr_level) > txpwr_dbm) - txpwr_dbm = _phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, - txpwr_level); + txpwr_dbm = rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, + txpwr_level); *powerlevel = txpwr_dbm; } @@ -912,28 +691,6 @@ static u8 _phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw, return txpwridx; } -static long _phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw, - enum wireless_mode wirelessmode, u8 txpwridx) -{ - long offset; - long pwrout_dbm; - - switch (wirelessmode) { - case WIRELESS_MODE_B: - offset = -7; - break; - case WIRELESS_MODE_G: - case WIRELESS_MODE_N_24G: - offset = -8; - break; - default: - offset = -8; - break; - } - pwrout_dbm = txpwridx / 2 + offset; - return pwrout_dbm; -} - void rtl8723ae_phy_set_bw_mode_callback(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -1117,26 +874,26 @@ static bool _phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, u8 channel, u8 num_total_rfpath = rtlphy->num_total_rfpath; precommoncmdcnt = 0; - _phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, - MAX_PRECMD_CNT, CMDID_SET_TXPOWEROWER_LEVEL, - 0, 0, 0); - _phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, - MAX_PRECMD_CNT, CMDID_END, 0, 0, 0); + rtl8723_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, + MAX_PRECMD_CNT, CMDID_SET_TXPOWEROWER_LEVEL, + 0, 0, 0); + rtl8723_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, + MAX_PRECMD_CNT, CMDID_END, 0, 0, 0); postcommoncmdcnt = 0; - _phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++, - MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0); + rtl8723_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++, + MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0); rfdependcmdcnt = 0; RT_ASSERT((channel >= 1 && channel <= 14), "illegal channel for Zebra: %d\n", channel); - _phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, - MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG, + rtl8723_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, + MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG, RF_CHNLBW, channel, 10); - _phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, - MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0, 0); + rtl8723_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, + MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0, 0); do { switch (*stage) { @@ -1204,29 +961,6 @@ static bool _phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, u8 channel, return false; } -static bool _phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, - u32 cmdtableidx, u32 cmdtablesz, - enum swchnlcmd_id cmdid, u32 para1, - u32 para2, u32 msdelay) -{ - struct swchnlcmd *pcmd; - - if (cmdtable == NULL) { - RT_ASSERT(false, "cmdtable cannot be NULL.\n"); - return false; - } - - if (cmdtableidx >= cmdtablesz) - return false; - - pcmd = cmdtable + cmdtableidx; - pcmd->cmdid = cmdid; - pcmd->para1 = para1; - pcmd->para2 = para2; - pcmd->msdelay = msdelay; - return true; -} - static u8 _rtl8723ae_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb) { u32 reg_eac, reg_e94, reg_e9c, reg_ea4; @@ -1297,136 +1031,6 @@ static u8 _rtl8723ae_phy_path_b_iqk(struct ieee80211_hw *hw) return result; } -static void phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw, bool iqk_ok, - long result[][8], u8 final_candidate, - bool btxonly) -{ - u32 oldval_0, x, tx0_a, reg; - long y, tx0_c; - - if (final_candidate == 0xFF) { - return; - } else if (iqk_ok) { - oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE, - MASKDWORD) >> 22) & 0x3FF; - x = result[final_candidate][0]; - if ((x & 0x00000200) != 0) - x = x | 0xFFFFFC00; - tx0_a = (x * oldval_0) >> 8; - rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x3FF, tx0_a); - rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(31), - ((x * oldval_0 >> 7) & 0x1)); - y = result[final_candidate][1]; - if ((y & 0x00000200) != 0) - y = y | 0xFFFFFC00; - tx0_c = (y * oldval_0) >> 8; - rtl_set_bbreg(hw, ROFDM0_XCTXAFE, 0xF0000000, - ((tx0_c & 0x3C0) >> 6)); - rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x003F0000, - (tx0_c & 0x3F)); - rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(29), - ((y * oldval_0 >> 7) & 0x1)); - if (btxonly) - return; - reg = result[final_candidate][2]; - rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0x3FF, reg); - reg = result[final_candidate][3] & 0x3F; - rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0xFC00, reg); - reg = (result[final_candidate][3] >> 6) & 0xF; - rtl_set_bbreg(hw, 0xca0, 0xF0000000, reg); - } -} - -static void phy_save_adda_regs(struct ieee80211_hw *hw, - u32 *addareg, u32 *addabackup, - u32 registernum) -{ - u32 i; - - for (i = 0; i < registernum; i++) - addabackup[i] = rtl_get_bbreg(hw, addareg[i], MASKDWORD); -} - -static void phy_save_mac_regs(struct ieee80211_hw *hw, u32 *macreg, - u32 *macbackup) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - u32 i; - - for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) - macbackup[i] = rtl_read_byte(rtlpriv, macreg[i]); - macbackup[i] = rtl_read_dword(rtlpriv, macreg[i]); -} - -static void phy_reload_adda_regs(struct ieee80211_hw *hw, u32 *addareg, - u32 *addabackup, u32 regiesternum) -{ - u32 i; - - for (i = 0; i < regiesternum; i++) - rtl_set_bbreg(hw, addareg[i], MASKDWORD, addabackup[i]); -} - -static void phy_reload_mac_regs(struct ieee80211_hw *hw, u32 *macreg, - u32 *macbackup) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - u32 i; - - for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) - rtl_write_byte(rtlpriv, macreg[i], (u8) macbackup[i]); - rtl_write_dword(rtlpriv, macreg[i], macbackup[i]); -} - -static void _rtl8723ae_phy_path_adda_on(struct ieee80211_hw *hw, - u32 *addareg, bool is_patha_on, - bool is2t) -{ - u32 pathOn; - u32 i; - - pathOn = is_patha_on ? 0x04db25a4 : 0x0b1b25a4; - if (false == is2t) { - pathOn = 0x0bdb25a0; - rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0b1b25a0); - } else { - rtl_set_bbreg(hw, addareg[0], MASKDWORD, pathOn); - } - - for (i = 1; i < IQK_ADDA_REG_NUM; i++) - rtl_set_bbreg(hw, addareg[i], MASKDWORD, pathOn); -} - -static void _rtl8723ae_phy_mac_setting_calibration(struct ieee80211_hw *hw, - u32 *macreg, u32 *macbackup) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - u32 i = 0; - - rtl_write_byte(rtlpriv, macreg[i], 0x3F); - - for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++) - rtl_write_byte(rtlpriv, macreg[i], - (u8) (macbackup[i] & (~BIT(3)))); - rtl_write_byte(rtlpriv, macreg[i], (u8) (macbackup[i] & (~BIT(5)))); -} - -static void _rtl8723ae_phy_path_a_standby(struct ieee80211_hw *hw) -{ - rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x0); - rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000); - rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000); -} - -static void _rtl8723ae_phy_pi_mode_switch(struct ieee80211_hw *hw, bool pi_mode) -{ - u32 mode; - - mode = pi_mode ? 0x01000100 : 0x01000000; - rtl_set_bbreg(hw, 0x820, MASKDWORD, mode); - rtl_set_bbreg(hw, 0x828, MASKDWORD, mode); -} - static bool phy_simularity_comp(struct ieee80211_hw *hw, long result[][8], u8 c1, u8 c2) { @@ -1498,10 +1102,12 @@ static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, const u32 retrycount = 2; if (t == 0) { - phy_save_adda_regs(hw, adda_reg, rtlphy->adda_backup, 16); - phy_save_mac_regs(hw, iqk_mac_reg, rtlphy->iqk_mac_backup); + rtl8723_save_adda_registers(hw, adda_reg, rtlphy->adda_backup, + 16); + rtl8723_phy_save_mac_registers(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); } - _rtl8723ae_phy_path_adda_on(hw, adda_reg, true, is2t); + rtl8723_phy_path_adda_on(hw, adda_reg, true, is2t); if (t == 0) { rtlphy->rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1, @@ -1509,7 +1115,7 @@ static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, } if (!rtlphy->rfpi_enable) - _rtl8723ae_phy_pi_mode_switch(hw, true); + rtl8723_phy_pi_mode_switch(hw, true); if (t == 0) { rtlphy->reg_c04 = rtl_get_bbreg(hw, 0xc04, MASKDWORD); rtlphy->reg_c08 = rtl_get_bbreg(hw, 0xc08, MASKDWORD); @@ -1522,7 +1128,7 @@ static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000); rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00010000); } - _rtl8723ae_phy_mac_setting_calibration(hw, iqk_mac_reg, + rtl8723_phy_mac_setting_calibration(hw, iqk_mac_reg, rtlphy->iqk_mac_backup); rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x00080000); if (is2t) @@ -1552,8 +1158,8 @@ static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, } if (is2t) { - _rtl8723ae_phy_path_a_standby(hw); - _rtl8723ae_phy_path_adda_on(hw, adda_reg, false, is2t); + rtl8723_phy_path_a_standby(hw); + rtl8723_phy_path_adda_on(hw, adda_reg, false, is2t); for (i = 0; i < retrycount; i++) { pathb_ok = _rtl8723ae_phy_path_b_iqk(hw); if (pathb_ok == 0x03) { @@ -1588,9 +1194,11 @@ static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00032ed3); if (t != 0) { if (!rtlphy->rfpi_enable) - _rtl8723ae_phy_pi_mode_switch(hw, false); - phy_reload_adda_regs(hw, adda_reg, rtlphy->adda_backup, 16); - phy_reload_mac_regs(hw, iqk_mac_reg, rtlphy->iqk_mac_backup); + rtl8723_phy_pi_mode_switch(hw, false); + rtl8723_phy_reload_adda_registers(hw, adda_reg, + rtlphy->adda_backup, 16); + rtl8723_phy_reload_mac_registers(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); } } @@ -1691,7 +1299,8 @@ void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery) }; if (recovery) { - phy_reload_adda_regs(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 10); + rtl8723_phy_reload_adda_registers(hw, iqk_bb_reg, + rtlphy->iqk_bb_backup, 10); return; } if (start_conttx || singletone) @@ -1756,9 +1365,10 @@ void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery) rtlphy->reg_e9c = rtlphy->reg_ebc = 0x0; } if (reg_e94 != 0) /*&&(reg_ea4 != 0) */ - phy_path_a_fill_iqk_matrix(hw, patha_ok, result, - final_candidate, (reg_ea4 == 0)); - phy_save_adda_regs(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 10); + rtl8723_phy_path_a_fill_iqk_matrix(hw, patha_ok, result, + final_candidate, + (reg_ea4 == 0)); + rtl8723_save_adda_registers(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 10); } void rtl8723ae_phy_lc_calibrate(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.h b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.h index 007ebdbbe108..cd43139ed332 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.h +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.h @@ -76,23 +76,6 @@ #define RTL92C_MAX_PATH_NUM 2 -enum swchnlcmd_id { - CMDID_END, - CMDID_SET_TXPOWEROWER_LEVEL, - CMDID_BBREGWRITE10, - CMDID_WRITEPORT_ULONG, - CMDID_WRITEPORT_USHORT, - CMDID_WRITEPORT_UCHAR, - CMDID_RF_WRITEREG, -}; - -struct swchnlcmd { - enum swchnlcmd_id cmdid; - u32 para1; - u32 para2; - u32 msdelay; -}; - enum hw90_block_e { HW90_BLOCK_MAC = 0, HW90_BLOCK_PHY0 = 1, @@ -183,10 +166,6 @@ struct tx_power_struct { u32 mcs_original_offset[4][16]; }; -u32 rtl8723ae_phy_query_bb_reg(struct ieee80211_hw *hw, - u32 regaddr, u32 bitmask); -void rtl8723ae_phy_set_bb_reg(struct ieee80211_hw *hw, - u32 regaddr, u32 bitmask, u32 data); u32 rtl8723ae_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, u32 regaddr, u32 bitmask); diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c index 62b204faf773..0b97c9acebaa 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c @@ -37,6 +37,7 @@ #include "reg.h" #include "def.h" #include "phy.h" +#include "../rtl8723com/phy_common.h" #include "dm.h" #include "hw.h" #include "sw.h" @@ -231,8 +232,8 @@ static struct rtl_hal_ops rtl8723ae_hal_ops = { .set_key = rtl8723ae_set_key, .init_sw_leds = rtl8723ae_init_sw_leds, .allow_all_destaddr = rtl8723ae_allow_all_destaddr, - .get_bbreg = rtl8723ae_phy_query_bb_reg, - .set_bbreg = rtl8723ae_phy_set_bb_reg, + .get_bbreg = rtl8723_phy_query_bb_reg, + .set_bbreg = rtl8723_phy_set_bb_reg, .get_rfreg = rtl8723ae_phy_query_rf_reg, .set_rfreg = rtl8723ae_phy_set_rf_reg, .c2h_command_handle = rtl_8723e_c2h_command_handle, diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/Makefile b/drivers/net/wireless/rtlwifi/rtl8723com/Makefile new file mode 100644 index 000000000000..00673c692e6b --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723com/Makefile @@ -0,0 +1,7 @@ +rtl8723-common-objs := \ + main.o \ + phy_common.o + +obj-$(CONFIG_RTL8723_COMMON) += rtl8723-common.o + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/main.c b/drivers/net/wireless/rtlwifi/rtl8723com/main.c new file mode 100644 index 000000000000..9014a94fac6a --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723com/main.c @@ -0,0 +1,33 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include + + +MODULE_AUTHOR("Realtek WlanFAE "); +MODULE_AUTHOR("Larry Finger "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek RTL8723AE/RTL8723BE 802.11n PCI wireless common routines"); diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.c new file mode 100644 index 000000000000..d73b659bd2b5 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.c @@ -0,0 +1,434 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "phy_common.h" +#include "../rtl8723ae/reg.h" +#include + +/* These routines are common to RTL8723AE and RTL8723bE */ + +u32 rtl8723_phy_query_bb_reg(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 returnvalue, originalvalue, bitshift; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x)\n", regaddr, bitmask); + originalvalue = rtl_read_dword(rtlpriv, regaddr); + bitshift = rtl8723_phy_calculate_bit_shift(bitmask); + returnvalue = (originalvalue & bitmask) >> bitshift; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "BBR MASK = 0x%x Addr[0x%x]= 0x%x\n", + bitmask, regaddr, originalvalue); + + return returnvalue; +} +EXPORT_SYMBOL_GPL(rtl8723_phy_query_bb_reg); + +void rtl8723_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, + u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 originalvalue, bitshift; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x)\n", + regaddr, bitmask, data); + + if (bitmask != MASKDWORD) { + originalvalue = rtl_read_dword(rtlpriv, regaddr); + bitshift = rtl8723_phy_calculate_bit_shift(bitmask); + data = ((originalvalue & (~bitmask)) | (data << bitshift)); + } + + rtl_write_dword(rtlpriv, regaddr, data); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x)\n", + regaddr, bitmask, data); +} +EXPORT_SYMBOL_GPL(rtl8723_phy_set_bb_reg); + +u32 rtl8723_phy_calculate_bit_shift(u32 bitmask) +{ + u32 i; + + for (i = 0; i <= 31; i++) { + if (((bitmask >> i) & 0x1) == 1) + break; + } + return i; +} +EXPORT_SYMBOL_GPL(rtl8723_phy_calculate_bit_shift); + +u32 rtl8723_phy_rf_serial_read(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; + u32 newoffset; + u32 tmplong, tmplong2; + u8 rfpi_enable = 0; + u32 retvalue; + + offset &= 0xff; + newoffset = offset; + if (RT_CANNOT_IO(hw)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "return all one\n"); + return 0xFFFFFFFF; + } + tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD); + if (rfpath == RF90_PATH_A) + tmplong2 = tmplong; + else + tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD); + tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) | + (newoffset << 23) | BLSSIREADEDGE; + rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, + tmplong & (~BLSSIREADEDGE)); + mdelay(1); + rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2); + mdelay(2); + if (rfpath == RF90_PATH_A) + rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1, + BIT(8)); + else if (rfpath == RF90_PATH_B) + rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1, + BIT(8)); + if (rfpi_enable) + retvalue = rtl_get_bbreg(hw, pphyreg->rf_rbpi, + BLSSIREADBACKDATA); + else + retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb, + BLSSIREADBACKDATA); + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "RFR-%d Addr[0x%x]= 0x%x\n", + rfpath, pphyreg->rf_rb, retvalue); + return retvalue; +} +EXPORT_SYMBOL_GPL(rtl8723_phy_rf_serial_read); + +void rtl8723_phy_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, + u32 offset, u32 data) +{ + u32 data_and_addr; + u32 newoffset; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; + + if (RT_CANNOT_IO(hw)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "stop\n"); + return; + } + offset &= 0xff; + newoffset = offset; + data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff; + rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr); + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "RFW-%d Addr[0x%x]= 0x%x\n", rfpath, + pphyreg->rf3wire_offset, data_and_addr); +} +EXPORT_SYMBOL_GPL(rtl8723_phy_rf_serial_write); + +long rtl8723_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw, + enum wireless_mode wirelessmode, + u8 txpwridx) +{ + long offset; + long pwrout_dbm; + + switch (wirelessmode) { + case WIRELESS_MODE_B: + offset = -7; + break; + case WIRELESS_MODE_G: + case WIRELESS_MODE_N_24G: + default: + offset = -8; + break; + } + pwrout_dbm = txpwridx / 2 + offset; + return pwrout_dbm; +} +EXPORT_SYMBOL_GPL(rtl8723_phy_txpwr_idx_to_dbm); + +void rtl8723_phy_init_bb_rf_reg_def(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW; + rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW; + rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW; + rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW; + + rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB; + rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB; + rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB; + rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB; + + rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE; + + rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE; + + rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset = + RFPGA0_XA_LSSIPARAMETER; + rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset = + RFPGA0_XB_LSSIPARAMETER; + + rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = rFPGA0_XAB_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = rFPGA0_XAB_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = rFPGA0_XCD_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = rFPGA0_XCD_RFPARAMETER; + + rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE; + rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE; + rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE; + rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE; + + rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1; + rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1; + + rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2; + rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2; + + rtlphy->phyreg_def[RF90_PATH_A].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_B].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_C].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_D].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL; + + rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1; + + rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2; + + rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbal = ROFDM0_XARXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbal = ROFDM0_XBRXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbal = ROFDM0_XCRXIQIMBANLANCE; + rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbal = ROFDM0_XDRXIQIMBALANCE; + + rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE; + rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE; + rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE; + rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE; + + rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbal = ROFDM0_XATXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbal = ROFDM0_XBTXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbal = ROFDM0_XCTXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbal = ROFDM0_XDTXIQIMBALANCE; + + rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE; + rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE; + rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTXAFE; + rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE; + + rtlphy->phyreg_def[RF90_PATH_A].rf_rb = RFPGA0_XA_LSSIREADBACK; + rtlphy->phyreg_def[RF90_PATH_B].rf_rb = RFPGA0_XB_LSSIREADBACK; + rtlphy->phyreg_def[RF90_PATH_C].rf_rb = RFPGA0_XC_LSSIREADBACK; + rtlphy->phyreg_def[RF90_PATH_D].rf_rb = RFPGA0_XD_LSSIREADBACK; + + rtlphy->phyreg_def[RF90_PATH_A].rf_rbpi = TRANSCEIVEA_HSPI_READBACK; + rtlphy->phyreg_def[RF90_PATH_B].rf_rbpi = TRANSCEIVEB_HSPI_READBACK; +} +EXPORT_SYMBOL_GPL(rtl8723_phy_init_bb_rf_reg_def); + +bool rtl8723_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, + u32 cmdtableidx, + u32 cmdtablesz, + enum swchnlcmd_id cmdid, + u32 para1, u32 para2, + u32 msdelay) +{ + struct swchnlcmd *pcmd; + + if (cmdtable == NULL) { + RT_ASSERT(false, "cmdtable cannot be NULL.\n"); + return false; + } + + if (cmdtableidx >= cmdtablesz) + return false; + + pcmd = cmdtable + cmdtableidx; + pcmd->cmdid = cmdid; + pcmd->para1 = para1; + pcmd->para2 = para2; + pcmd->msdelay = msdelay; + return true; +} +EXPORT_SYMBOL_GPL(rtl8723_phy_set_sw_chnl_cmdarray); + +void rtl8723_phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw, + bool iqk_ok, + long result[][8], + u8 final_candidate, + bool btxonly) +{ + u32 oldval_0, x, tx0_a, reg; + long y, tx0_c; + + if (final_candidate == 0xFF) { + return; + } else if (iqk_ok) { + oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE, + MASKDWORD) >> 22) & 0x3FF; + x = result[final_candidate][0]; + if ((x & 0x00000200) != 0) + x = x | 0xFFFFFC00; + tx0_a = (x * oldval_0) >> 8; + rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x3FF, tx0_a); + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(31), + ((x * oldval_0 >> 7) & 0x1)); + y = result[final_candidate][1]; + if ((y & 0x00000200) != 0) + y = y | 0xFFFFFC00; + tx0_c = (y * oldval_0) >> 8; + rtl_set_bbreg(hw, ROFDM0_XCTXAFE, 0xF0000000, + ((tx0_c & 0x3C0) >> 6)); + rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x003F0000, + (tx0_c & 0x3F)); + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(29), + ((y * oldval_0 >> 7) & 0x1)); + if (btxonly) + return; + reg = result[final_candidate][2]; + rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0x3FF, reg); + reg = result[final_candidate][3] & 0x3F; + rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0xFC00, reg); + reg = (result[final_candidate][3] >> 6) & 0xF; + rtl_set_bbreg(hw, 0xca0, 0xF0000000, reg); + } +} +EXPORT_SYMBOL_GPL(rtl8723_phy_path_a_fill_iqk_matrix); + +void rtl8723_save_adda_registers(struct ieee80211_hw *hw, u32 *addareg, + u32 *addabackup, u32 registernum) +{ + u32 i; + + for (i = 0; i < registernum; i++) + addabackup[i] = rtl_get_bbreg(hw, addareg[i], MASKDWORD); +} +EXPORT_SYMBOL_GPL(rtl8723_save_adda_registers); + +void rtl8723_phy_save_mac_registers(struct ieee80211_hw *hw, + u32 *macreg, u32 *macbackup) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) + macbackup[i] = rtl_read_byte(rtlpriv, macreg[i]); + macbackup[i] = rtl_read_dword(rtlpriv, macreg[i]); +} +EXPORT_SYMBOL_GPL(rtl8723_phy_save_mac_registers); + +void rtl8723_phy_reload_adda_registers(struct ieee80211_hw *hw, + u32 *addareg, u32 *addabackup, + u32 regiesternum) +{ + u32 i; + + for (i = 0; i < regiesternum; i++) + rtl_set_bbreg(hw, addareg[i], MASKDWORD, addabackup[i]); +} +EXPORT_SYMBOL_GPL(rtl8723_phy_reload_adda_registers); + +void rtl8723_phy_reload_mac_registers(struct ieee80211_hw *hw, + u32 *macreg, u32 *macbackup) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + + for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) + rtl_write_byte(rtlpriv, macreg[i], (u8) macbackup[i]); + rtl_write_dword(rtlpriv, macreg[i], macbackup[i]); +} +EXPORT_SYMBOL_GPL(rtl8723_phy_reload_mac_registers); + +void rtl8723_phy_path_adda_on(struct ieee80211_hw *hw, u32 *addareg, + bool is_patha_on, bool is2t) +{ + u32 pathon; + u32 i; + + pathon = is_patha_on ? 0x04db25a4 : 0x0b1b25a4; + if (!is2t) { + pathon = 0x0bdb25a0; + rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0b1b25a0); + } else { + rtl_set_bbreg(hw, addareg[0], MASKDWORD, pathon); + } + + for (i = 1; i < IQK_ADDA_REG_NUM; i++) + rtl_set_bbreg(hw, addareg[i], MASKDWORD, pathon); +} +EXPORT_SYMBOL_GPL(rtl8723_phy_path_adda_on); + +void rtl8723_phy_mac_setting_calibration(struct ieee80211_hw *hw, + u32 *macreg, u32 *macbackup) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i = 0; + + rtl_write_byte(rtlpriv, macreg[i], 0x3F); + + for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++) + rtl_write_byte(rtlpriv, macreg[i], + (u8) (macbackup[i] & (~BIT(3)))); + rtl_write_byte(rtlpriv, macreg[i], (u8) (macbackup[i] & (~BIT(5)))); +} +EXPORT_SYMBOL_GPL(rtl8723_phy_mac_setting_calibration); + +void rtl8723_phy_path_a_standby(struct ieee80211_hw *hw) +{ + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x0); + rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000); + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000); +} +EXPORT_SYMBOL_GPL(rtl8723_phy_path_a_standby); + +void rtl8723_phy_pi_mode_switch(struct ieee80211_hw *hw, bool pi_mode) +{ + u32 mode; + + mode = pi_mode ? 0x01000100 : 0x01000000; + rtl_set_bbreg(hw, 0x820, MASKDWORD, mode); + rtl_set_bbreg(hw, 0x828, MASKDWORD, mode); +} +EXPORT_SYMBOL_GPL(rtl8723_phy_pi_mode_switch); diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.h b/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.h index 8f451d0584df..83b891a9adb8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.h @@ -26,6 +26,25 @@ #ifndef __PHY_COMMON__ #define __PHY_COMMON__ +#define RT_CANNOT_IO(hw) false + +enum swchnlcmd_id { + CMDID_END, + CMDID_SET_TXPOWEROWER_LEVEL, + CMDID_BBREGWRITE10, + CMDID_WRITEPORT_ULONG, + CMDID_WRITEPORT_USHORT, + CMDID_WRITEPORT_UCHAR, + CMDID_RF_WRITEREG, +}; + +struct swchnlcmd { + enum swchnlcmd_id cmdid; + u32 para1; + u32 para2; + u32 msdelay; +}; + u32 rtl8723_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask); void rtl8723_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, @@ -36,11 +55,6 @@ u32 rtl8723_phy_rf_serial_read(struct ieee80211_hw *hw, void rtl8723_phy_rf_serial_write(struct ieee80211_hw *hw, enum radio_path rfpath, u32 offset, u32 data); -u32 rtl8723_phy_query_bb_reg(struct ieee80211_hw *hw, - u32 regaddr, u32 bitmask); -u32 rtl8723_phy_calculate_bit_shift(u32 bitmask); -void rtl8723_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, - u32 bitmask, u32 data); long rtl8723_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw, enum wireless_mode wirelessmode, u8 txpwridx); @@ -58,8 +72,8 @@ void rtl8723_phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw, bool btxonly); void rtl8723_save_adda_registers(struct ieee80211_hw *hw, u32 *addareg, u32 *addabackup, u32 registernum); -static void rtl8723_phy_save_mac_registers(struct ieee80211_hw *hw, - u32 *macreg, u32 *macbackup); +void rtl8723_phy_save_mac_registers(struct ieee80211_hw *hw, + u32 *macreg, u32 *macbackup); void rtl8723_phy_reload_adda_registers(struct ieee80211_hw *hw, u32 *addareg, u32 *addabackup, u32 regiesternum); From cbd0c8512f3b06c86849c554eb092862c46885d5 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 28 Feb 2014 15:16:48 -0600 Subject: [PATCH 392/414] rtlwifi: rtl8723ae: rtl8723-common: Copy common firmware code The drivers for RTL8723AE and RTL8723BE have some code in common. This commit copies the common firmware routines into the shared code. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8723ae/def.h | 5 - drivers/net/wireless/rtlwifi/rtl8723ae/fw.c | 260 +-------- drivers/net/wireless/rtlwifi/rtl8723ae/fw.h | 18 +- .../rtlwifi/rtl8723ae/hal_bt_coexist.c | 2 + .../net/wireless/rtlwifi/rtl8723ae/hal_btc.c | 1 + drivers/net/wireless/rtlwifi/rtl8723ae/hw.c | 3 +- drivers/net/wireless/rtlwifi/rtl8723ae/sw.c | 8 + .../net/wireless/rtlwifi/rtl8723com/Makefile | 1 + .../wireless/rtlwifi/rtl8723com/fw_common.c | 540 +----------------- .../wireless/rtlwifi/rtl8723com/fw_common.h | 106 +++- drivers/net/wireless/rtlwifi/wifi.h | 3 + 11 files changed, 142 insertions(+), 805 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/def.h b/drivers/net/wireless/rtlwifi/rtl8723ae/def.h index 8c110356dff9..debe261a7eeb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/def.h @@ -46,11 +46,6 @@ #define E_CUT_VERSION BIT(14) #define RF_RL_ID (BIT(31)|BIT(30)|BIT(29)|BIT(28)) -enum version_8723e { - VERSION_TEST_UMC_CHIP_8723 = 0x0081, - VERSION_NORMAL_UMC_CHIP_8723_1T1R_A_CUT = 0x0089, - VERSION_NORMAL_UMC_CHIP_8723_1T1R_B_CUT = 0x1089, -}; /* MASK */ #define IC_TYPE_MASK (BIT(0)|BIT(1)|BIT(2)) diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c index ba1502b172a6..728b7563ad36 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c @@ -34,199 +34,7 @@ #include "reg.h" #include "def.h" #include "fw.h" - -static void _rtl8723ae_enable_fw_download(struct ieee80211_hw *hw, bool enable) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - u8 tmp; - if (enable) { - tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); - rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04); - - tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); - rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01); - - tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2); - rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7); - } else { - tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); - rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe); - - rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00); - } -} - -static void _rtl8723ae_fw_block_write(struct ieee80211_hw *hw, - const u8 *buffer, u32 size) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - u32 blockSize = sizeof(u32); - u8 *bufferPtr = (u8 *) buffer; - u32 *pu4BytePtr = (u32 *) buffer; - u32 i, offset, blockCount, remainSize; - - blockCount = size / blockSize; - remainSize = size % blockSize; - - for (i = 0; i < blockCount; i++) { - offset = i * blockSize; - rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset), - *(pu4BytePtr + i)); - } - - if (remainSize) { - offset = blockCount * blockSize; - bufferPtr += offset; - for (i = 0; i < remainSize; i++) { - rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS + - offset + i), *(bufferPtr + i)); - } - } -} - -static void _rtl8723ae_fw_page_write(struct ieee80211_hw *hw, - u32 page, const u8 *buffer, u32 size) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - u8 value8; - u8 u8page = (u8) (page & 0x07); - - value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page; - - rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8); - _rtl8723ae_fw_block_write(hw, buffer, size); -} - -static void _rtl8723ae_write_fw(struct ieee80211_hw *hw, - enum version_8723e version, u8 *buffer, - u32 size) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - u8 *bufferPtr = (u8 *) buffer; - u32 page_nums, remain_size; - u32 page, offset; - - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size); - - page_nums = size / FW_8192C_PAGE_SIZE; - remain_size = size % FW_8192C_PAGE_SIZE; - - if (page_nums > 6) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "Page numbers should not be greater then 6\n"); - } - - for (page = 0; page < page_nums; page++) { - offset = page * FW_8192C_PAGE_SIZE; - _rtl8723ae_fw_page_write(hw, page, (bufferPtr + offset), - FW_8192C_PAGE_SIZE); - } - - if (remain_size) { - offset = page_nums * FW_8192C_PAGE_SIZE; - page = page_nums; - _rtl8723ae_fw_page_write(hw, page, (bufferPtr + offset), - remain_size); - } - - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW write done.\n"); -} - -static int _rtl8723ae_fw_free_to_go(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - int err = -EIO; - u32 counter = 0; - u32 value32; - - do { - value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); - } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) && - (!(value32 & FWDL_ChkSum_rpt))); - - if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "chksum report faill ! REG_MCUFWDL:0x%08x .\n", - value32); - goto exit; - } - - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, - "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32); - - value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); - value32 |= MCUFWDL_RDY; - value32 &= ~WINTINI_RDY; - rtl_write_dword(rtlpriv, REG_MCUFWDL, value32); - - counter = 0; - - do { - value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); - if (value32 & WINTINI_RDY) { - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, - "Polling FW ready success!! REG_MCUFWDL:0x%08x .\n", - value32); - err = 0; - goto exit; - } - - mdelay(FW_8192C_POLLING_DELAY); - - } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT); - - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32); - -exit: - return err; -} - -int rtl8723ae_download_fw(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - struct rtl8723ae_firmware_header *pfwheader; - u8 *pfwdata; - u32 fwsize; - int err; - enum version_8723e version = rtlhal->version; - - if (!rtlhal->pfirmware) - return 1; - - pfwheader = (struct rtl8723ae_firmware_header *)rtlhal->pfirmware; - pfwdata = (u8 *) rtlhal->pfirmware; - fwsize = rtlhal->fwsize; - - if (IS_FW_HEADER_EXIST(pfwheader)) { - RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, - "Firmware Version(%d), Signature(%#x),Size(%d)\n", - pfwheader->version, pfwheader->signature, - (int)sizeof(struct rtl8723ae_firmware_header)); - - pfwdata = pfwdata + sizeof(struct rtl8723ae_firmware_header); - fwsize = fwsize - sizeof(struct rtl8723ae_firmware_header); - } - - if (rtl_read_byte(rtlpriv, REG_MCUFWDL)&BIT(7)) { - rtl8723ae_firmware_selfreset(hw); - rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); - } - _rtl8723ae_enable_fw_download(hw, true); - _rtl8723ae_write_fw(hw, version, pfwdata, fwsize); - _rtl8723ae_enable_fw_download(hw, false); - - err = _rtl8723ae_fw_free_to_go(hw); - if (err) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "Firmware is not ready to run!\n"); - } else { - RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, - "Firmware is ready to run!\n"); - } - return 0; -} +#include "../rtl8723com/fw_common.h" static bool rtl8723ae_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum) { @@ -463,50 +271,6 @@ void rtl8723ae_fill_h2c_cmd(struct ieee80211_hw *hw, return; } -void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw) -{ - u8 u1tmp; - u8 delay = 100; - struct rtl_priv *rtlpriv = rtl_priv(hw); - - rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20); - u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); - - while (u1tmp & BIT(2)) { - delay--; - if (delay == 0) - break; - udelay(50); - u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); - } - if (delay == 0) { - u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); - rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, u1tmp&(~BIT(2))); - } -} - -void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - u8 u1_h2c_set_pwrmode[3] = { 0 }; - struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - - RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode); - - SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode); - SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, - (rtlpriv->mac80211.p2p) ? - ppsc->smart_ps : 1); - SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode, - ppsc->reg_max_lps_awakeintvl); - - RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, - "rtl8723ae_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n", - u1_h2c_set_pwrmode, 3); - rtl8723ae_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode); - -} - static bool _rtl8723ae_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb) { @@ -812,7 +576,6 @@ void rtl8723ae_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state) rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4)); p2p_ps_offload->offload_en = 1; - if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) { p2p_ps_offload->role = 1; p2p_ps_offload->allstasleep = 0; @@ -836,3 +599,24 @@ void rtl8723ae_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state) } rtl8723ae_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload); } + +void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1_h2c_set_pwrmode[3] = { 0 }; + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode); + + SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode); + SET_H2CCMD_PWRMODE_PARM_SMART_PS_23A(u1_h2c_set_pwrmode, + (rtlpriv->mac80211.p2p) ? + ppsc->smart_ps : 1); + SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode, + ppsc->reg_max_lps_awakeintvl); + + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "rtl8723ae_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n", + u1_h2c_set_pwrmode, 3); + rtl8723ae_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h index ed3b795e6980..d355b85dd9fe 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h @@ -34,7 +34,7 @@ #define FW_8192C_END_ADDRESS 0x3FFF #define FW_8192C_PAGE_SIZE 4096 #define FW_8192C_POLLING_DELAY 5 -#define FW_8192C_POLLING_TIMEOUT_COUNT 1000 +#define FW_8192C_POLLING_TIMEOUT_COUNT 6000 #define BEACON_PG 0 #define PSPOLL_PG 2 @@ -65,21 +65,9 @@ struct rtl8723ae_firmware_header { u32 rsvd5; }; -enum rtl8192c_h2c_cmd { - H2C_AP_OFFLOAD = 0, - H2C_SETPWRMODE = 1, - H2C_JOINBSSRPT = 2, - H2C_RSVDPAGE = 3, - H2C_RSSI_REPORT = 4, - H2C_P2P_PS_CTW_CMD = 5, - H2C_P2P_PS_OFFLOAD = 6, - H2C_RA_MASK = 7, - MAX_H2CCMD -}; - #define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val) \ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) -#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__ph2ccmd, __val) \ +#define SET_H2CCMD_PWRMODE_PARM_SMART_PS_23A(__ph2ccmd, __val) \ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val) #define SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(__ph2ccmd, __val) \ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val) @@ -92,10 +80,8 @@ enum rtl8192c_h2c_cmd { #define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val) \ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val) -int rtl8723ae_download_fw(struct ieee80211_hw *hw); void rtl8723ae_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, u32 cmd_len, u8 *p_cmdbuffer); -void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw); void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); void rtl8723ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); void rtl8723ae_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c index 3d092e4b0b7f..48fee1be78c2 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c @@ -31,6 +31,8 @@ #include "../pci.h" #include "dm.h" #include "fw.h" +#include "../rtl8723com/fw_common.h" +#include "../rtl8723com/fw_common.h" #include "phy.h" #include "reg.h" #include "hal_btc.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c index 8b64b1cd3176..5d534df8d90c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c @@ -32,6 +32,7 @@ #include "phy.h" #include "../rtl8723com/phy_common.h" #include "fw.h" +#include "../rtl8723com/fw_common.h" #include "reg.h" #include "def.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c index 914b36f72d55..7eff1c51539c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c @@ -39,6 +39,7 @@ #include "phy.h" #include "dm.h" #include "fw.h" +#include "../rtl8723com/fw_common.h" #include "led.h" #include "hw.h" #include "pwrseqcmd.h" @@ -890,7 +891,7 @@ int rtl8723ae_hw_init(struct ieee80211_hw *hw) return err; } - err = rtl8723ae_download_fw(hw); + err = rtl8723_download_fw(hw, false); if (err) { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "Failed to download FW. Init HW without FW now..\n"); diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c index 0b97c9acebaa..1087a3bd07fa 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c @@ -40,6 +40,8 @@ #include "../rtl8723com/phy_common.h" #include "dm.h" #include "hw.h" +#include "fw.h" +#include "../rtl8723com/fw_common.h" #include "sw.h" #include "trx.h" #include "led.h" @@ -194,6 +196,11 @@ void rtl8723ae_deinit_sw_vars(struct ieee80211_hw *hw) } } +static bool is_fw_header(struct rtl92c_firmware_header *hdr) +{ + return (hdr->signature & 0xfff0) == 0x2300; +} + static struct rtl_hal_ops rtl8723ae_hal_ops = { .init_sw_vars = rtl8723ae_init_sw_vars, .deinit_sw_vars = rtl8723ae_deinit_sw_vars, @@ -239,6 +246,7 @@ static struct rtl_hal_ops rtl8723ae_hal_ops = { .c2h_command_handle = rtl_8723e_c2h_command_handle, .bt_wifi_media_status_notify = rtl_8723e_bt_wifi_media_status_notify, .bt_coex_off_before_lps = rtl8723ae_bt_coex_off_before_lps, + .is_fw_header = is_fw_header, }; static struct rtl_mod_params rtl8723ae_mod_params = { diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/Makefile b/drivers/net/wireless/rtlwifi/rtl8723com/Makefile index 00673c692e6b..97c7eaceb430 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723com/Makefile +++ b/drivers/net/wireless/rtlwifi/rtl8723com/Makefile @@ -1,5 +1,6 @@ rtl8723-common-objs := \ main.o \ + fw_common.o \ phy_common.o obj-$(CONFIG_RTL8723_COMMON) += rtl8723-common.o diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c index 83ca4e25ee50..32c390ffc7d2 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c @@ -24,126 +24,11 @@ *****************************************************************************/ #include "../wifi.h" +#include "../pci.h" +#include "../base.h" #include "fw_common.h" #include -#define BEACON_PG 0 /* ->1 */ -#define PSPOLL_PG 2 -#define NULL_PG 3 -#define PROBERSP_PG 4 /* ->5 */ - -#define TOTAL_RESERVED_PKT_LEN 768 - -static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = { - /* page 0 beacon */ - 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78, - 0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x20, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x64, 0x00, 0x10, 0x04, 0x00, 0x05, 0x54, 0x65, - 0x73, 0x74, 0x32, 0x01, 0x08, 0x82, 0x84, 0x0B, - 0x16, 0x24, 0x30, 0x48, 0x6C, 0x03, 0x01, 0x06, - 0x06, 0x02, 0x00, 0x00, 0x2A, 0x01, 0x02, 0x32, - 0x04, 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, - 0x09, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3D, 0x00, 0xDD, 0x07, 0x00, 0xE0, 0x4C, - 0x02, 0x02, 0x00, 0x00, 0xDD, 0x18, 0x00, 0x50, - 0xF2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, - 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, 0x01, 0x00, - - /* page 1 beacon */ - 0x00, 0x50, 0xF2, 0x02, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - /* page 2 ps-poll */ - 0xA4, 0x10, 0x01, 0xC0, 0xEC, 0x1A, 0x59, 0x0B, - 0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - /* page 3 null */ - 0x48, 0x01, 0x00, 0x00, 0xEC, 0x1A, 0x59, 0x0B, - 0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78, - 0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x72, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - /* page 4 probe_resp */ - 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, - 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, - 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, - 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00, - 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69, - 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C, - 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96, - 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A, - 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C, - 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02, - 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - /* page 5 probe_resp */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - void rtl8723_enable_fw_download(struct ieee80211_hw *hw, bool enable) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -226,7 +111,7 @@ static void rtl8723_fill_dummy(u8 *pfwbuf, u32 *pfwlen) } void rtl8723_write_fw(struct ieee80211_hw *hw, - enum version_8723be version, + enum version_8723e version, u8 *buffer, u32 size) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -236,7 +121,7 @@ void rtl8723_write_fw(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "FW size is %d bytes,\n", size); - _rtl8723be_fill_dummy(bufferptr, &size); + rtl8723_fill_dummy(bufferptr, &size); pagenums = size / FW_8192C_PAGE_SIZE; remainsize = size % FW_8192C_PAGE_SIZE; @@ -319,15 +204,14 @@ int rtl8723_fw_free_to_go(struct ieee80211_hw *hw, bool is_8723be) if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "chksum report faill ! REG_MCUFWDL:0x%08x .\n", + "chksum report fail ! REG_MCUFWDL:0x%08x .\n", value32); goto exit; } RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32); - value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); - value32 |= MCUFWDL_RDY; + value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL) | MCUFWDL_RDY; value32 &= ~WINTINI_RDY; rtl_write_dword(rtlpriv, REG_MCUFWDL, value32); @@ -378,8 +262,8 @@ int rtl8723_download_fw(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, "normal Firmware SIZE %d\n", fwsize); - if (IS_FW_HEADER_EXIST(pfwheader)) { - RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, + if (rtlpriv->cfg->ops->is_fw_header(pfwheader)) { + RT_TRACE(rtlpriv, COMP_FW, DBG_EMERG, "Firmware Version(%d), Signature(%#x), Size(%d)\n", pfwheader->version, pfwheader->signature, (int)sizeof(struct rtl92c_firmware_header)); @@ -394,9 +278,9 @@ int rtl8723_download_fw(struct ieee80211_hw *hw, else rtl8723ae_firmware_selfreset(hw); } - rtl8723_enable_fw_download(hw, is_8723be); + rtl8723_enable_fw_download(hw, true); rtl8723_write_fw(hw, version, pfwdata, fwsize); - rtl8723_enable_fw_download(hw, is_8723be); + rtl8723_enable_fw_download(hw, false); err = rtl8723_fw_free_to_go(hw, is_8723be); if (err) { @@ -410,219 +294,6 @@ int rtl8723_download_fw(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rtl8723_download_fw); -bool rtl8723_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - u8 val_hmetfr, val_mcutst_1; - bool result = false; - - val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR); - val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum)); - - if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0) - result = true; - return result; -} -EXPORT_SYMBOL_GPL(rtl8723_check_fw_read_last_h2c); - -void rtl8723_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id, - u32 cmd_len, u8 *p_cmdbuffer) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - u8 boxnum; - u16 box_reg = 0, box_extreg = 0; - u8 u1b_tmp; - bool isfw_read = false; - u8 buf_index = 0; - bool bwrite_sucess = false; - u8 wait_h2c_limit = 100; - u8 wait_writeh2c_limit = 100; - u8 boxcontent[4], boxextcontent[4]; - u32 h2c_waitcounter = 0; - unsigned long flag; - u8 idx; - - RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n"); - - while (true) { - spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); - if (rtlhal->h2c_setinprogress) { - RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, - "H2C set in progress! Wait to set.." - "element_id(%d).\n", element_id); - - while (rtlhal->h2c_setinprogress) { - spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, - flag); - h2c_waitcounter++; - RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, - "Wait 100 us (%d times)...\n", - h2c_waitcounter); - udelay(100); - - if (h2c_waitcounter > 1000) - return; - spin_lock_irqsave(&rtlpriv->locks.h2c_lock, - flag); - } - spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); - } else { - rtlhal->h2c_setinprogress = true; - spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); - break; - } - } - while (!bwrite_sucess) { - wait_writeh2c_limit--; - if (wait_writeh2c_limit == 0) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "Write H2C fail because no trigger " - "for FW INT!\n"); - break; - } - boxnum = rtlhal->last_hmeboxnum; - switch (boxnum) { - case 0: - box_reg = REG_HMEBOX_0; - box_extreg = REG_HMEBOX_EXT_0; - break; - case 1: - box_reg = REG_HMEBOX_1; - box_extreg = REG_HMEBOX_EXT_1; - break; - case 2: - box_reg = REG_HMEBOX_2; - box_extreg = REG_HMEBOX_EXT_2; - break; - case 3: - box_reg = REG_HMEBOX_3; - box_extreg = REG_HMEBOX_EXT_3; - break; - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "switch case not processed\n"); - break; - } - isfw_read = rtl8723_check_fw_read_last_h2c(hw, boxnum); - while (!isfw_read) { - wait_h2c_limit--; - if (wait_h2c_limit == 0) { - RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, - "Waiting too long for FW read " - "clear HMEBox(%d)!\n", boxnum); - break; - } - udelay(10); - - isfw_read = rtl8723_check_fw_read_last_h2c(hw, - boxnum); - } - if (!isfw_read) { - RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, - "Write H2C register BOX[%d] fail!!!!! " - "Fw do not read.\n", boxnum); - break; - } - memset(boxcontent, 0, sizeof(boxcontent)); - memset(boxextcontent, 0, sizeof(boxextcontent)); - boxcontent[0] = element_id; - RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, - "Write element_id box_reg(%4x) = %2x\n", - box_reg, element_id); - - switch (cmd_len) { - case 1: - case 2: - case 3: - /*boxcontent[0] &= ~(BIT(7));*/ - memcpy((u8 *)(boxcontent) + 1, - p_cmdbuffer + buf_index, cmd_len); - - for (idx = 0; idx < 4; idx++) { - rtl_write_byte(rtlpriv, box_reg + idx, - boxcontent[idx]); - } - break; - case 4: - case 5: - case 6: - case 7: - /*boxcontent[0] |= (BIT(7));*/ - memcpy((u8 *)(boxextcontent), - p_cmdbuffer + buf_index+3, cmd_len-3); - memcpy((u8 *)(boxcontent) + 1, - p_cmdbuffer + buf_index, 3); - - for (idx = 0; idx < 4; idx++) { - rtl_write_byte(rtlpriv, box_extreg + idx, - boxextcontent[idx]); - } - for (idx = 0; idx < 4; idx++) { - rtl_write_byte(rtlpriv, box_reg + idx, - boxcontent[idx]); - } - break; - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "switch case not process\n"); - break; - } - bwrite_sucess = true; - - rtlhal->last_hmeboxnum = boxnum + 1; - if (rtlhal->last_hmeboxnum == 4) - rtlhal->last_hmeboxnum = 0; - - RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, - "pHalData->last_hmeboxnum = %d\n", - rtlhal->last_hmeboxnum); - } - if (!rtlpriv) { - pr_err("rtlpriv bad\n"); - return; - } - if (!rtlhal) { - pr_err("rtlhal bad\n"); - return; - } - spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); - rtlhal->h2c_setinprogress = false; - spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); - - RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n"); -} -EXPORT_SYMBOL_GPL(rtl8723_fill_h2c_command); - -void rtl8723_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, - u32 cmd_len, u8 *p_cmdbuffer) -{ - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - u32 tmp_cmdbuf[2]; - - if (!rtlhal->fw_ready) { - RT_ASSERT(false, - "return H2C cmd because of Fw download fail!!!\n"); - return; - } - memset(tmp_cmdbuf, 0, 8); - memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len); - rtl8723_fill_h2c_command(hw, element_id, cmd_len, - (u8 *)&tmp_cmdbuf); - return; -} -EXPORT_SYMBOL_GPL(rtl8723_fill_h2c_cmd); - -void rtl8723_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus) -{ - u8 u1_joinbssrpt_parm[1] = { 0 }; - - SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus); - - rtl8723_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm); -} -EXPORT_SYMBOL_GPL(rtl8723_set_fw_joinbss_report_cmd); - bool rtl8723_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb) { @@ -656,194 +327,3 @@ bool rtl8723_cmd_send_packet(struct ieee80211_hw *hw, return true; } EXPORT_SYMBOL_GPL(rtl8723_cmd_send_packet); - -void rtl8723_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - struct sk_buff *skb = NULL; - - u32 totalpacketlen; - bool rtstatus; - u8 u1rsvdpageloc[5] = { 0 }; - bool dlok = false; - - u8 *beacon; - u8 *p_pspoll; - u8 *nullfunc; - u8 *p_probersp; - /*--------------------------------------------------------- - * (1) beacon - *--------------------------------------------------------- - */ - beacon = &reserved_page_packet[BEACON_PG * 128]; - SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr); - SET_80211_HDR_ADDRESS3(beacon, mac->bssid); - - /*------------------------------------------------------- - * (2) ps-poll - *------------------------------------------------------- - */ - p_pspoll = &reserved_page_packet[PSPOLL_PG * 128]; - SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000)); - SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid); - SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr); - - SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG); - - /*-------------------------------------------------------- - * (3) null data - *-------------------------------------------------------- - */ - nullfunc = &reserved_page_packet[NULL_PG * 128]; - SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid); - SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr); - SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid); - - SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG); - - /*--------------------------------------------------------- - * (4) probe response - *--------------------------------------------------------- - */ - p_probersp = &reserved_page_packet[PROBERSP_PG * 128]; - SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid); - SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr); - SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid); - - SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG); - - totalpacketlen = TOTAL_RESERVED_PKT_LEN; - - RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, - "rtl8723be_set_fw_rsvdpagepkt(): " - "HW_VAR_SET_TX_CMD: ALL\n", - &reserved_page_packet[0], totalpacketlen); - RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, - "rtl8723be_set_fw_rsvdpagepkt(): " - "HW_VAR_SET_TX_CMD: ALL\n", u1rsvdpageloc, 3); - - - skb = dev_alloc_skb(totalpacketlen); - memcpy((u8 *)skb_put(skb, totalpacketlen), - &reserved_page_packet, totalpacketlen); - - rtstatus = rtl8723_cmd_send_packet(hw, skb); - - if (rtstatus) - dlok = true; - - if (dlok) { - RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, - "Set RSVD page location to Fw.\n"); - RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, "H2C_RSVDPAGE:\n", - u1rsvdpageloc, 3); - rtl8723_fill_h2c_cmd(hw, H2C_88E_RSVDPAGE, - sizeof(u1rsvdpageloc), u1rsvdpageloc); - } else { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - "Set RSVD page location to Fw FAIL!!!!!!.\n"); - } -} -EXPORT_SYMBOL_GPL(rtl8723_set_fw_rsvdpagepkt); - -/*Should check FW support p2p or not.*/ -void rtl8723_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow) -{ - u8 u1_ctwindow_period[1] = {ctwindow}; - - rtl8723_fill_h2c_cmd(hw, H2C_88E_P2P_PS_CTW_CMD, 1, - u1_ctwindow_period); -} -EXPORT_SYMBOL_GPL(rtl8723_set_p2p_ctw_period_cmd); - -void rtl8723_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw)); - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info); - struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload; - u8 i; - u16 ctwindow; - u32 start_time, tsf_low; - - switch (p2p_ps_state) { - case P2P_PS_DISABLE: - RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n"); - memset(p2p_ps_offload, 0, sizeof(struct p2p_ps_offload_t *)); - break; - case P2P_PS_ENABLE: - RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n"); - /* update CTWindow value. */ - if (p2pinfo->ctwindow > 0) { - p2p_ps_offload->ctwindow_en = 1; - ctwindow = p2pinfo->ctwindow; - rtl8723_set_p2p_ctw_period_cmd(hw, ctwindow); - } - /* hw only support 2 set of NoA */ - for (i = 0; i < p2pinfo->noa_num; i++) { - /* To control the register setting - * for which NOA - */ - rtl_write_byte(rtlpriv, 0x5cf, (i << 4)); - if (i == 0) - p2p_ps_offload->noa0_en = 1; - else - p2p_ps_offload->noa1_en = 1; - - /* config P2P NoA Descriptor Register */ - rtl_write_dword(rtlpriv, 0x5E0, - p2pinfo->noa_duration[i]); - rtl_write_dword(rtlpriv, 0x5E4, - p2pinfo->noa_interval[i]); - - /*Get Current TSF value */ - tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR); - - start_time = p2pinfo->noa_start_time[i]; - if (p2pinfo->noa_count_type[i] != 1) { - while (start_time <= (tsf_low + (50 * 1024))) { - start_time += p2pinfo->noa_interval[i]; - if (p2pinfo->noa_count_type[i] != 255) - p2pinfo->noa_count_type[i]--; - } - } - rtl_write_dword(rtlpriv, 0x5E8, start_time); - rtl_write_dword(rtlpriv, 0x5EC, - p2pinfo->noa_count_type[i]); - } - if ((p2pinfo->opp_ps == 1) || - (p2pinfo->noa_num > 0)) { - /* rst p2p circuit */ - rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4)); - - p2p_ps_offload->offload_en = 1; - - if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) { - p2p_ps_offload->role = 1; - p2p_ps_offload->allstasleep = 0; - } else { - p2p_ps_offload->role = 0; - } - p2p_ps_offload->discovery = 0; - } - break; - case P2P_PS_SCAN: - RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n"); - p2p_ps_offload->discovery = 1; - break; - case P2P_PS_SCAN_DONE: - RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n"); - p2p_ps_offload->discovery = 0; - p2pinfo->p2p_ps_state = P2P_PS_ENABLE; - break; - default: - break; - } - rtl8723_fill_h2c_cmd(hw, H2C_88E_P2P_PS_OFFLOAD, 1, - (u8 *)p2p_ps_offload); -} -EXPORT_SYMBOL_GPL(rtl8723_set_p2p_ps_offload_cmd); - -#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h index 0890e5deddfa..cf1cc5804d06 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h @@ -24,27 +24,103 @@ *****************************************************************************/ #ifndef __FW_COMMON_H__ -#define __FW_COMMON_H__#endif +#define __FW_COMMON_H__ +#define REG_SYS_FUNC_EN 0x0002 +#define REG_MCUFWDL 0x0080 +#define FW_8192C_START_ADDRESS 0x1000 +#define FW_8192C_PAGE_SIZE 4096 +#define FW_8192C_POLLING_TIMEOUT_COUNT 6000 +#define FW_8192C_POLLING_DELAY 5 + +#define MCUFWDL_RDY BIT(1) +#define FWDL_CHKSUM_RPT BIT(2) +#define WINTINI_RDY BIT(6) + +#define REG_RSV_CTRL 0x001C +#define REG_HMETFR 0x01CC + +enum version_8723e { + VERSION_TEST_UMC_CHIP_8723 = 0x0081, + VERSION_NORMAL_UMC_CHIP_8723_1T1R_A_CUT = 0x0089, + VERSION_NORMAL_UMC_CHIP_8723_1T1R_B_CUT = 0x1089, + VERSION_TEST_CHIP_1T1R_8723B = 0x0106, + VERSION_NORMAL_SMIC_CHIP_1T1R_8723B = 0x010E, + VERSION_UNKNOWN = 0xFF, +}; + +enum rtl8723ae_h2c_cmd { + H2C_AP_OFFLOAD = 0, + H2C_SETPWRMODE = 1, + H2C_JOINBSSRPT = 2, + H2C_RSVDPAGE = 3, + H2C_RSSI_REPORT = 4, + H2C_P2P_PS_CTW_CMD = 5, + H2C_P2P_PS_OFFLOAD = 6, + H2C_RA_MASK = 7, + MAX_H2CCMD +}; + +enum rtl8723be_cmd { + H2C_8723BE_RSVDPAGE = 0, + H2C_8723BE_JOINBSSRPT = 1, + H2C_8723BE_SCAN = 2, + H2C_8723BE_KEEP_ALIVE_CTRL = 3, + H2C_8723BE_DISCONNECT_DECISION = 4, + H2C_8723BE_INIT_OFFLOAD = 6, + H2C_8723BE_AP_OFFLOAD = 8, + H2C_8723BE_BCN_RSVDPAGE = 9, + H2C_8723BE_PROBERSP_RSVDPAGE = 10, + + H2C_8723BE_SETPWRMODE = 0x20, + H2C_8723BE_PS_TUNING_PARA = 0x21, + H2C_8723BE_PS_TUNING_PARA2 = 0x22, + H2C_8723BE_PS_LPS_PARA = 0x23, + H2C_8723BE_P2P_PS_OFFLOAD = 0x24, + + H2C_8723BE_WO_WLAN = 0x80, + H2C_8723BE_REMOTE_WAKE_CTRL = 0x81, + H2C_8723BE_AOAC_GLOBAL_INFO = 0x82, + H2C_8723BE_AOAC_RSVDPAGE = 0x83, + H2C_8723BE_RSSI_REPORT = 0x42, + H2C_8723BE_RA_MASK = 0x40, + H2C_8723BE_SELECTIVE_SUSPEND_ROF_CMD, + H2C_8723BE_P2P_PS_MODE, + H2C_8723BE_PSD_RESULT, + /*Not defined CTW CMD for P2P yet*/ + H2C_8723BE_P2P_PS_CTW_CMD, + MAX_8723BE_H2CCMD +}; + +struct rtl92c_firmware_header { + u16 signature; + u8 category; + u8 function; + u16 version; + u8 subversion; + u8 rsvd1; + u8 month; + u8 date; + u8 hour; + u8 minute; + u16 ramcodesize; + u16 rsvd2; + u32 svnindex; + u32 rsvd3; + u32 rsvd4; + u32 rsvd5; +}; + +void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw); +void rtl8723be_firmware_selfreset(struct ieee80211_hw *hw); void rtl8723_enable_fw_download(struct ieee80211_hw *hw, bool enable); void rtl8723_fw_block_write(struct ieee80211_hw *hw, const u8 *buffer, u32 size); void rtl8723_fw_page_write(struct ieee80211_hw *hw, u32 page, const u8 *buffer, u32 size); void rtl8723_write_fw(struct ieee80211_hw *hw, - enum version_8723be version, + enum version_8723e version, u8 *buffer, u32 size); int rtl8723_fw_free_to_go(struct ieee80211_hw *hw, bool is_8723be); -int rtl8723_download_fw(struct ieee80211_hw *hw, - bool buse_wake_on_wlan_fw, bool is_8723be); -bool rtl8723_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum); -void rtl8723_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id, - u32 cmd_len, u8 *p_cmdbuffer); -void rtl8723_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, - u32 cmd_len, u8 *p_cmdbuffer); -void rtl8723_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); -bool rtl8723_cmd_send_packet(struct ieee80211_hw *hw, - struct sk_buff *skb); -void rtl8723_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished); -void rtl8723_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow); -void rtl8723_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state); +int rtl8723_download_fw(struct ieee80211_hw *hw, bool is_8723be); +#endif diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 3f52bf8abe00..2304c7f23361 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -1712,6 +1712,8 @@ struct rtl_tcb_desc { bool btx_enable_sw_calc_duration; }; +struct rtl92c_firmware_header; + struct rtl_hal_ops { int (*init_sw_vars) (struct ieee80211_hw *hw); void (*deinit_sw_vars) (struct ieee80211_hw *hw); @@ -1809,6 +1811,7 @@ struct rtl_hal_ops { void (*fill_h2c_cmd) (struct ieee80211_hw *hw, u8 element_id, u32 cmd_len, u8 *p_cmdbuffer); bool (*get_btc_status) (void); + bool (*is_fw_header) (struct rtl92c_firmware_header *hdr); }; struct rtl_intf_ops { From 57d9d9630a6b3f289ae87b1fc00e83ae44636766 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 28 Feb 2014 15:16:49 -0600 Subject: [PATCH 393/414] rtlwifi: rtl8723ae: rtl8723-common: Copy common dynamic power management code The drivers for RTL8723AE and RTL8723BE have some code in common. This commit copies the common power management routines into the shared code. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8723ae/dm.c | 42 ++---------- drivers/net/wireless/rtlwifi/rtl8723ae/dm.h | 1 - drivers/net/wireless/rtlwifi/rtl8723ae/hw.c | 5 +- .../net/wireless/rtlwifi/rtl8723com/Makefile | 1 + .../wireless/rtlwifi/rtl8723com/dm_common.c | 65 +++++++++++++++++++ .../wireless/rtlwifi/rtl8723com/dm_common.h | 33 ++++++++++ 6 files changed, 106 insertions(+), 41 deletions(-) create mode 100644 drivers/net/wireless/rtlwifi/rtl8723com/dm_common.c create mode 100644 drivers/net/wireless/rtlwifi/rtl8723com/dm_common.h diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c index a36eee28f9e7..863ddb3e2888 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c @@ -35,6 +35,7 @@ #include "def.h" #include "phy.h" #include "dm.h" +#include "../rtl8723com/dm_common.h" #include "fw.h" #include "hal_btc.h" @@ -483,16 +484,6 @@ static void rtl8723ae_dm_dig(struct ieee80211_hw *hw) rtl8723ae_dm_ctrl_initgain_by_twoport(hw); } -static void rtl8723ae_dm_init_dynamic_txpower(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - rtlpriv->dm.dynamic_txpower_enable = false; - - rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; - rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; -} - static void rtl8723ae_dm_dynamic_txpower(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -585,19 +576,6 @@ void rtl8723ae_dm_write_dig(struct ieee80211_hw *hw) } } -static void rtl8723ae_dm_pwdmonitor(struct ieee80211_hw *hw) -{ -} - -void rtl8723ae_dm_init_edca_turbo(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - rtlpriv->dm.current_turbo_edca = false; - rtlpriv->dm.is_any_nonbepkts = false; - rtlpriv->dm.is_cur_rdlstate = false; -} - static void rtl8723ae_dm_check_edca_turbo(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -778,17 +756,6 @@ static void rtl8723ae_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw) } } -static void rtl8723ae_dm_init_dynamic_bpowersaving(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - rtlpriv->dm_pstable.pre_ccastate = CCA_MAX; - rtlpriv->dm_pstable.cur_ccasate = CCA_MAX; - rtlpriv->dm_pstable.pre_rfstate = RF_MAX; - rtlpriv->dm_pstable.cur_rfstate = RF_MAX; - rtlpriv->dm_pstable.rssi_val_min = 0; -} - void rtl8723ae_dm_rf_saving(struct ieee80211_hw *hw, u8 force_in_normal) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -905,11 +872,11 @@ void rtl8723ae_dm_init(struct ieee80211_hw *hw) rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; rtl8723ae_dm_diginit(hw); - rtl8723ae_dm_init_dynamic_txpower(hw); - rtl8723ae_dm_init_edca_turbo(hw); + rtl8723_dm_init_dynamic_txpower(hw); + rtl8723_dm_init_edca_turbo(hw); rtl8723ae_dm_init_rate_adaptive_mask(hw); rtl8723ae_dm_initialize_txpower_tracking(hw); - rtl8723ae_dm_init_dynamic_bpowersaving(hw); + rtl8723_dm_init_dynamic_bb_powersaving(hw); } void rtl8723ae_dm_watchdog(struct ieee80211_hw *hw) @@ -930,7 +897,6 @@ void rtl8723ae_dm_watchdog(struct ieee80211_hw *hw) if ((ppsc->rfpwr_state == ERFON) && ((!fw_current_inpsmode) && fw_ps_awake) && (!ppsc->rfchange_inprogress)) { - rtl8723ae_dm_pwdmonitor(hw); rtl8723ae_dm_dig(hw); rtl8723ae_dm_false_alarm_counter_statistics(hw); rtl8723ae_dm_dynamic_bpowersaving(hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h index a372b0204456..d253bb53d03e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h @@ -147,7 +147,6 @@ enum dm_dig_connect_e { void rtl8723ae_dm_init(struct ieee80211_hw *hw); void rtl8723ae_dm_watchdog(struct ieee80211_hw *hw); void rtl8723ae_dm_write_dig(struct ieee80211_hw *hw); -void rtl8723ae_dm_init_edca_turbo(struct ieee80211_hw *hw); void rtl8723ae_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw); void rtl8723ae_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal); void rtl8723ae_dm_bt_coexist(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c index 7eff1c51539c..8a8577a1783b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c @@ -38,6 +38,7 @@ #include "def.h" #include "phy.h" #include "dm.h" +#include "../rtl8723com/dm_common.h" #include "fw.h" #include "../rtl8723com/fw_common.h" #include "led.h" @@ -305,7 +306,7 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) break; } case HW_VAR_AC_PARAM:{ u8 e_aci = *((u8 *) val); - rtl8723ae_dm_init_edca_turbo(hw); + rtl8723_dm_init_edca_turbo(hw); if (rtlpci->acm_method != EACMWAY2_SW) rtlpriv->cfg->ops->set_hw_reg(hw, @@ -1155,7 +1156,7 @@ void rtl8723ae_set_qos(struct ieee80211_hw *hw, int aci) { struct rtl_priv *rtlpriv = rtl_priv(hw); - rtl8723ae_dm_init_edca_turbo(hw); + rtl8723_dm_init_edca_turbo(hw); switch (aci) { case AC1_BK: rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f); diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/Makefile b/drivers/net/wireless/rtlwifi/rtl8723com/Makefile index 97c7eaceb430..345a68adcf38 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723com/Makefile +++ b/drivers/net/wireless/rtlwifi/rtl8723com/Makefile @@ -1,5 +1,6 @@ rtl8723-common-objs := \ main.o \ + dm_common.o \ fw_common.o \ phy_common.o diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.c new file mode 100644 index 000000000000..4e254b72bf45 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.c @@ -0,0 +1,65 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "dm_common.h" +#include "../rtl8723ae/dm.h" +#include + +/* These routines are common to RTL8723AE and RTL8723bE */ + +void rtl8723_dm_init_dynamic_txpower(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.dynamic_txpower_enable = false; + + rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; +} +EXPORT_SYMBOL_GPL(rtl8723_dm_init_dynamic_txpower); + +void rtl8723_dm_init_edca_turbo(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.current_turbo_edca = false; + rtlpriv->dm.is_any_nonbepkts = false; + rtlpriv->dm.is_cur_rdlstate = false; +} +EXPORT_SYMBOL_GPL(rtl8723_dm_init_edca_turbo); + +void rtl8723_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm_pstable.pre_ccastate = CCA_MAX; + rtlpriv->dm_pstable.cur_ccasate = CCA_MAX; + rtlpriv->dm_pstable.pre_rfstate = RF_MAX; + rtlpriv->dm_pstable.cur_rfstate = RF_MAX; + rtlpriv->dm_pstable.rssi_val_min = 0; + rtlpriv->dm_pstable.initialize = 0; +} +EXPORT_SYMBOL_GPL(rtl8723_dm_init_dynamic_bb_powersaving); diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.h b/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.h new file mode 100644 index 000000000000..5c1b94ce2f86 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.h @@ -0,0 +1,33 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __DM_COMMON_H__ +#define __DM_COMMON_H__ + +void rtl8723_dm_init_dynamic_txpower(struct ieee80211_hw *hw); +void rtl8723_dm_init_edca_turbo(struct ieee80211_hw *hw); +void rtl8723_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw); + +#endif From a619d1abe20cc892ddd8f6f60345b24d43971fb4 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 28 Feb 2014 15:16:50 -0600 Subject: [PATCH 394/414] rtlwifi: rtl8723be: Add new driver Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/Kconfig | 19 +- drivers/net/wireless/rtlwifi/Makefile | 1 + .../net/wireless/rtlwifi/rtl8723be/Makefile | 20 + drivers/net/wireless/rtlwifi/rtl8723be/def.h | 248 ++ drivers/net/wireless/rtlwifi/rtl8723be/dm.c | 1325 +++++++++ drivers/net/wireless/rtlwifi/rtl8723be/dm.h | 310 ++ drivers/net/wireless/rtlwifi/rtl8723be/fw.c | 628 ++++ drivers/net/wireless/rtlwifi/rtl8723be/fw.h | 248 ++ drivers/net/wireless/rtlwifi/rtl8723be/hw.c | 2529 +++++++++++++++++ drivers/net/wireless/rtlwifi/rtl8723be/hw.h | 64 + drivers/net/wireless/rtlwifi/rtl8723be/led.c | 153 + drivers/net/wireless/rtlwifi/rtl8723be/led.h | 35 + drivers/net/wireless/rtlwifi/rtl8723be/phy.c | 2175 ++++++++++++++ drivers/net/wireless/rtlwifi/rtl8723be/phy.h | 217 ++ .../net/wireless/rtlwifi/rtl8723be/pwrseq.c | 106 + .../net/wireless/rtlwifi/rtl8723be/pwrseq.h | 305 ++ .../wireless/rtlwifi/rtl8723be/pwrseqcmd.c | 140 + .../wireless/rtlwifi/rtl8723be/pwrseqcmd.h | 95 + drivers/net/wireless/rtlwifi/rtl8723be/reg.h | 2293 +++++++++++++++ drivers/net/wireless/rtlwifi/rtl8723be/rf.c | 504 ++++ drivers/net/wireless/rtlwifi/rtl8723be/rf.h | 43 + drivers/net/wireless/rtlwifi/rtl8723be/sw.c | 385 +++ drivers/net/wireless/rtlwifi/rtl8723be/sw.h | 35 + .../net/wireless/rtlwifi/rtl8723be/table.c | 572 ++++ .../net/wireless/rtlwifi/rtl8723be/table.h | 43 + drivers/net/wireless/rtlwifi/rtl8723be/trx.c | 959 +++++++ drivers/net/wireless/rtlwifi/rtl8723be/trx.h | 616 ++++ 27 files changed, 14065 insertions(+), 3 deletions(-) create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/Makefile create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/def.h create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/dm.c create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/dm.h create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/fw.c create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/fw.h create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/hw.c create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/hw.h create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/led.c create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/led.h create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/phy.c create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/phy.h create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.c create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.c create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.h create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/reg.h create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/rf.c create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/rf.h create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/sw.c create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/sw.h create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/table.c create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/table.h create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/trx.c create mode 100644 drivers/net/wireless/rtlwifi/rtl8723be/trx.h diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig index 9251e0d3685c..bf3cf124e4ea 100644 --- a/drivers/net/wireless/rtlwifi/Kconfig +++ b/drivers/net/wireless/rtlwifi/Kconfig @@ -5,7 +5,7 @@ menuconfig RTL_CARDS ---help--- This option will enable support for the Realtek mac80211-based wireless drivers. Drivers rtl8192ce, rtl8192cu, rtl8192se, rtl8192de, - rtl8723ae, and rtl8188ae share some common code. + rtl8723ae, rtl8723be, and rtl8188ae share some common code. if RTL_CARDS @@ -56,6 +56,19 @@ config RTL8723AE If you choose to build it as a module, it will be called rtl8723ae +config RTL8723BE + tristate "Realtek RTL8723BE PCIe Wireless Network Adapter" + depends on PCI + select RTLWIFI + select RTLWIFI_PCI + select RTL8723_COMMON + select RTLBTCOEXIST + ---help--- + This is the driver for Realtek RTL8723BE 802.11n PCIe + wireless network adapters. + + If you choose to build it as a module, it will be called rtl8723be + config RTL8188EE tristate "Realtek RTL8188EE Wireless Network Adapter" depends on PCI @@ -105,12 +118,12 @@ config RTL8192C_COMMON config RTL8723_COMMON tristate - depends on RTL8723AE + depends on RTL8723AE || RTL8723BE default y config RTLBTCOEXIST tristate - depends on RTL8723AE + depends on RTL8723AE || RTL8723BE default y endif diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile index d97d1b9d2427..bba36a06abcc 100644 --- a/drivers/net/wireless/rtlwifi/Makefile +++ b/drivers/net/wireless/rtlwifi/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_RTL8192CU) += rtl8192cu/ obj-$(CONFIG_RTL8192SE) += rtl8192se/ obj-$(CONFIG_RTL8192DE) += rtl8192de/ obj-$(CONFIG_RTL8723AE) += rtl8723ae/ +obj-$(CONFIG_RTL8723BE) += rtl8723be/ obj-$(CONFIG_RTL8188EE) += rtl8188ee/ obj-$(CONFIG_RTLBTCOEXIST) += btcoexist/ obj-$(CONFIG_RTL8723_COMMON) += rtl8723com/ diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/Makefile b/drivers/net/wireless/rtlwifi/rtl8723be/Makefile new file mode 100644 index 000000000000..4a75aab0539a --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/Makefile @@ -0,0 +1,20 @@ +obj-m := rtl8723be.o + + +rtl8723be-objs := \ + dm.o \ + fw.o \ + hw.o \ + led.o \ + phy.o \ + pwrseq.o \ + pwrseqcmd.o \ + rf.o \ + sw.o \ + table.o \ + trx.o \ + + +obj-$(CONFIG_RTL8723BE) += rtl8723be.o + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/def.h b/drivers/net/wireless/rtlwifi/rtl8723be/def.h new file mode 100644 index 000000000000..3c30b74e983d --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/def.h @@ -0,0 +1,248 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8723BE_DEF_H__ +#define __RTL8723BE_DEF_H__ + +#define HAL_RETRY_LIMIT_INFRA 48 +#define HAL_RETRY_LIMIT_AP_ADHOC 7 + +#define RESET_DELAY_8185 20 + +#define RT_IBSS_INT_MASKS (IMR_BCNINT | IMR_TBDOK | IMR_TBDER) +#define RT_AC_INT_MASKS (IMR_VIDOK | IMR_VODOK | IMR_BEDOK|IMR_BKDOK) + +#define NUM_OF_FIRMWARE_QUEUE 10 +#define NUM_OF_PAGES_IN_FW 0x100 +#define NUM_OF_PAGE_IN_FW_QUEUE_BK 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_BE 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_VI 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_VO 0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA 0x0 +#define NUM_OF_PAGE_IN_FW_QUEUE_CMD 0x0 +#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT 0x02 +#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH 0x02 +#define NUM_OF_PAGE_IN_FW_QUEUE_BCN 0x2 +#define NUM_OF_PAGE_IN_FW_QUEUE_PUB 0xA1 + +#define NUM_OF_PAGE_IN_FW_QUEUE_BK_DTM 0x026 +#define NUM_OF_PAGE_IN_FW_QUEUE_BE_DTM 0x048 +#define NUM_OF_PAGE_IN_FW_QUEUE_VI_DTM 0x048 +#define NUM_OF_PAGE_IN_FW_QUEUE_VO_DTM 0x026 +#define NUM_OF_PAGE_IN_FW_QUEUE_PUB_DTM 0x00 + +#define MAX_LINES_HWCONFIG_TXT 1000 +#define MAX_BYTES_LINE_HWCONFIG_TXT 256 + +#define SW_THREE_WIRE 0 +#define HW_THREE_WIRE 2 + +#define BT_DEMO_BOARD 0 +#define BT_QA_BOARD 1 +#define BT_FPGA 2 + +#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0 +#define HAL_PRIME_CHNL_OFFSET_LOWER 1 +#define HAL_PRIME_CHNL_OFFSET_UPPER 2 + +#define MAX_H2C_QUEUE_NUM 10 + +#define RX_MPDU_QUEUE 0 +#define RX_CMD_QUEUE 1 +#define RX_MAX_QUEUE 2 +#define AC2QUEUEID(_AC) (_AC) + +#define C2H_RX_CMD_HDR_LEN 8 +#define GET_C2H_CMD_CMD_LEN(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 0, 16) +#define GET_C2H_CMD_ELEMENT_ID(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 16, 8) +#define GET_C2H_CMD_CMD_SEQ(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 24, 7) +#define GET_C2H_CMD_CONTINUE(__prxhdr) \ + LE_BITS_TO_4BYTE((__prxhdr), 31, 1) +#define GET_C2H_CMD_CONTENT(__prxhdr) \ + ((u8 *)(__prxhdr) + C2H_RX_CMD_HDR_LEN) + +#define GET_C2H_CMD_FEEDBACK_ELEMENT_ID(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE((__pcmdfbhdr), 0, 8) +#define GET_C2H_CMD_FEEDBACK_CCX_LEN(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE((__pcmdfbhdr), 8, 8) +#define GET_C2H_CMD_FEEDBACK_CCX_CMD_CNT(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE((__pcmdfbhdr), 16, 16) +#define GET_C2H_CMD_FEEDBACK_CCX_MAC_ID(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 0, 5) +#define GET_C2H_CMD_FEEDBACK_CCX_VALID(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 7, 1) +#define GET_C2H_CMD_FEEDBACK_CCX_RETRY_CNT(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 8, 5) +#define GET_C2H_CMD_FEEDBACK_CCX_TOK(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 15, 1) +#define GET_C2H_CMD_FEEDBACK_CCX_QSEL(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 16, 4) +#define GET_C2H_CMD_FEEDBACK_CCX_SEQ(__pcmdfbhdr) \ + LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12) + +#define CHIP_BONDING_IDENTIFIER(_value) (((_value)>>22)&0x3) +#define CHIP_BONDING_92C_1T2R 0x1 + +#define CHIP_8723 BIT(0) +#define CHIP_8723B (BIT(1) | BIT(2)) +#define NORMAL_CHIP BIT(3) +#define RF_TYPE_1T1R (~(BIT(4) | BIT(5) | BIT(6))) +#define RF_TYPE_1T2R BIT(4) +#define RF_TYPE_2T2R BIT(5) +#define CHIP_VENDOR_UMC BIT(7) +#define B_CUT_VERSION BIT(12) +#define C_CUT_VERSION BIT(13) +#define D_CUT_VERSION ((BIT(12) | BIT(13))) +#define E_CUT_VERSION BIT(14) +#define RF_RL_ID (BIT(31) | BIT(30) | BIT(29) | BIT(28)) + +/* MASK */ +#define IC_TYPE_MASK (BIT(0) | BIT(1) | BIT(2)) +#define CHIP_TYPE_MASK BIT(3) +#define RF_TYPE_MASK (BIT(4) | BIT(5) | BIT(6)) +#define MANUFACTUER_MASK BIT(7) +#define ROM_VERSION_MASK (BIT(11) | BIT(10) | BIT(9) | BIT(8)) +#define CUT_VERSION_MASK (BIT(15) | BIT(14) | BIT(13) | BIT(12)) + +/* Get element */ +#define GET_CVID_IC_TYPE(version) ((version) & IC_TYPE_MASK) +#define GET_CVID_CHIP_TYPE(version) ((version) & CHIP_TYPE_MASK) +#define GET_CVID_RF_TYPE(version) ((version) & RF_TYPE_MASK) +#define GET_CVID_MANUFACTUER(version) ((version) & MANUFACTUER_MASK) +#define GET_CVID_ROM_VERSION(version) ((version) & ROM_VERSION_MASK) +#define GET_CVID_CUT_VERSION(version) ((version) & CUT_VERSION_MASK) + +#define IS_92C_SERIAL(version) ((IS_81XXC(version) && IS_2T2R(version)) ?\ + true : false) +#define IS_81XXC(version) ((GET_CVID_IC_TYPE(version) == 0) ?\ + true : false) +#define IS_8723_SERIES(version) ((GET_CVID_IC_TYPE(version) == CHIP_8723) ?\ + true : false) +#define IS_1T1R(version) ((GET_CVID_RF_TYPE(version)) ? false : true) +#define IS_1T2R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R)\ + ? true : false) +#define IS_2T2R(version) ((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R)\ + ? true : false) +enum rf_optype { + RF_OP_BY_SW_3WIRE = 0, + RF_OP_BY_FW, + RF_OP_MAX +}; + +enum rf_power_state { + RF_ON, + RF_OFF, + RF_SLEEP, + RF_SHUT_DOWN, +}; + +enum power_save_mode { + POWER_SAVE_MODE_ACTIVE, + POWER_SAVE_MODE_SAVE, +}; + +enum power_polocy_config { + POWERCFG_MAX_POWER_SAVINGS, + POWERCFG_GLOBAL_POWER_SAVINGS, + POWERCFG_LOCAL_POWER_SAVINGS, + POWERCFG_LENOVO, +}; + +enum interface_select_pci { + INTF_SEL1_MINICARD = 0, + INTF_SEL0_PCIE = 1, + INTF_SEL2_RSV = 2, + INTF_SEL3_RSV = 3, +}; + +enum rtl_desc_qsel { + QSLT_BK = 0x2, + QSLT_BE = 0x0, + QSLT_VI = 0x5, + QSLT_VO = 0x7, + QSLT_BEACON = 0x10, + QSLT_HIGH = 0x11, + QSLT_MGNT = 0x12, + QSLT_CMD = 0x13, +}; + +enum rtl_desc8723e_rate { + DESC92C_RATE1M = 0x00, + DESC92C_RATE2M = 0x01, + DESC92C_RATE5_5M = 0x02, + DESC92C_RATE11M = 0x03, + + DESC92C_RATE6M = 0x04, + DESC92C_RATE9M = 0x05, + DESC92C_RATE12M = 0x06, + DESC92C_RATE18M = 0x07, + DESC92C_RATE24M = 0x08, + DESC92C_RATE36M = 0x09, + DESC92C_RATE48M = 0x0a, + DESC92C_RATE54M = 0x0b, + + DESC92C_RATEMCS0 = 0x0c, + DESC92C_RATEMCS1 = 0x0d, + DESC92C_RATEMCS2 = 0x0e, + DESC92C_RATEMCS3 = 0x0f, + DESC92C_RATEMCS4 = 0x10, + DESC92C_RATEMCS5 = 0x11, + DESC92C_RATEMCS6 = 0x12, + DESC92C_RATEMCS7 = 0x13, + DESC92C_RATEMCS8 = 0x14, + DESC92C_RATEMCS9 = 0x15, + DESC92C_RATEMCS10 = 0x16, + DESC92C_RATEMCS11 = 0x17, + DESC92C_RATEMCS12 = 0x18, + DESC92C_RATEMCS13 = 0x19, + DESC92C_RATEMCS14 = 0x1a, + DESC92C_RATEMCS15 = 0x1b, + DESC92C_RATEMCS15_SG = 0x1c, + DESC92C_RATEMCS32 = 0x20, +}; + +enum rx_packet_type { + NORMAL_RX, + TX_REPORT1, + TX_REPORT2, + HIS_REPORT, +}; + +struct phy_sts_cck_8723e_t { + u8 adc_pwdb_X[4]; + u8 sq_rpt; + u8 cck_agc_rpt; +}; + +struct h2c_cmd_8723e { + u8 element_id; + u32 cmd_len; + u8 *p_cmdbuffer; +}; + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c new file mode 100644 index 000000000000..736bfcb7938a --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c @@ -0,0 +1,1325 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../base.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "../rtl8723com/dm_common.h" +#include "fw.h" +#include "../rtl8723com/fw_common.h" +#include "trx.h" +#include "../btcoexist/rtl_btc.h" + +static const u32 ofdmswing_table[] = { + 0x0b40002d, /* 0, -15.0dB */ + 0x0c000030, /* 1, -14.5dB */ + 0x0cc00033, /* 2, -14.0dB */ + 0x0d800036, /* 3, -13.5dB */ + 0x0e400039, /* 4, -13.0dB */ + 0x0f00003c, /* 5, -12.5dB */ + 0x10000040, /* 6, -12.0dB */ + 0x11000044, /* 7, -11.5dB */ + 0x12000048, /* 8, -11.0dB */ + 0x1300004c, /* 9, -10.5dB */ + 0x14400051, /* 10, -10.0dB */ + 0x15800056, /* 11, -9.5dB */ + 0x16c0005b, /* 12, -9.0dB */ + 0x18000060, /* 13, -8.5dB */ + 0x19800066, /* 14, -8.0dB */ + 0x1b00006c, /* 15, -7.5dB */ + 0x1c800072, /* 16, -7.0dB */ + 0x1e400079, /* 17, -6.5dB */ + 0x20000080, /* 18, -6.0dB */ + 0x22000088, /* 19, -5.5dB */ + 0x24000090, /* 20, -5.0dB */ + 0x26000098, /* 21, -4.5dB */ + 0x288000a2, /* 22, -4.0dB */ + 0x2ac000ab, /* 23, -3.5dB */ + 0x2d4000b5, /* 24, -3.0dB */ + 0x300000c0, /* 25, -2.5dB */ + 0x32c000cb, /* 26, -2.0dB */ + 0x35c000d7, /* 27, -1.5dB */ + 0x390000e4, /* 28, -1.0dB */ + 0x3c8000f2, /* 29, -0.5dB */ + 0x40000100, /* 30, +0dB */ + 0x43c0010f, /* 31, +0.5dB */ + 0x47c0011f, /* 32, +1.0dB */ + 0x4c000130, /* 33, +1.5dB */ + 0x50800142, /* 34, +2.0dB */ + 0x55400155, /* 35, +2.5dB */ + 0x5a400169, /* 36, +3.0dB */ + 0x5fc0017f, /* 37, +3.5dB */ + 0x65400195, /* 38, +4.0dB */ + 0x6b8001ae, /* 39, +4.5dB */ + 0x71c001c7, /* 40, +5.0dB */ + 0x788001e2, /* 41, +5.5dB */ + 0x7f8001fe /* 42, +6.0dB */ +}; + +static const u8 cckswing_table_ch1ch13[CCK_TABLE_SIZE][8] = { + {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01}, /* 0, -16.0dB */ + {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /* 1, -15.5dB */ + {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 2, -15.0dB */ + {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 3, -14.5dB */ + {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 4, -14.0dB */ + {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 5, -13.5dB */ + {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /* 6, -13.0dB */ + {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /* 7, -12.5dB */ + {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /* 8, -12.0dB */ + {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /* 9, -11.5dB */ + {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 10, -11.0dB */ + {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 11, -10.5dB */ + {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 12, -10.0dB */ + {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 13, -9.5dB */ + {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 14, -9.0dB */ + {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /* 15, -8.5dB */ + {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 16, -8.0dB */ + {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /* 17, -7.5dB */ + {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 18, -7.0dB */ + {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /* 19, -6.5dB */ + {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /* 20, -6.0dB */ + {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /* 21, -5.5dB */ + {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 22, -5.0dB */ + {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /* 23, -4.5dB */ + {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 24, -4.0dB */ + {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /* 25, -3.5dB */ + {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 26, -3.0dB */ + {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /* 27, -2.5dB */ + {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 28, -2.0dB */ + {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /* 29, -1.5dB */ + {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 30, -1.0dB */ + {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /* 31, -0.5dB */ + {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04} /* 32, +0dB */ +}; + +static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = { + {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00}, /* 0, -16.0dB */ + {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 1, -15.5dB */ + {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 2, -15.0dB */ + {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 3, -14.5dB */ + {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 4, -14.0dB */ + {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 5, -13.5dB */ + {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 6, -13.0dB */ + {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 7, -12.5dB */ + {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 8, -12.0dB */ + {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 9, -11.5dB */ + {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 10, -11.0dB */ + {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 11, -10.5dB */ + {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 12, -10.0dB */ + {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 13, -9.5dB */ + {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 14, -9.0dB */ + {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 15, -8.5dB */ + {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 16, -8.0dB */ + {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 17, -7.5dB */ + {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 18, -7.0dB */ + {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /* 19, -6.5dB */ + {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 20, -6.0dB */ + {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 21, -5.5dB */ + {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 22, -5.0dB */ + {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /* 23, -4.5dB */ + {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 24, -4.0dB */ + {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /* 25, -3.5dB */ + {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 26, -3.0dB */ + {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /* 27, -2.5dB */ + {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 28, -2.0dB */ + {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /* 29, -1.5dB */ + {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 30, -1.0dB */ + {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /* 31, -0.5dB */ + {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00} /* 32, +0dB */ +}; + +static const u32 edca_setting_dl[PEER_MAX] = { + 0xa44f, /* 0 UNKNOWN */ + 0x5ea44f, /* 1 REALTEK_90 */ + 0x5e4322, /* 2 REALTEK_92SE */ + 0x5ea42b, /* 3 BROAD */ + 0xa44f, /* 4 RAL */ + 0xa630, /* 5 ATH */ + 0x5ea630, /* 6 CISCO */ + 0x5ea42b, /* 7 MARVELL */ +}; + +static const u32 edca_setting_ul[PEER_MAX] = { + 0x5e4322, /* 0 UNKNOWN */ + 0xa44f, /* 1 REALTEK_90 */ + 0x5ea44f, /* 2 REALTEK_92SE */ + 0x5ea32b, /* 3 BROAD */ + 0x5ea422, /* 4 RAL */ + 0x5ea322, /* 5 ATH */ + 0x3ea430, /* 6 CISCO */ + 0x5ea44f, /* 7 MARV */ +}; + +void rtl8723be_dm_txpower_track_adjust(struct ieee80211_hw *hw, u8 type, + u8 *pdirection, u32 *poutwrite_val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + u8 pwr_val = 0; + u8 ofdm_base = rtlpriv->dm.swing_idx_ofdm_base[RF90_PATH_A]; + u8 ofdm_val = rtlpriv->dm.swing_idx_ofdm[RF90_PATH_A]; + u8 cck_base = rtldm->swing_idx_cck_base; + u8 cck_val = rtldm->swing_idx_cck; + + if (type == 0) { + if (ofdm_val <= ofdm_base) { + *pdirection = 1; + pwr_val = ofdm_base - ofdm_val; + } else { + *pdirection = 2; + pwr_val = ofdm_val - ofdm_base; + } + } else if (type == 1) { + if (cck_val <= cck_base) { + *pdirection = 1; + pwr_val = cck_base - cck_val; + } else { + *pdirection = 2; + pwr_val = cck_val - cck_base; + } + } + + if (pwr_val >= TXPWRTRACK_MAX_IDX && (*pdirection == 1)) + pwr_val = TXPWRTRACK_MAX_IDX; + + *poutwrite_val = pwr_val | (pwr_val << 8) | + (pwr_val << 16) | (pwr_val << 24); +} + +static void rtl8723be_dm_diginit(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *dm_digtable = &rtlpriv->dm_digtable; + + dm_digtable->dig_enable_flag = true; + dm_digtable->cur_igvalue = rtl_get_bbreg(hw, + ROFDM0_XAAGCCORE1, 0x7f); + dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW; + dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH; + dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; + dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; + dm_digtable->rx_gain_max = DM_DIG_MAX; + dm_digtable->rx_gain_min = DM_DIG_MIN; + dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT; + dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX; + dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN; + dm_digtable->pre_cck_cca_thres = 0xff; + dm_digtable->cur_cck_cca_thres = 0x83; + dm_digtable->forbidden_igi = DM_DIG_MIN; + dm_digtable->large_fa_hit = 0; + dm_digtable->recover_cnt = 0; + dm_digtable->dig_min_0 = DM_DIG_MIN; + dm_digtable->dig_min_1 = DM_DIG_MIN; + dm_digtable->media_connect_0 = false; + dm_digtable->media_connect_1 = false; + rtlpriv->dm.dm_initialgain_enable = true; + dm_digtable->bt30_cur_igi = 0x32; +} + +void rtl8723be_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rate_adaptive *ra = &(rtlpriv->ra); + + ra->ratr_state = DM_RATR_STA_INIT; + ra->pre_ratr_state = DM_RATR_STA_INIT; + + if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER) + rtlpriv->dm.useramask = true; + else + rtlpriv->dm.useramask = false; + + ra->high_rssi_thresh_for_ra = 50; + ra->low_rssi_thresh_for_ra40m = 20; +} + +static void rtl8723be_dm_init_txpower_tracking(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.txpower_tracking = true; + rtlpriv->dm.txpower_track_control = true; + rtlpriv->dm.thermalvalue = 0; + + rtlpriv->dm.ofdm_index[0] = 30; + rtlpriv->dm.cck_index = 20; + + rtlpriv->dm.swing_idx_cck_base = rtlpriv->dm.cck_index; + + rtlpriv->dm.swing_idx_ofdm_base[0] = rtlpriv->dm.ofdm_index[0]; + rtlpriv->dm.delta_power_index[RF90_PATH_A] = 0; + rtlpriv->dm.delta_power_index_last[RF90_PATH_A] = 0; + rtlpriv->dm.power_index_offset[RF90_PATH_A] = 0; + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + " rtlpriv->dm.txpower_tracking = %d\n", + rtlpriv->dm.txpower_tracking); +} + +static void rtl8723be_dm_init_dynamic_atc_switch(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.crystal_cap = rtlpriv->efuse.crystalcap; + rtlpriv->dm.atc_status = rtl_get_bbreg(hw, ROFDM1_CFOTRACKING, 0x800); + rtlpriv->dm.cfo_threshold = CFO_THRESHOLD_XTAL; +} + +void rtl8723be_dm_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; + rtl8723be_dm_diginit(hw); + rtl8723be_dm_init_rate_adaptive_mask(hw); + rtl8723_dm_init_edca_turbo(hw); + rtl8723_dm_init_dynamic_bb_powersaving(hw); + rtl8723_dm_init_dynamic_txpower(hw); + rtl8723be_dm_init_txpower_tracking(hw); + rtl8723be_dm_init_dynamic_atc_switch(hw); +} + +static void rtl8723be_dm_find_minimum_rssi(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *rtl_dm_dig = &(rtlpriv->dm_digtable); + struct rtl_mac *mac = rtl_mac(rtlpriv); + + /* Determine the minimum RSSI */ + if ((mac->link_state < MAC80211_LINKED) && + (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) { + rtl_dm_dig->min_undec_pwdb_for_dm = 0; + RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD, + "Not connected to any\n"); + } + if (mac->link_state >= MAC80211_LINKED) { + if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + rtl_dm_dig->min_undec_pwdb_for_dm = + rtlpriv->dm.entry_min_undec_sm_pwdb; + RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD, + "AP Client PWDB = 0x%lx\n", + rtlpriv->dm.entry_min_undec_sm_pwdb); + } else { + rtl_dm_dig->min_undec_pwdb_for_dm = + rtlpriv->dm.undec_sm_pwdb; + RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD, + "STA Default Port PWDB = 0x%x\n", + rtl_dm_dig->min_undec_pwdb_for_dm); + } + } else { + rtl_dm_dig->min_undec_pwdb_for_dm = + rtlpriv->dm.entry_min_undec_sm_pwdb; + RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD, + "AP Ext Port or disconnet PWDB = 0x%x\n", + rtl_dm_dig->min_undec_pwdb_for_dm); + } + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "MinUndecoratedPWDBForDM =%d\n", + rtl_dm_dig->min_undec_pwdb_for_dm); +} + +static void rtl8723be_dm_check_rssi_monitor(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_sta_info *drv_priv; + u8 h2c_parameter[3] = { 0 }; + long tmp_entry_max_pwdb = 0, tmp_entry_min_pwdb = 0xff; + + /* AP & ADHOC & MESH */ + spin_lock_bh(&rtlpriv->locks.entry_list_lock); + list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) { + if (drv_priv->rssi_stat.undec_sm_pwdb < + tmp_entry_min_pwdb) + tmp_entry_min_pwdb = + drv_priv->rssi_stat.undec_sm_pwdb; + if (drv_priv->rssi_stat.undec_sm_pwdb > + tmp_entry_max_pwdb) + tmp_entry_max_pwdb = + drv_priv->rssi_stat.undec_sm_pwdb; + } + spin_unlock_bh(&rtlpriv->locks.entry_list_lock); + + /* If associated entry is found */ + if (tmp_entry_max_pwdb != 0) { + rtlpriv->dm.entry_max_undec_sm_pwdb = tmp_entry_max_pwdb; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "EntryMaxPWDB = 0x%lx(%ld)\n", + tmp_entry_max_pwdb, tmp_entry_max_pwdb); + } else { + rtlpriv->dm.entry_max_undec_sm_pwdb = 0; + } + /* If associated entry is found */ + if (tmp_entry_min_pwdb != 0xff) { + rtlpriv->dm.entry_min_undec_sm_pwdb = tmp_entry_min_pwdb; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "EntryMinPWDB = 0x%lx(%ld)\n", + tmp_entry_min_pwdb, tmp_entry_min_pwdb); + } else { + rtlpriv->dm.entry_min_undec_sm_pwdb = 0; + } + /* Indicate Rx signal strength to FW. */ + if (rtlpriv->dm.useramask) { + h2c_parameter[2] = (u8) (rtlpriv->dm.undec_sm_pwdb & 0xFF); + h2c_parameter[1] = 0x20; + h2c_parameter[0] = 0; + rtl8723be_fill_h2c_cmd(hw, H2C_RSSI_REPORT, 3, h2c_parameter); + } else { + rtl_write_byte(rtlpriv, 0x4fe, rtlpriv->dm.undec_sm_pwdb); + } + rtl8723be_dm_find_minimum_rssi(hw); + rtlpriv->dm_digtable.rssi_val_min = + rtlpriv->dm_digtable.min_undec_pwdb_for_dm; +} + +void rtl8723be_dm_write_dig(struct ieee80211_hw *hw, u8 current_igi) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->dm_digtable.cur_igvalue != current_igi) { + rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f, current_igi); + if (rtlpriv->phy.rf_type != RF_1T1R) + rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, 0x7f, current_igi); + } + rtlpriv->dm_digtable.pre_igvalue = rtlpriv->dm_digtable.cur_igvalue; + rtlpriv->dm_digtable.cur_igvalue = current_igi; +} + +static void rtl8723be_dm_dig(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct dig_t *dm_digtable = &(rtlpriv->dm_digtable); + u8 dig_dynamic_min, dig_maxofmin; + bool firstconnect, firstdisconnect; + u8 dm_dig_max, dm_dig_min; + u8 current_igi = dm_digtable->cur_igvalue; + u8 offset; + + /* AP, BT */ + if (mac->act_scanning) + return; + + dig_dynamic_min = dm_digtable->dig_min_0; + firstconnect = (mac->link_state >= MAC80211_LINKED) && + !dm_digtable->media_connect_0; + firstdisconnect = (mac->link_state < MAC80211_LINKED) && + dm_digtable->media_connect_0; + + dm_dig_max = 0x5a; + dm_dig_min = DM_DIG_MIN; + dig_maxofmin = DM_DIG_MAX_AP; + + if (mac->link_state >= MAC80211_LINKED) { + if ((dm_digtable->rssi_val_min + 10) > dm_dig_max) + dm_digtable->rx_gain_max = dm_dig_max; + else if ((dm_digtable->rssi_val_min + 10) < dm_dig_min) + dm_digtable->rx_gain_max = dm_dig_min; + else + dm_digtable->rx_gain_max = + dm_digtable->rssi_val_min + 10; + + if (rtlpriv->dm.one_entry_only) { + offset = 12; + if (dm_digtable->rssi_val_min - offset < dm_dig_min) + dig_dynamic_min = dm_dig_min; + else if (dm_digtable->rssi_val_min - offset > + dig_maxofmin) + dig_dynamic_min = dig_maxofmin; + else + dig_dynamic_min = + dm_digtable->rssi_val_min - offset; + } else { + dig_dynamic_min = dm_dig_min; + } + } else { + dm_digtable->rx_gain_max = dm_dig_max; + dig_dynamic_min = dm_dig_min; + RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "no link\n"); + } + + if (rtlpriv->falsealm_cnt.cnt_all > 10000) { + if (dm_digtable->large_fa_hit != 3) + dm_digtable->large_fa_hit++; + if (dm_digtable->forbidden_igi < current_igi) { + dm_digtable->forbidden_igi = current_igi; + dm_digtable->large_fa_hit = 1; + } + + if (dm_digtable->large_fa_hit >= 3) { + if ((dm_digtable->forbidden_igi + 1) > + dm_digtable->rx_gain_max) + dm_digtable->rx_gain_min = + dm_digtable->rx_gain_max; + else + dm_digtable->rx_gain_min = + dm_digtable->forbidden_igi + 1; + dm_digtable->recover_cnt = 3600; + } + } else { + if (dm_digtable->recover_cnt != 0) { + dm_digtable->recover_cnt--; + } else { + if (dm_digtable->large_fa_hit < 3) { + if ((dm_digtable->forbidden_igi - 1) < + dig_dynamic_min) { + dm_digtable->forbidden_igi = + dig_dynamic_min; + dm_digtable->rx_gain_min = + dig_dynamic_min; + } else { + dm_digtable->forbidden_igi--; + dm_digtable->rx_gain_min = + dm_digtable->forbidden_igi + 1; + } + } else { + dm_digtable->large_fa_hit = 0; + } + } + } + if (dm_digtable->rx_gain_min > dm_digtable->rx_gain_max) + dm_digtable->rx_gain_min = dm_digtable->rx_gain_max; + + if (mac->link_state >= MAC80211_LINKED) { + if (firstconnect) { + if (dm_digtable->rssi_val_min <= dig_maxofmin) + current_igi = dm_digtable->rssi_val_min; + else + current_igi = dig_maxofmin; + + dm_digtable->large_fa_hit = 0; + } else { + if (rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH2) + current_igi += 4; + else if (rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH1) + current_igi += 2; + else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH0) + current_igi -= 2; + } + } else { + if (firstdisconnect) { + current_igi = dm_digtable->rx_gain_min; + } else { + if (rtlpriv->falsealm_cnt.cnt_all > 10000) + current_igi += 4; + else if (rtlpriv->falsealm_cnt.cnt_all > 8000) + current_igi += 2; + else if (rtlpriv->falsealm_cnt.cnt_all < 500) + current_igi -= 2; + } + } + + if (current_igi > dm_digtable->rx_gain_max) + current_igi = dm_digtable->rx_gain_max; + else if (current_igi < dm_digtable->rx_gain_min) + current_igi = dm_digtable->rx_gain_min; + + rtl8723be_dm_write_dig(hw, current_igi); + dm_digtable->media_connect_0 = + ((mac->link_state >= MAC80211_LINKED) ? true : false); + dm_digtable->dig_min_0 = dig_dynamic_min; +} + +static void rtl8723be_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) +{ + u32 ret_value; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); + + rtl_set_bbreg(hw, DM_REG_OFDM_FA_HOLDC_11N, BIT(31), 1); + rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(31), 1); + + ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE1_11N, MASKDWORD); + falsealm_cnt->cnt_fast_fsync_fail = ret_value & 0xffff; + falsealm_cnt->cnt_sb_search_fail = (ret_value & 0xffff0000) >> 16; + + ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE2_11N, MASKDWORD); + falsealm_cnt->cnt_ofdm_cca = ret_value & 0xffff; + falsealm_cnt->cnt_parity_fail = (ret_value & 0xffff0000) >> 16; + + ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE3_11N, MASKDWORD); + falsealm_cnt->cnt_rate_illegal = ret_value & 0xffff; + falsealm_cnt->cnt_crc8_fail = (ret_value & 0xffff0000) >> 16; + + ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE4_11N, MASKDWORD); + falsealm_cnt->cnt_mcs_fail = ret_value & 0xffff; + + falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail + + falsealm_cnt->cnt_rate_illegal + + falsealm_cnt->cnt_crc8_fail + + falsealm_cnt->cnt_mcs_fail + + falsealm_cnt->cnt_fast_fsync_fail + + falsealm_cnt->cnt_sb_search_fail; + + rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(12), 1); + rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(14), 1); + + ret_value = rtl_get_bbreg(hw, DM_REG_CCK_FA_RST_11N, MASKBYTE0); + falsealm_cnt->cnt_cck_fail = ret_value; + + ret_value = rtl_get_bbreg(hw, DM_REG_CCK_FA_MSB_11N, MASKBYTE3); + falsealm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8; + + ret_value = rtl_get_bbreg(hw, DM_REG_CCK_CCA_CNT_11N, MASKDWORD); + falsealm_cnt->cnt_cck_cca = ((ret_value & 0xff) << 8) | + ((ret_value & 0xff00) >> 8); + + falsealm_cnt->cnt_all = falsealm_cnt->cnt_fast_fsync_fail + + falsealm_cnt->cnt_sb_search_fail + + falsealm_cnt->cnt_parity_fail + + falsealm_cnt->cnt_rate_illegal + + falsealm_cnt->cnt_crc8_fail + + falsealm_cnt->cnt_mcs_fail + + falsealm_cnt->cnt_cck_fail; + + falsealm_cnt->cnt_cca_all = falsealm_cnt->cnt_ofdm_cca + + falsealm_cnt->cnt_cck_cca; + + rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTC_11N, BIT(31), 1); + rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTC_11N, BIT(31), 0); + rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(27), 1); + rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(27), 0); + + rtl_set_bbreg(hw, DM_REG_OFDM_FA_HOLDC_11N, BIT(31), 0); + rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(31), 0); + + rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(13) | BIT(12), 0); + rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(13) | BIT(12), 2); + + rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(15) | BIT(14), 0); + rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(15) | BIT(14), 2); + + RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, + "cnt_parity_fail = %d, cnt_rate_illegal = %d, " + "cnt_crc8_fail = %d, cnt_mcs_fail = %d\n", + falsealm_cnt->cnt_parity_fail, + falsealm_cnt->cnt_rate_illegal, + falsealm_cnt->cnt_crc8_fail, + falsealm_cnt->cnt_mcs_fail); + + RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, + "cnt_ofdm_fail = %x, cnt_cck_fail = %x," + " cnt_all = %x\n", + falsealm_cnt->cnt_ofdm_fail, + falsealm_cnt->cnt_cck_fail, + falsealm_cnt->cnt_all); +} + +static void rtl8723be_dm_dynamic_txpower(struct ieee80211_hw *hw) +{ + /* 8723BE does not support ODM_BB_DYNAMIC_TXPWR*/ + return; +} + +static void rtl8723be_set_iqk_matrix(struct ieee80211_hw *hw, u8 ofdm_index, + u8 rfpath, long iqk_result_x, + long iqk_result_y) +{ + long ele_a = 0, ele_d, ele_c = 0, value32; + + if (ofdm_index >= 43) + ofdm_index = 43 - 1; + + ele_d = (ofdmswing_table[ofdm_index] & 0xFFC00000) >> 22; + + if (iqk_result_x != 0) { + if ((iqk_result_x & 0x00000200) != 0) + iqk_result_x = iqk_result_x | 0xFFFFFC00; + ele_a = ((iqk_result_x * ele_d) >> 8) & 0x000003FF; + + if ((iqk_result_y & 0x00000200) != 0) + iqk_result_y = iqk_result_y | 0xFFFFFC00; + ele_c = ((iqk_result_y * ele_d) >> 8) & 0x000003FF; + + switch (rfpath) { + case RF90_PATH_A: + value32 = (ele_d << 22) | + ((ele_c & 0x3F) << 16) | ele_a; + rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, MASKDWORD, + value32); + value32 = (ele_c & 0x000003C0) >> 6; + rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS, value32); + value32 = ((iqk_result_x * ele_d) >> 7) & 0x01; + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(24), + value32); + break; + default: + break; + } + } else { + switch (rfpath) { + case RF90_PATH_A: + rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, MASKDWORD, + ofdmswing_table[ofdm_index]); + rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS, 0x00); + rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(24), 0x00); + break; + default: + break; + } + } +} + +static void rtl8723be_dm_tx_power_track_set_power(struct ieee80211_hw *hw, + enum pwr_track_control_method method, + u8 rfpath, u8 idx) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + u8 swing_idx_ofdm_limit = 36; + + if (method == TXAGC) { + rtl8723be_phy_set_txpower_level(hw, rtlphy->current_channel); + } else if (method == BBSWING) { + if (rtldm->swing_idx_cck >= CCK_TABLE_SIZE) + rtldm->swing_idx_cck = CCK_TABLE_SIZE - 1; + + if (!rtldm->cck_inch14) { + rtl_write_byte(rtlpriv, 0xa22, + cckswing_table_ch1ch13[rtldm->swing_idx_cck][0]); + rtl_write_byte(rtlpriv, 0xa23, + cckswing_table_ch1ch13[rtldm->swing_idx_cck][1]); + rtl_write_byte(rtlpriv, 0xa24, + cckswing_table_ch1ch13[rtldm->swing_idx_cck][2]); + rtl_write_byte(rtlpriv, 0xa25, + cckswing_table_ch1ch13[rtldm->swing_idx_cck][3]); + rtl_write_byte(rtlpriv, 0xa26, + cckswing_table_ch1ch13[rtldm->swing_idx_cck][4]); + rtl_write_byte(rtlpriv, 0xa27, + cckswing_table_ch1ch13[rtldm->swing_idx_cck][5]); + rtl_write_byte(rtlpriv, 0xa28, + cckswing_table_ch1ch13[rtldm->swing_idx_cck][6]); + rtl_write_byte(rtlpriv, 0xa29, + cckswing_table_ch1ch13[rtldm->swing_idx_cck][7]); + } else { + rtl_write_byte(rtlpriv, 0xa22, + cckswing_table_ch14[rtldm->swing_idx_cck][0]); + rtl_write_byte(rtlpriv, 0xa23, + cckswing_table_ch14[rtldm->swing_idx_cck][1]); + rtl_write_byte(rtlpriv, 0xa24, + cckswing_table_ch14[rtldm->swing_idx_cck][2]); + rtl_write_byte(rtlpriv, 0xa25, + cckswing_table_ch14[rtldm->swing_idx_cck][3]); + rtl_write_byte(rtlpriv, 0xa26, + cckswing_table_ch14[rtldm->swing_idx_cck][4]); + rtl_write_byte(rtlpriv, 0xa27, + cckswing_table_ch14[rtldm->swing_idx_cck][5]); + rtl_write_byte(rtlpriv, 0xa28, + cckswing_table_ch14[rtldm->swing_idx_cck][6]); + rtl_write_byte(rtlpriv, 0xa29, + cckswing_table_ch14[rtldm->swing_idx_cck][7]); + } + + if (rfpath == RF90_PATH_A) { + if (rtldm->swing_idx_ofdm[RF90_PATH_A] < + swing_idx_ofdm_limit) + swing_idx_ofdm_limit = + rtldm->swing_idx_ofdm[RF90_PATH_A]; + + rtl8723be_set_iqk_matrix(hw, + rtldm->swing_idx_ofdm[rfpath], rfpath, + rtlphy->iqk_matrix[idx].value[0][0], + rtlphy->iqk_matrix[idx].value[0][1]); + } else if (rfpath == RF90_PATH_B) { + if (rtldm->swing_idx_ofdm[RF90_PATH_B] < + swing_idx_ofdm_limit) + swing_idx_ofdm_limit = + rtldm->swing_idx_ofdm[RF90_PATH_B]; + + rtl8723be_set_iqk_matrix(hw, + rtldm->swing_idx_ofdm[rfpath], rfpath, + rtlphy->iqk_matrix[idx].value[0][4], + rtlphy->iqk_matrix[idx].value[0][5]); + } + } else { + return; + } +} + +static void txpwr_track_cb_therm(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + u8 thermalvalue = 0, delta, delta_lck, delta_iqk; + u8 thermalvalue_avg_count = 0; + u32 thermalvalue_avg = 0; + int i = 0; + + u8 ofdm_min_index = 6; + u8 index = 0; + + char delta_swing_table_idx_tup_a[] = { + 0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 5, + 5, 6, 6, 7, 7, 8, 8, 9, 9, 9, 10, + 10, 11, 11, 12, 12, 13, 14, 15}; + char delta_swing_table_idx_tdown_a[] = { + 0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 5, + 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 9, + 9, 10, 10, 11, 12, 13, 14, 15}; + + /*Initilization ( 7 steps in total)*/ + rtlpriv->dm.txpower_trackinginit = true; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "rtl8723be_dm_txpower_tracking" + "_callback_thermalmeter\n"); + + thermalvalue = (u8)rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER, 0xfc00); + if (!rtlpriv->dm.txpower_track_control || thermalvalue == 0 || + rtlefuse->eeprom_thermalmeter == 0xFF) + return; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "Readback Thermal Meter = 0x%x pre thermal meter 0x%x " + "eeprom_thermalmeter 0x%x\n", + thermalvalue, rtldm->thermalvalue, + rtlefuse->eeprom_thermalmeter); + /*3 Initialize ThermalValues of RFCalibrateInfo*/ + if (!rtldm->thermalvalue) { + rtlpriv->dm.thermalvalue_lck = thermalvalue; + rtlpriv->dm.thermalvalue_iqk = thermalvalue; + } + + /*4 Calculate average thermal meter*/ + rtldm->thermalvalue_avg[rtldm->thermalvalue_avg_index] = thermalvalue; + rtldm->thermalvalue_avg_index++; + if (rtldm->thermalvalue_avg_index == AVG_THERMAL_NUM_8723BE) + rtldm->thermalvalue_avg_index = 0; + + for (i = 0; i < AVG_THERMAL_NUM_8723BE; i++) { + if (rtldm->thermalvalue_avg[i]) { + thermalvalue_avg += rtldm->thermalvalue_avg[i]; + thermalvalue_avg_count++; + } + } + + if (thermalvalue_avg_count) + thermalvalue = (u8)(thermalvalue_avg / thermalvalue_avg_count); + + /* 5 Calculate delta, delta_LCK, delta_IQK.*/ + delta = (thermalvalue > rtlpriv->dm.thermalvalue) ? + (thermalvalue - rtlpriv->dm.thermalvalue) : + (rtlpriv->dm.thermalvalue - thermalvalue); + delta_lck = (thermalvalue > rtlpriv->dm.thermalvalue_lck) ? + (thermalvalue - rtlpriv->dm.thermalvalue_lck) : + (rtlpriv->dm.thermalvalue_lck - thermalvalue); + delta_iqk = (thermalvalue > rtlpriv->dm.thermalvalue_iqk) ? + (thermalvalue - rtlpriv->dm.thermalvalue_iqk) : + (rtlpriv->dm.thermalvalue_iqk - thermalvalue); + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "Readback Thermal Meter = 0x%x pre thermal meter 0x%x " + "eeprom_thermalmeter 0x%x delta 0x%x " + "delta_lck 0x%x delta_iqk 0x%x\n", + thermalvalue, rtlpriv->dm.thermalvalue, + rtlefuse->eeprom_thermalmeter, delta, delta_lck, delta_iqk); + /* 6 If necessary, do LCK.*/ + if (delta_lck >= IQK_THRESHOLD) { + rtlpriv->dm.thermalvalue_lck = thermalvalue; + rtl8723be_phy_lc_calibrate(hw); + } + + /* 7 If necessary, move the index of + * swing table to adjust Tx power. + */ + if (delta > 0 && rtlpriv->dm.txpower_track_control) { + delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ? + (thermalvalue - rtlefuse->eeprom_thermalmeter) : + (rtlefuse->eeprom_thermalmeter - thermalvalue); + + if (delta >= TXSCALE_TABLE_SIZE) + delta = TXSCALE_TABLE_SIZE - 1; + /* 7.1 Get the final CCK_index and + * OFDM_index for each swing table. + */ + if (thermalvalue > rtlefuse->eeprom_thermalmeter) { + rtldm->delta_power_index_last[RF90_PATH_A] = + rtldm->delta_power_index[RF90_PATH_A]; + rtldm->delta_power_index[RF90_PATH_A] = + delta_swing_table_idx_tup_a[delta]; + } else { + rtldm->delta_power_index_last[RF90_PATH_A] = + rtldm->delta_power_index[RF90_PATH_A]; + rtldm->delta_power_index[RF90_PATH_A] = + -1 * delta_swing_table_idx_tdown_a[delta]; + } + + /* 7.2 Handle boundary conditions of index.*/ + if (rtldm->delta_power_index[RF90_PATH_A] == + rtldm->delta_power_index_last[RF90_PATH_A]) + rtldm->power_index_offset[RF90_PATH_A] = 0; + else + rtldm->power_index_offset[RF90_PATH_A] = + rtldm->delta_power_index[RF90_PATH_A] - + rtldm->delta_power_index_last[RF90_PATH_A]; + + rtldm->ofdm_index[0] = + rtldm->swing_idx_ofdm_base[RF90_PATH_A] + + rtldm->power_index_offset[RF90_PATH_A]; + rtldm->cck_index = rtldm->swing_idx_cck_base + + rtldm->power_index_offset[RF90_PATH_A]; + + rtldm->swing_idx_cck = rtldm->cck_index; + rtldm->swing_idx_ofdm[0] = rtldm->ofdm_index[0]; + + if (rtldm->ofdm_index[0] > OFDM_TABLE_SIZE - 1) + rtldm->ofdm_index[0] = OFDM_TABLE_SIZE - 1; + else if (rtldm->ofdm_index[0] < ofdm_min_index) + rtldm->ofdm_index[0] = ofdm_min_index; + + if (rtldm->cck_index > CCK_TABLE_SIZE - 1) + rtldm->cck_index = CCK_TABLE_SIZE - 1; + else if (rtldm->cck_index < 0) + rtldm->cck_index = 0; + } else { + rtldm->power_index_offset[RF90_PATH_A] = 0; + } + + if ((rtldm->power_index_offset[RF90_PATH_A] != 0) && + (rtldm->txpower_track_control)) { + rtldm->done_txpower = true; + if (thermalvalue > rtlefuse->eeprom_thermalmeter) + rtl8723be_dm_tx_power_track_set_power(hw, BBSWING, 0, + index); + else + rtl8723be_dm_tx_power_track_set_power(hw, BBSWING, 0, + index); + + rtldm->swing_idx_cck_base = rtldm->swing_idx_cck; + rtldm->swing_idx_ofdm_base[RF90_PATH_A] = + rtldm->swing_idx_ofdm[0]; + rtldm->thermalvalue = thermalvalue; + } + + if (delta_iqk >= IQK_THRESHOLD) { + rtldm->thermalvalue_iqk = thermalvalue; + rtl8723be_phy_iq_calibrate(hw, false); + } + + rtldm->txpowercount = 0; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "end\n"); +} + +void rtl8723be_dm_check_txpower_tracking(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + static u8 tm_trigger; + + if (!rtlpriv->dm.txpower_tracking) + return; + + if (!tm_trigger) { + rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, BIT(17) | BIT(16), + 0x03); + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "Trigger 8723be Thermal Meter!!\n"); + tm_trigger = 1; + return; + } else { + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "Schedule TxPowerTracking !!\n"); + txpwr_track_cb_therm(hw); + tm_trigger = 0; + } +} + +static void rtl8723be_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rate_adaptive *ra = &(rtlpriv->ra); + struct ieee80211_sta *sta = NULL; + u32 low_rssithresh_for_ra = ra->low2high_rssi_thresh_for_ra40m; + u32 high_rssithresh_for_ra = ra->high_rssi_thresh_for_ra; + u8 go_up_gap = 5; + + if (is_hal_stop(rtlhal)) { + RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, + "driver is going to unload\n"); + return; + } + + if (!rtlpriv->dm.useramask) { + RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, + "driver does not control rate adaptive mask\n"); + return; + } + + if (mac->link_state == MAC80211_LINKED && + mac->opmode == NL80211_IFTYPE_STATION) { + switch (ra->pre_ratr_state) { + case DM_RATR_STA_MIDDLE: + high_rssithresh_for_ra += go_up_gap; + break; + case DM_RATR_STA_LOW: + high_rssithresh_for_ra += go_up_gap; + low_rssithresh_for_ra += go_up_gap; + break; + default: + break; + } + + if (rtlpriv->dm.undec_sm_pwdb > + (long)high_rssithresh_for_ra) + ra->ratr_state = DM_RATR_STA_HIGH; + else if (rtlpriv->dm.undec_sm_pwdb > + (long)low_rssithresh_for_ra) + ra->ratr_state = DM_RATR_STA_MIDDLE; + else + ra->ratr_state = DM_RATR_STA_LOW; + + if (ra->pre_ratr_state != ra->ratr_state) { + RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, + "RSSI = %ld\n", + rtlpriv->dm.undec_sm_pwdb); + RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, + "RSSI_LEVEL = %d\n", ra->ratr_state); + RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, + "PreState = %d, CurState = %d\n", + ra->pre_ratr_state, ra->ratr_state); + + rcu_read_lock(); + sta = rtl_find_sta(hw, mac->bssid); + if (sta) + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, + ra->ratr_state); + rcu_read_unlock(); + + ra->pre_ratr_state = ra->ratr_state; + } + } +} + +static bool rtl8723be_dm_is_edca_turbo_disable(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->cfg->ops->get_btc_status()) { + if (rtlpriv->btcoexist.btc_ops->btc_is_disable_edca_turbo(rtlpriv)) + return true; + } + if (rtlpriv->mac80211.mode == WIRELESS_MODE_B) + return true; + + return false; +} + +static void rtl8723be_dm_check_edca_turbo(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + static u64 last_txok_cnt; + static u64 last_rxok_cnt; + u64 cur_txok_cnt = 0; + u64 cur_rxok_cnt = 0; + u32 edca_be_ul = 0x6ea42b; + u32 edca_be_dl = 0x6ea42b;/*not sure*/ + u32 edca_be = 0x5ea42b; + u32 iot_peer = 0; + bool is_cur_rdlstate; + bool last_is_cur_rdlstate = false; + bool bias_on_rx = false; + bool edca_turbo_on = false; + + last_is_cur_rdlstate = rtlpriv->dm.is_cur_rdlstate; + + cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt; + cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt; + + iot_peer = rtlpriv->mac80211.vendor; + bias_on_rx = (iot_peer == PEER_RAL || iot_peer == PEER_ATH) ? + true : false; + edca_turbo_on = ((!rtlpriv->dm.is_any_nonbepkts) && + (!rtlpriv->dm.disable_framebursting)) ? + true : false; + + if ((iot_peer == PEER_CISCO) && + (mac->mode == WIRELESS_MODE_N_24G)) { + edca_be_dl = edca_setting_dl[iot_peer]; + edca_be_ul = edca_setting_ul[iot_peer]; + } + if (rtl8723be_dm_is_edca_turbo_disable(hw)) + goto exit; + + if (edca_turbo_on) { + if (bias_on_rx) + is_cur_rdlstate = (cur_txok_cnt > cur_rxok_cnt * 4) ? + false : true; + else + is_cur_rdlstate = (cur_rxok_cnt > cur_txok_cnt * 4) ? + true : false; + + edca_be = (is_cur_rdlstate) ? edca_be_dl : edca_be_ul; + rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, edca_be); + rtlpriv->dm.is_cur_rdlstate = is_cur_rdlstate; + rtlpriv->dm.current_turbo_edca = true; + } else { + if (rtlpriv->dm.current_turbo_edca) { + u8 tmp = AC0_BE; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM, + (u8 *)(&tmp)); + } + rtlpriv->dm.current_turbo_edca = false; + } + +exit: + rtlpriv->dm.is_any_nonbepkts = false; + last_txok_cnt = rtlpriv->stats.txbytesunicast; + last_rxok_cnt = rtlpriv->stats.rxbytesunicast; +} + +static void rtl8723be_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 cur_cck_cca_thresh; + + if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) { + if (rtlpriv->dm_digtable.rssi_val_min > 25) { + cur_cck_cca_thresh = 0xcd; + } else if ((rtlpriv->dm_digtable.rssi_val_min <= 25) && + (rtlpriv->dm_digtable.rssi_val_min > 10)) { + cur_cck_cca_thresh = 0x83; + } else { + if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000) + cur_cck_cca_thresh = 0x83; + else + cur_cck_cca_thresh = 0x40; + } + } else { + if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000) + cur_cck_cca_thresh = 0x83; + else + cur_cck_cca_thresh = 0x40; + } + + if (rtlpriv->dm_digtable.cur_cck_cca_thres != cur_cck_cca_thresh) + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, cur_cck_cca_thresh); + + rtlpriv->dm_digtable.pre_cck_cca_thres = rtlpriv->dm_digtable.cur_cck_cca_thres; + rtlpriv->dm_digtable.cur_cck_cca_thres = cur_cck_cca_thresh; + RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, + "CCK cca thresh hold =%x\n", + rtlpriv->dm_digtable.cur_cck_cca_thres); +} + +static void rtl8723be_dm_dynamic_edcca(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 reg_c50, reg_c58; + bool fw_current_in_ps_mode = false; + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, + (u8 *)(&fw_current_in_ps_mode)); + if (fw_current_in_ps_mode) + return; + + reg_c50 = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0); + reg_c58 = rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0); + + if (reg_c50 > 0x28 && reg_c58 > 0x28) { + if (!rtlpriv->rtlhal.pre_edcca_enable) { + rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD, 0x03); + rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD + 2, 0x00); + } + } else if (reg_c50 < 0x25 && reg_c58 < 0x25) { + if (rtlpriv->rtlhal.pre_edcca_enable) { + rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD, 0x7f); + rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD + 2, 0x7f); + } + } +} + +static void rtl8723be_dm_dynamic_atc_switch(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + u8 crystal_cap; + u32 packet_count; + int cfo_khz_a, cfo_khz_b, cfo_ave = 0, adjust_xtal = 0; + int cfo_ave_diff; + + if (rtlpriv->mac80211.link_state < MAC80211_LINKED) { + if (rtldm->atc_status == ATC_STATUS_OFF) { + rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11), + ATC_STATUS_ON); + rtldm->atc_status = ATC_STATUS_ON; + } + if (rtlpriv->cfg->ops->get_btc_status()) { + if (!rtlpriv->btcoexist.btc_ops->btc_is_bt_disabled(rtlpriv)) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "odm_DynamicATCSwitch(): Disable" + " CFO tracking for BT!!\n"); + return; + } + } + + if (rtldm->crystal_cap != rtlpriv->efuse.crystalcap) { + rtldm->crystal_cap = rtlpriv->efuse.crystalcap; + crystal_cap = rtldm->crystal_cap & 0x3f; + rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0xFFF000, + (crystal_cap | (crystal_cap << 6))); + } + } else { + cfo_khz_a = (int)(rtldm->cfo_tail[0] * 3125) / 1280; + cfo_khz_b = (int)(rtldm->cfo_tail[1] * 3125) / 1280; + packet_count = rtldm->packet_count; + + if (packet_count == rtldm->packet_count_pre) + return; + + rtldm->packet_count_pre = packet_count; + + if (rtlpriv->phy.rf_type == RF_1T1R) + cfo_ave = cfo_khz_a; + else + cfo_ave = (int)(cfo_khz_a + cfo_khz_b) >> 1; + + cfo_ave_diff = (rtldm->cfo_ave_pre >= cfo_ave) ? + (rtldm->cfo_ave_pre - cfo_ave) : + (cfo_ave - rtldm->cfo_ave_pre); + + if (cfo_ave_diff > 20 && rtldm->large_cfo_hit == 0) { + rtldm->large_cfo_hit = 1; + return; + } else { + rtldm->large_cfo_hit = 0; + } + + rtldm->cfo_ave_pre = cfo_ave; + + if (cfo_ave >= -rtldm->cfo_threshold && + cfo_ave <= rtldm->cfo_threshold && rtldm->is_freeze == 0) { + if (rtldm->cfo_threshold == CFO_THRESHOLD_XTAL) { + rtldm->cfo_threshold = CFO_THRESHOLD_XTAL + 10; + rtldm->is_freeze = 1; + } else { + rtldm->cfo_threshold = CFO_THRESHOLD_XTAL; + } + } + + if (cfo_ave > rtldm->cfo_threshold && rtldm->crystal_cap < 0x3f) + adjust_xtal = ((cfo_ave - CFO_THRESHOLD_XTAL) >> 1) + 1; + else if ((cfo_ave < -rtlpriv->dm.cfo_threshold) && + rtlpriv->dm.crystal_cap > 0) + adjust_xtal = ((cfo_ave + CFO_THRESHOLD_XTAL) >> 1) - 1; + + if (adjust_xtal != 0) { + rtldm->is_freeze = 0; + rtldm->crystal_cap += adjust_xtal; + + if (rtldm->crystal_cap > 0x3f) + rtldm->crystal_cap = 0x3f; + else if (rtldm->crystal_cap < 0) + rtldm->crystal_cap = 0; + + crystal_cap = rtldm->crystal_cap & 0x3f; + rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0xFFF000, + (crystal_cap | (crystal_cap << 6))); + } + + if (cfo_ave < CFO_THRESHOLD_ATC && + cfo_ave > -CFO_THRESHOLD_ATC) { + if (rtldm->atc_status == ATC_STATUS_ON) { + rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11), + ATC_STATUS_OFF); + rtldm->atc_status = ATC_STATUS_OFF; + } + } else { + if (rtldm->atc_status == ATC_STATUS_OFF) { + rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11), + ATC_STATUS_ON); + rtldm->atc_status = ATC_STATUS_ON; + } + } + } +} + +static void rtl8723be_dm_common_info_self_update(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_sta_info *drv_priv; + u8 cnt = 0; + + rtlpriv->dm.one_entry_only = false; + + if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_STATION && + rtlpriv->mac80211.link_state >= MAC80211_LINKED) { + rtlpriv->dm.one_entry_only = true; + return; + } + + if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP || + rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC || + rtlpriv->mac80211.opmode == NL80211_IFTYPE_MESH_POINT) { + spin_lock_bh(&rtlpriv->locks.entry_list_lock); + list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) { + cnt++; + } + spin_unlock_bh(&rtlpriv->locks.entry_list_lock); + + if (cnt == 1) + rtlpriv->dm.one_entry_only = true; + } +} + +void rtl8723be_dm_watchdog(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool fw_current_inpsmode = false; + bool fw_ps_awake = true; + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, + (u8 *)(&fw_current_inpsmode)); + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON, + (u8 *)(&fw_ps_awake)); + + if (ppsc->p2p_ps_info.p2p_ps_mode) + fw_ps_awake = false; + + if ((ppsc->rfpwr_state == ERFON) && + ((!fw_current_inpsmode) && fw_ps_awake) && + (!ppsc->rfchange_inprogress)) { + rtl8723be_dm_common_info_self_update(hw); + rtl8723be_dm_false_alarm_counter_statistics(hw); + rtl8723be_dm_check_rssi_monitor(hw); + rtl8723be_dm_dig(hw); + rtl8723be_dm_dynamic_edcca(hw); + rtl8723be_dm_cck_packet_detection_thresh(hw); + rtl8723be_dm_refresh_rate_adaptive_mask(hw); + rtl8723be_dm_check_edca_turbo(hw); + rtl8723be_dm_dynamic_atc_switch(hw); + rtl8723be_dm_check_txpower_tracking(hw); + rtl8723be_dm_dynamic_txpower(hw); + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_periodical(rtlpriv); + } + rtlpriv->dm.dbginfo.num_qry_beacon_pkt = 0; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.h b/drivers/net/wireless/rtlwifi/rtl8723be/dm.h new file mode 100644 index 000000000000..c6c2f2a78a66 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/dm.h @@ -0,0 +1,310 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8723BE_DM_H__ +#define __RTL8723BE_DM_H__ + +#define MAIN_ANT 0 +#define AUX_ANT 1 +#define MAIN_ANT_CG_TRX 1 +#define AUX_ANT_CG_TRX 0 +#define MAIN_ANT_CGCS_RX 0 +#define AUX_ANT_CGCS_RX 1 + +#define TXSCALE_TABLE_SIZE 30 + +/*RF REG LIST*/ +#define DM_REG_RF_MODE_11N 0x00 +#define DM_REG_RF_0B_11N 0x0B +#define DM_REG_CHNBW_11N 0x18 +#define DM_REG_T_METER_11N 0x24 +#define DM_REG_RF_25_11N 0x25 +#define DM_REG_RF_26_11N 0x26 +#define DM_REG_RF_27_11N 0x27 +#define DM_REG_RF_2B_11N 0x2B +#define DM_REG_RF_2C_11N 0x2C +#define DM_REG_RXRF_A3_11N 0x3C +#define DM_REG_T_METER_92D_11N 0x42 +#define DM_REG_T_METER_88E_11N 0x42 + +/*BB REG LIST*/ +/*PAGE 8 */ +#define DM_REG_BB_CTRL_11N 0x800 +#define DM_REG_RF_PIN_11N 0x804 +#define DM_REG_PSD_CTRL_11N 0x808 +#define DM_REG_TX_ANT_CTRL_11N 0x80C +#define DM_REG_BB_PWR_SAV5_11N 0x818 +#define DM_REG_CCK_RPT_FORMAT_11N 0x824 +#define DM_REG_RX_DEFUALT_A_11N 0x858 +#define DM_REG_RX_DEFUALT_B_11N 0x85A +#define DM_REG_BB_PWR_SAV3_11N 0x85C +#define DM_REG_ANTSEL_CTRL_11N 0x860 +#define DM_REG_RX_ANT_CTRL_11N 0x864 +#define DM_REG_PIN_CTRL_11N 0x870 +#define DM_REG_BB_PWR_SAV1_11N 0x874 +#define DM_REG_ANTSEL_PATH_11N 0x878 +#define DM_REG_BB_3WIRE_11N 0x88C +#define DM_REG_SC_CNT_11N 0x8C4 +#define DM_REG_PSD_DATA_11N 0x8B4 +/*PAGE 9*/ +#define DM_REG_ANT_MAPPING1_11N 0x914 +#define DM_REG_ANT_MAPPING2_11N 0x918 +/*PAGE A*/ +#define DM_REG_CCK_ANTDIV_PARA1_11N 0xA00 +#define DM_REG_CCK_CCA_11N 0xA0A +#define DM_REG_CCK_ANTDIV_PARA2_11N 0xA0C +#define DM_REG_CCK_ANTDIV_PARA3_11N 0xA10 +#define DM_REG_CCK_ANTDIV_PARA4_11N 0xA14 +#define DM_REG_CCK_FILTER_PARA1_11N 0xA22 +#define DM_REG_CCK_FILTER_PARA2_11N 0xA23 +#define DM_REG_CCK_FILTER_PARA3_11N 0xA24 +#define DM_REG_CCK_FILTER_PARA4_11N 0xA25 +#define DM_REG_CCK_FILTER_PARA5_11N 0xA26 +#define DM_REG_CCK_FILTER_PARA6_11N 0xA27 +#define DM_REG_CCK_FILTER_PARA7_11N 0xA28 +#define DM_REG_CCK_FILTER_PARA8_11N 0xA29 +#define DM_REG_CCK_FA_RST_11N 0xA2C +#define DM_REG_CCK_FA_MSB_11N 0xA58 +#define DM_REG_CCK_FA_LSB_11N 0xA5C +#define DM_REG_CCK_CCA_CNT_11N 0xA60 +#define DM_REG_BB_PWR_SAV4_11N 0xA74 +/*PAGE B */ +#define DM_REG_LNA_SWITCH_11N 0xB2C +#define DM_REG_PATH_SWITCH_11N 0xB30 +#define DM_REG_RSSI_CTRL_11N 0xB38 +#define DM_REG_CONFIG_ANTA_11N 0xB68 +#define DM_REG_RSSI_BT_11N 0xB9C +/*PAGE C */ +#define DM_REG_OFDM_FA_HOLDC_11N 0xC00 +#define DM_REG_RX_PATH_11N 0xC04 +#define DM_REG_TRMUX_11N 0xC08 +#define DM_REG_OFDM_FA_RSTC_11N 0xC0C +#define DM_REG_RXIQI_MATRIX_11N 0xC14 +#define DM_REG_TXIQK_MATRIX_LSB1_11N 0xC4C +#define DM_REG_IGI_A_11N 0xC50 +#define DM_REG_ANTDIV_PARA2_11N 0xC54 +#define DM_REG_IGI_B_11N 0xC58 +#define DM_REG_ANTDIV_PARA3_11N 0xC5C +#define DM_REG_BB_PWR_SAV2_11N 0xC70 +#define DM_REG_RX_OFF_11N 0xC7C +#define DM_REG_TXIQK_MATRIXA_11N 0xC80 +#define DM_REG_TXIQK_MATRIXB_11N 0xC88 +#define DM_REG_TXIQK_MATRIXA_LSB2_11N 0xC94 +#define DM_REG_TXIQK_MATRIXB_LSB2_11N 0xC9C +#define DM_REG_RXIQK_MATRIX_LSB_11N 0xCA0 +#define DM_REG_ANTDIV_PARA1_11N 0xCA4 +#define DM_REG_OFDM_FA_TYPE1_11N 0xCF0 +/*PAGE D */ +#define DM_REG_OFDM_FA_RSTD_11N 0xD00 +#define DM_REG_OFDM_FA_TYPE2_11N 0xDA0 +#define DM_REG_OFDM_FA_TYPE3_11N 0xDA4 +#define DM_REG_OFDM_FA_TYPE4_11N 0xDA8 +/*PAGE E */ +#define DM_REG_TXAGC_A_6_18_11N 0xE00 +#define DM_REG_TXAGC_A_24_54_11N 0xE04 +#define DM_REG_TXAGC_A_1_MCS32_11N 0xE08 +#define DM_REG_TXAGC_A_MCS0_3_11N 0xE10 +#define DM_REG_TXAGC_A_MCS4_7_11N 0xE14 +#define DM_REG_TXAGC_A_MCS8_11_11N 0xE18 +#define DM_REG_TXAGC_A_MCS12_15_11N 0xE1C +#define DM_REG_FPGA0_IQK_11N 0xE28 +#define DM_REG_TXIQK_TONE_A_11N 0xE30 +#define DM_REG_RXIQK_TONE_A_11N 0xE34 +#define DM_REG_TXIQK_PI_A_11N 0xE38 +#define DM_REG_RXIQK_PI_A_11N 0xE3C +#define DM_REG_TXIQK_11N 0xE40 +#define DM_REG_RXIQK_11N 0xE44 +#define DM_REG_IQK_AGC_PTS_11N 0xE48 +#define DM_REG_IQK_AGC_RSP_11N 0xE4C +#define DM_REG_BLUETOOTH_11N 0xE6C +#define DM_REG_RX_WAIT_CCA_11N 0xE70 +#define DM_REG_TX_CCK_RFON_11N 0xE74 +#define DM_REG_TX_CCK_BBON_11N 0xE78 +#define DM_REG_OFDM_RFON_11N 0xE7C +#define DM_REG_OFDM_BBON_11N 0xE80 +#define DM_REG_TX2RX_11N 0xE84 +#define DM_REG_TX2TX_11N 0xE88 +#define DM_REG_RX_CCK_11N 0xE8C +#define DM_REG_RX_OFDM_11N 0xED0 +#define DM_REG_RX_WAIT_RIFS_11N 0xED4 +#define DM_REG_RX2RX_11N 0xED8 +#define DM_REG_STANDBY_11N 0xEDC +#define DM_REG_SLEEP_11N 0xEE0 +#define DM_REG_PMPD_ANAEN_11N 0xEEC + +/*MAC REG LIST*/ +#define DM_REG_BB_RST_11N 0x02 +#define DM_REG_ANTSEL_PIN_11N 0x4C +#define DM_REG_EARLY_MODE_11N 0x4D0 +#define DM_REG_RSSI_MONITOR_11N 0x4FE +#define DM_REG_EDCA_VO_11N 0x500 +#define DM_REG_EDCA_VI_11N 0x504 +#define DM_REG_EDCA_BE_11N 0x508 +#define DM_REG_EDCA_BK_11N 0x50C +#define DM_REG_TXPAUSE_11N 0x522 +#define DM_REG_RESP_TX_11N 0x6D8 +#define DM_REG_ANT_TRAIN_PARA1_11N 0x7b0 +#define DM_REG_ANT_TRAIN_PARA2_11N 0x7b4 + +/*DIG Related*/ +#define DM_BIT_IGI_11N 0x0000007F + +#define HAL_DM_DIG_DISABLE BIT(0) +#define HAL_DM_HIPWR_DISABLE BIT(1) + +#define OFDM_TABLE_LENGTH 43 +#define CCK_TABLE_LENGTH 33 + +#define OFDM_TABLE_SIZE 37 +#define CCK_TABLE_SIZE 33 + +#define BW_AUTO_SWITCH_HIGH_LOW 25 +#define BW_AUTO_SWITCH_LOW_HIGH 30 + +#define DM_DIG_THRESH_HIGH 40 +#define DM_DIG_THRESH_LOW 35 + +#define DM_FALSEALARM_THRESH_LOW 400 +#define DM_FALSEALARM_THRESH_HIGH 1000 + +#define DM_DIG_MAX 0x3e +#define DM_DIG_MIN 0x1e + +#define DM_DIG_MAX_AP 0x32 +#define DM_DIG_MIN_AP 0x20 + +#define DM_DIG_FA_UPPER 0x3e +#define DM_DIG_FA_LOWER 0x1e +#define DM_DIG_FA_TH0 0x200 +#define DM_DIG_FA_TH1 0x300 +#define DM_DIG_FA_TH2 0x400 + +#define DM_DIG_BACKOFF_MAX 12 +#define DM_DIG_BACKOFF_MIN -4 +#define DM_DIG_BACKOFF_DEFAULT 10 + +#define RXPATHSELECTION_DIFF_TH 18 + +#define DM_RATR_STA_INIT 0 +#define DM_RATR_STA_HIGH 1 +#define DM_RATR_STA_MIDDLE 2 +#define DM_RATR_STA_LOW 3 + +#define CTS2SELF_THVAL 30 +#define REGC38_TH 20 + +#define TXHIGHPWRLEVEL_NORMAL 0 +#define TXHIGHPWRLEVEL_LEVEL1 1 +#define TXHIGHPWRLEVEL_LEVEL2 2 +#define TXHIGHPWRLEVEL_BT1 3 +#define TXHIGHPWRLEVEL_BT2 4 + +#define DM_TYPE_BYFW 0 +#define DM_TYPE_BYDRIVER 1 + +#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 +#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 +#define TXPWRTRACK_MAX_IDX 6 + +/* Dynamic ATC switch */ +#define ATC_STATUS_OFF 0x0 /* enable */ +#define ATC_STATUS_ON 0x1 /* disable */ +#define CFO_THRESHOLD_XTAL 10 /* kHz */ +#define CFO_THRESHOLD_ATC 80 /* kHz */ + +enum FAT_STATE { + FAT_NORMAL_STATE = 0, + FAT_TRAINING_STATE = 1, +}; + +enum tag_dynamic_init_gain_operation_type_definition { + DIG_TYPE_THRESH_HIGH = 0, + DIG_TYPE_THRESH_LOW = 1, + DIG_TYPE_BACKOFF = 2, + DIG_TYPE_RX_GAIN_MIN = 3, + DIG_TYPE_RX_GAIN_MAX = 4, + DIG_TYPE_ENABLE = 5, + DIG_TYPE_DISABLE = 6, + DIG_OP_TYPE_MAX +}; + +enum dm_1r_cca_e { + CCA_1R = 0, + CCA_2R = 1, + CCA_MAX = 2, +}; + +enum dm_rf_e { + RF_SAVE = 0, + RF_NORMAL = 1, + RF_MAX = 2, +}; + +enum dm_sw_ant_switch_e { + ANS_ANTENNA_B = 1, + ANS_ANTENNA_A = 2, + ANS_ANTENNA_MAX = 3, +}; + +enum dm_dig_ext_port_alg_e { + DIG_EXT_PORT_STAGE_0 = 0, + DIG_EXT_PORT_STAGE_1 = 1, + DIG_EXT_PORT_STAGE_2 = 2, + DIG_EXT_PORT_STAGE_3 = 3, + DIG_EXT_PORT_STAGE_MAX = 4, +}; + +enum dm_dig_connect_e { + DIG_STA_DISCONNECT = 0, + DIG_STA_CONNECT = 1, + DIG_STA_BEFORE_CONNECT = 2, + DIG_MULTISTA_DISCONNECT = 3, + DIG_MULTISTA_CONNECT = 4, + DIG_CONNECT_MAX +}; + +enum pwr_track_control_method { + BBSWING, + TXAGC +}; + +#define BT_RSSI_STATE_NORMAL_POWER BIT_OFFSET_LEN_MASK_32(0, 1) +#define BT_RSSI_STATE_AMDPU_OFF BIT_OFFSET_LEN_MASK_32(1, 1) +#define BT_RSSI_STATE_SPECIAL_LOW BIT_OFFSET_LEN_MASK_32(2, 1) +#define BT_RSSI_STATE_BG_EDCA_LOW BIT_OFFSET_LEN_MASK_32(3, 1) +#define BT_RSSI_STATE_TXPOWER_LOW BIT_OFFSET_LEN_MASK_32(4, 1) + +void rtl8723be_dm_set_tx_ant_by_tx_info(struct ieee80211_hw *hw, u8 *pdesc, + u32 mac_id); +void rtl8723be_dm_ant_sel_statistics(struct ieee80211_hw *hw, u8 antsel_tr_mux, + u32 mac_id, u32 rx_pwdb_all); +void rtl8723be_dm_fast_antenna_trainning_callback(unsigned long data); +void rtl8723be_dm_init(struct ieee80211_hw *hw); +void rtl8723be_dm_watchdog(struct ieee80211_hw *hw); +void rtl8723be_dm_write_dig(struct ieee80211_hw *hw, u8 current_igi); +void rtl8723be_dm_check_txpower_tracking(struct ieee80211_hw *hw); +void rtl8723be_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw); +void rtl8723be_dm_txpower_track_adjust(struct ieee80211_hw *hw, u8 type, + u8 *pdirection, u32 *poutwrite_val); +void rtl8723be_dm_init_edca_turbo(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/fw.c b/drivers/net/wireless/rtlwifi/rtl8723be/fw.c new file mode 100644 index 000000000000..0f3522db5b37 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/fw.c @@ -0,0 +1,628 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "fw.h" +#include "../rtl8723com/fw_common.h" + +static bool _rtl8723be_check_fw_read_last_h2c(struct ieee80211_hw *hw, + u8 boxnum) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 val_hmetfr; + bool result = false; + + val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR); + if (((val_hmetfr >> boxnum) & BIT(0)) == 0) + result = true; + return result; +} + +static void _rtl8723be_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id, + u32 cmd_len, u8 *p_cmdbuffer) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 boxnum; + u16 box_reg = 0, box_extreg = 0; + u8 u1b_tmp; + bool isfw_read = false; + u8 buf_index = 0; + bool bwrite_sucess = false; + u8 wait_h2c_limit = 100; + u8 wait_writeh2c_limit = 100; + u8 boxcontent[4], boxextcontent[4]; + u32 h2c_waitcounter = 0; + unsigned long flag; + u8 idx; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n"); + + while (true) { + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); + if (rtlhal->h2c_setinprogress) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "H2C set in progress! Wait to set.." + "element_id(%d).\n", element_id); + + while (rtlhal->h2c_setinprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, + flag); + h2c_waitcounter++; + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Wait 100 us (%d times)...\n", + h2c_waitcounter); + udelay(100); + + if (h2c_waitcounter > 1000) + return; + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, + flag); + } + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + } else { + rtlhal->h2c_setinprogress = true; + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + break; + } + } + while (!bwrite_sucess) { + wait_writeh2c_limit--; + if (wait_writeh2c_limit == 0) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Write H2C fail because no trigger " + "for FW INT!\n"); + break; + } + boxnum = rtlhal->last_hmeboxnum; + switch (boxnum) { + case 0: + box_reg = REG_HMEBOX_0; + box_extreg = REG_HMEBOX_EXT_0; + break; + case 1: + box_reg = REG_HMEBOX_1; + box_extreg = REG_HMEBOX_EXT_1; + break; + case 2: + box_reg = REG_HMEBOX_2; + box_extreg = REG_HMEBOX_EXT_2; + break; + case 3: + box_reg = REG_HMEBOX_3; + box_extreg = REG_HMEBOX_EXT_3; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + isfw_read = _rtl8723be_check_fw_read_last_h2c(hw, boxnum); + while (!isfw_read) { + wait_h2c_limit--; + if (wait_h2c_limit == 0) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Wating too long for FW read " + "clear HMEBox(%d)!\n", boxnum); + break; + } + udelay(10); + + isfw_read = _rtl8723be_check_fw_read_last_h2c(hw, + boxnum); + u1b_tmp = rtl_read_byte(rtlpriv, 0x130); + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Wating for FW read clear HMEBox(%d)!!! 0x130 = %2x\n", + boxnum, u1b_tmp); + } + if (!isfw_read) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Write H2C register BOX[%d] fail!!!!! " + "Fw do not read.\n", boxnum); + break; + } + memset(boxcontent, 0, sizeof(boxcontent)); + memset(boxextcontent, 0, sizeof(boxextcontent)); + boxcontent[0] = element_id; + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "Write element_id box_reg(%4x) = %2x\n", + box_reg, element_id); + + switch (cmd_len) { + case 1: + case 2: + case 3: + /*boxcontent[0] &= ~(BIT(7));*/ + memcpy((u8 *)(boxcontent) + 1, + p_cmdbuffer + buf_index, cmd_len); + + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + } + break; + case 4: + case 5: + case 6: + case 7: + /*boxcontent[0] |= (BIT(7));*/ + memcpy((u8 *)(boxextcontent), + p_cmdbuffer + buf_index+3, cmd_len-3); + memcpy((u8 *)(boxcontent) + 1, + p_cmdbuffer + buf_index, 3); + + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_extreg + idx, + boxextcontent[idx]); + } + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + } + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not process\n"); + break; + } + bwrite_sucess = true; + + rtlhal->last_hmeboxnum = boxnum + 1; + if (rtlhal->last_hmeboxnum == 4) + rtlhal->last_hmeboxnum = 0; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + "pHalData->last_hmeboxnum = %d\n", + rtlhal->last_hmeboxnum); + } + if (!rtlpriv) { + pr_err("rtlpriv bad\n"); + return; + } + if (!rtlhal) { + pr_err("rtlhal bad\n"); + return; + } + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); + rtlhal->h2c_setinprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n"); +} + +void rtl8723be_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, + u32 cmd_len, u8 *p_cmdbuffer) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 tmp_cmdbuf[2]; + + if (!rtlhal->fw_ready) { + RT_ASSERT(false, + "return H2C cmd because of Fw download fail!!!\n"); + return; + } + memset(tmp_cmdbuf, 0, 8); + memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len); + _rtl8723be_fill_h2c_command(hw, element_id, cmd_len, + (u8 *)&tmp_cmdbuf); + return; +} + +void rtl8723be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1_h2c_set_pwrmode[H2C_8723BE_PWEMODE_LENGTH] = { 0 }; + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + u8 rlbm, power_state = 0; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode); + + SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0)); + rlbm = 0;/*YJ, temp, 120316. FW now not support RLBM = 2.*/ + SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm); + SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, + (rtlpriv->mac80211.p2p) ? + ppsc->smart_ps : 1); + SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode, + ppsc->reg_max_lps_awakeintvl); + SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0); + if (mode == FW_PS_ACTIVE_MODE) + power_state |= FW_PWR_STATE_ACTIVE; + else + power_state |= FW_PWR_STATE_RF_OFF; + SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state); + + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n", + u1_h2c_set_pwrmode, H2C_8723BE_PWEMODE_LENGTH); + rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_SETPWRMODE, + H2C_8723BE_PWEMODE_LENGTH, + u1_h2c_set_pwrmode); +} + +static bool _rtl8723be_cmd_send_packet(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring; + struct rtl_tx_desc *pdesc; + struct sk_buff *pskb = NULL; + u8 own; + unsigned long flags; + + ring = &rtlpci->tx_ring[BEACON_QUEUE]; + + pskb = __skb_dequeue(&ring->queue); + if (pskb) + kfree_skb(pskb); + + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + + pdesc = &ring->desc[0]; + own = (u8) rtlpriv->cfg->ops->get_desc((u8 *)pdesc, true, HW_DESC_OWN); + + rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb); + + __skb_queue_tail(&ring->queue, skb); + + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE); + + return true; +} +#define BEACON_PG 0 /* ->1 */ +#define PSPOLL_PG 2 +#define NULL_PG 3 +#define PROBERSP_PG 4 /* ->5 */ + +#define TOTAL_RESERVED_PKT_LEN 768 + +static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = { + /* page 0 beacon */ + 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78, + 0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x10, 0x04, 0x00, 0x05, 0x54, 0x65, + 0x73, 0x74, 0x32, 0x01, 0x08, 0x82, 0x84, 0x0B, + 0x16, 0x24, 0x30, 0x48, 0x6C, 0x03, 0x01, 0x06, + 0x06, 0x02, 0x00, 0x00, 0x2A, 0x01, 0x02, 0x32, + 0x04, 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, + 0x09, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3D, 0x00, 0xDD, 0x07, 0x00, 0xE0, 0x4C, + 0x02, 0x02, 0x00, 0x00, 0xDD, 0x18, 0x00, 0x50, + 0xF2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, + 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, 0x01, 0x00, + + /* page 1 beacon */ + 0x00, 0x50, 0xF2, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 2 ps-poll */ + 0xA4, 0x10, 0x01, 0xC0, 0xEC, 0x1A, 0x59, 0x0B, + 0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 3 null */ + 0x48, 0x01, 0x00, 0x00, 0xEC, 0x1A, 0x59, 0x0B, + 0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78, + 0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x72, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 4 probe_resp */ + 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, + 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, + 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, + 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00, + 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69, + 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C, + 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96, + 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A, + 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C, + 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02, + 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 5 probe_resp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +void rtl8723be_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, + bool dl_finished) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct sk_buff *skb = NULL; + + u32 totalpacketlen; + bool rtstatus; + u8 u1rsvdpageloc[5] = { 0 }; + bool dlok = false; + + u8 *beacon; + u8 *p_pspoll; + u8 *nullfunc; + u8 *p_probersp; + /*--------------------------------------------------------- + * (1) beacon + *--------------------------------------------------------- + */ + beacon = &reserved_page_packet[BEACON_PG * 128]; + SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr); + SET_80211_HDR_ADDRESS3(beacon, mac->bssid); + + /*------------------------------------------------------- + * (2) ps-poll + *------------------------------------------------------- + */ + p_pspoll = &reserved_page_packet[PSPOLL_PG * 128]; + SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000)); + SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid); + SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr); + + SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG); + + /*-------------------------------------------------------- + * (3) null data + *-------------------------------------------------------- + */ + nullfunc = &reserved_page_packet[NULL_PG * 128]; + SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid); + SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr); + SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid); + + SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG); + + /*--------------------------------------------------------- + * (4) probe response + *--------------------------------------------------------- + */ + p_probersp = &reserved_page_packet[PROBERSP_PG * 128]; + SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid); + SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr); + SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid); + + SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG); + + totalpacketlen = TOTAL_RESERVED_PKT_LEN; + + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, + "rtl8723be_set_fw_rsvdpagepkt(): " + "HW_VAR_SET_TX_CMD: ALL\n", + &reserved_page_packet[0], totalpacketlen); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "rtl8723be_set_fw_rsvdpagepkt(): " + "HW_VAR_SET_TX_CMD: ALL\n", u1rsvdpageloc, 3); + + + skb = dev_alloc_skb(totalpacketlen); + memcpy((u8 *)skb_put(skb, totalpacketlen), + &reserved_page_packet, totalpacketlen); + + rtstatus = _rtl8723be_cmd_send_packet(hw, skb); + + if (rtstatus) + dlok = true; + + if (dlok) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Set RSVD page location to Fw.\n"); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, "H2C_RSVDPAGE:\n", + u1rsvdpageloc, 3); + rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_RSVDPAGE, + sizeof(u1rsvdpageloc), u1rsvdpageloc); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Set RSVD page location to Fw FAIL!!!!!!.\n"); + } +} + +/*Should check FW support p2p or not.*/ +static void rtl8723be_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, + u8 ctwindow) +{ + u8 u1_ctwindow_period[1] = {ctwindow}; + + rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_P2P_PS_CTW_CMD, 1, + u1_ctwindow_period); +} + +void rtl8723be_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, + u8 p2p_ps_state) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info); + struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload; + u8 i; + u16 ctwindow; + u32 start_time, tsf_low; + + switch (p2p_ps_state) { + case P2P_PS_DISABLE: + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n"); + memset(p2p_ps_offload, 0, sizeof(struct p2p_ps_offload_t)); + break; + case P2P_PS_ENABLE: + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n"); + /* update CTWindow value. */ + if (p2pinfo->ctwindow > 0) { + p2p_ps_offload->ctwindow_en = 1; + ctwindow = p2pinfo->ctwindow; + rtl8723be_set_p2p_ctw_period_cmd(hw, ctwindow); + } + /* hw only support 2 set of NoA */ + for (i = 0; i < p2pinfo->noa_num; i++) { + /* To control the register setting + * for which NOA + */ + rtl_write_byte(rtlpriv, 0x5cf, (i << 4)); + if (i == 0) + p2p_ps_offload->noa0_en = 1; + else + p2p_ps_offload->noa1_en = 1; + + /* config P2P NoA Descriptor Register */ + rtl_write_dword(rtlpriv, 0x5E0, + p2pinfo->noa_duration[i]); + rtl_write_dword(rtlpriv, 0x5E4, + p2pinfo->noa_interval[i]); + + /*Get Current TSF value */ + tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR); + + start_time = p2pinfo->noa_start_time[i]; + if (p2pinfo->noa_count_type[i] != 1) { + while (start_time <= (tsf_low + (50 * 1024))) { + start_time += p2pinfo->noa_interval[i]; + if (p2pinfo->noa_count_type[i] != 255) + p2pinfo->noa_count_type[i]--; + } + } + rtl_write_dword(rtlpriv, 0x5E8, start_time); + rtl_write_dword(rtlpriv, 0x5EC, + p2pinfo->noa_count_type[i]); + } + if ((p2pinfo->opp_ps == 1) || + (p2pinfo->noa_num > 0)) { + /* rst p2p circuit */ + rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4)); + + p2p_ps_offload->offload_en = 1; + + if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) { + p2p_ps_offload->role = 1; + p2p_ps_offload->allstasleep = 0; + } else { + p2p_ps_offload->role = 0; + } + p2p_ps_offload->discovery = 0; + } + break; + case P2P_PS_SCAN: + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n"); + p2p_ps_offload->discovery = 1; + break; + case P2P_PS_SCAN_DONE: + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n"); + p2p_ps_offload->discovery = 0; + p2pinfo->p2p_ps_state = P2P_PS_ENABLE; + break; + default: + break; + } + rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_P2P_PS_OFFLOAD, 1, + (u8 *)p2p_ps_offload); +} + +void rtl8723be_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus) +{ + u8 u1_joinbssrpt_parm[1] = { 0 }; + + SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus); + + rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_JOINBSSRPT, 1, + u1_joinbssrpt_parm); +} + +void rtl8723be_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw, + u8 ap_offload_enable) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u8 u1_apoffload_parm[H2C_8723BE_AP_OFFLOAD_LENGTH] = { 0 }; + + SET_H2CCMD_AP_OFFLOAD_ON(u1_apoffload_parm, ap_offload_enable); + SET_H2CCMD_AP_OFFLOAD_HIDDEN(u1_apoffload_parm, mac->hiddenssid); + SET_H2CCMD_AP_OFFLOAD_DENYANY(u1_apoffload_parm, 0); + + rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_AP_OFFLOAD, + H2C_8723BE_AP_OFFLOAD_LENGTH, u1_apoffload_parm); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/fw.h b/drivers/net/wireless/rtlwifi/rtl8723be/fw.h new file mode 100644 index 000000000000..31eec281e446 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/fw.h @@ -0,0 +1,248 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8723BE__FW__H__ +#define __RTL8723BE__FW__H__ + +#define FW_8192C_SIZE 0x8000 +#define FW_8192C_START_ADDRESS 0x1000 +#define FW_8192C_END_ADDRESS 0x5FFF +#define FW_8192C_PAGE_SIZE 4096 +#define FW_8192C_POLLING_DELAY 5 +#define FW_8192C_POLLING_TIMEOUT_COUNT 6000 + +#define IS_FW_HEADER_EXIST(_pfwhdr) \ + ((_pfwhdr->signature&0xFFF0) == 0x5300) +#define USE_OLD_WOWLAN_DEBUG_FW 0 + +#define H2C_8723BE_RSVDPAGE_LOC_LEN 5 +#define H2C_8723BE_PWEMODE_LENGTH 5 +#define H2C_8723BE_JOINBSSRPT_LENGTH 1 +#define H2C_8723BE_AP_OFFLOAD_LENGTH 3 +#define H2C_8723BE_WOWLAN_LENGTH 3 +#define H2C_8723BE_KEEP_ALIVE_CTRL_LENGTH 3 +#if (USE_OLD_WOWLAN_DEBUG_FW == 0) +#define H2C_8723BE_REMOTE_WAKE_CTRL_LEN 1 +#else +#define H2C_8723BE_REMOTE_WAKE_CTRL_LEN 3 +#endif +#define H2C_8723BE_AOAC_GLOBAL_INFO_LEN 2 +#define H2C_8723BE_AOAC_RSVDPAGE_LOC_LEN 7 + + +/* Fw PS state for RPWM. +*BIT[2:0] = HW state +*BIT[3] = Protocol PS state, 1: register active state , 0: register sleep state +*BIT[4] = sub-state +*/ +#define FW_PS_GO_ON BIT(0) +#define FW_PS_TX_NULL BIT(1) +#define FW_PS_RF_ON BIT(2) +#define FW_PS_REGISTER_ACTIVE BIT(3) + +#define FW_PS_DPS BIT(0) +#define FW_PS_LCLK (FW_PS_DPS) +#define FW_PS_RF_OFF BIT(1) +#define FW_PS_ALL_ON BIT(2) +#define FW_PS_ST_ACTIVE BIT(3) +#define FW_PS_ISR_ENABLE BIT(4) +#define FW_PS_IMR_ENABLE BIT(5) + + +#define FW_PS_ACK BIT(6) +#define FW_PS_TOGGLE BIT(7) + + /* 88E RPWM value*/ + /* BIT[0] = 1: 32k, 0: 40M*/ +#define FW_PS_CLOCK_OFF BIT(0) /* 32k*/ +#define FW_PS_CLOCK_ON 0 /*40M*/ + +#define FW_PS_STATE_MASK (0x0F) +#define FW_PS_STATE_HW_MASK (0x07) +/*ISR_ENABLE, IMR_ENABLE, and PS mode should be inherited.*/ +#define FW_PS_STATE_INT_MASK (0x3F) + +#define FW_PS_STATE(x) (FW_PS_STATE_MASK & (x)) +#define FW_PS_STATE_HW(x) (FW_PS_STATE_HW_MASK & (x)) +#define FW_PS_STATE_INT(x) (FW_PS_STATE_INT_MASK & (x)) +#define FW_PS_ISR_VAL(x) ((x) & 0x70) +#define FW_PS_IMR_MASK(x) ((x) & 0xDF) +#define FW_PS_KEEP_IMR(x) ((x) & 0x20) + + +#define FW_PS_STATE_S0 (FW_PS_DPS) +#define FW_PS_STATE_S1 (FW_PS_LCLK) +#define FW_PS_STATE_S2 (FW_PS_RF_OFF) +#define FW_PS_STATE_S3 (FW_PS_ALL_ON) +#define FW_PS_STATE_S4 ((FW_PS_ST_ACTIVE) | (FW_PS_ALL_ON)) + +/* ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))*/ +#define FW_PS_STATE_ALL_ON_88E (FW_PS_CLOCK_ON) +/* (FW_PS_RF_ON)*/ +#define FW_PS_STATE_RF_ON_88E (FW_PS_CLOCK_ON) +/* 0x0*/ +#define FW_PS_STATE_RF_OFF_88E (FW_PS_CLOCK_ON) +/* (FW_PS_STATE_RF_OFF)*/ +#define FW_PS_STATE_RF_OFF_LOW_PWR_88E (FW_PS_CLOCK_OFF) + +#define FW_PS_STATE_ALL_ON_92C (FW_PS_STATE_S4) +#define FW_PS_STATE_RF_ON_92C (FW_PS_STATE_S3) +#define FW_PS_STATE_RF_OFF_92C (FW_PS_STATE_S2) +#define FW_PS_STATE_RF_OFF_LOW_PWR_92C (FW_PS_STATE_S1) + + +/* For 88E H2C PwrMode Cmd ID 5.*/ +#define FW_PWR_STATE_ACTIVE ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE)) +#define FW_PWR_STATE_RF_OFF 0 + +#define FW_PS_IS_ACK(x) ((x) & FW_PS_ACK) +#define FW_PS_IS_CLK_ON(x) ((x) & (FW_PS_RF_OFF | FW_PS_ALL_ON)) +#define FW_PS_IS_RF_ON(x) ((x) & (FW_PS_ALL_ON)) +#define FW_PS_IS_ACTIVE(x) ((x) & (FW_PS_ST_ACTIVE)) +#define FW_PS_IS_CPWM_INT(x) ((x) & 0x40) + +#define FW_CLR_PS_STATE(x) ((x) = ((x) & (0xF0))) + +#define IS_IN_LOW_POWER_STATE_88E(fwpsstate) \ + (FW_PS_STATE(fwpsstate) == FW_PS_CLOCK_OFF) + +#define FW_PWR_STATE_ACTIVE ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE)) +#define FW_PWR_STATE_RF_OFF 0 + +#define pagenum_128(_len) (u32)(((_len)>>7) + ((_len)&0x7F ? 1 : 0)) + +#define SET_88E_H2CCMD_WOWLAN_FUNC_ENABLE(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 1, __val) +#define SET_88E_H2CCMD_WOWLAN_PATTERN_MATCH_ENABLE(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 1, 1, __val) +#define SET_88E_H2CCMD_WOWLAN_MAGIC_PKT_ENABLE(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 2, 1, __val) +#define SET_88E_H2CCMD_WOWLAN_UNICAST_PKT_ENABLE(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 3, 1, __val) +#define SET_88E_H2CCMD_WOWLAN_ALL_PKT_DROP(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 4, 1, __val) +#define SET_88E_H2CCMD_WOWLAN_GPIO_ACTIVE(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 5, 1, __val) +#define SET_88E_H2CCMD_WOWLAN_REKEY_WAKE_UP(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 6, 1, __val) +#define SET_88E_H2CCMD_WOWLAN_DISCONNECT_WAKE_UP(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 7, 1, __val) +#define SET_88E_H2CCMD_WOWLAN_GPIONUM(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val) +#define SET_88E_H2CCMD_WOWLAN_GPIO_DURATION(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val) + + +#define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_RLBM(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 4, __val) +#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 4, 4, __val) +#define SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+3, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_PWR_STATE(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+4, 0, 8, __val) +#define GET_88E_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd) \ + LE_BITS_TO_1BYTE(__ph2ccmd, 0, 8) + +#define SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val) + +/* AP_OFFLOAD */ +#define SET_H2CCMD_AP_OFFLOAD_ON(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_AP_OFFLOAD_HIDDEN(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val) +#define SET_H2CCMD_AP_OFFLOAD_DENYANY(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val) +#define SET_H2CCMD_AP_OFFLOAD_WAKEUP_EVT_RPT(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+3, 0, 8, __val) + +/* Keep Alive Control*/ +#define SET_88E_H2CCMD_KEEP_ALIVE_ENABLE(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 1, __val) +#define SET_88E_H2CCMD_KEEP_ALIVE_ACCPEPT_USER_DEFINED(__ph2ccmd, __val)\ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 1, 1, __val) +#define SET_88E_H2CCMD_KEEP_ALIVE_PERIOD(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val) + +/*REMOTE_WAKE_CTRL */ +#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_EN(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 1, __val) +#if (USE_OLD_WOWLAN_DEBUG_FW == 0) +#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_ARP_OFFLOAD_EN(__ph2ccmd, __val)\ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 1, 1, __val) +#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_NDP_OFFLOAD_EN(__ph2ccmd, __val)\ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 2, 1, __val) +#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_GTK_OFFLOAD_EN(__ph2ccmd, __val)\ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 3, 1, __val) +#else +#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_PAIRWISE_ENC_ALG(__ph2ccmd, __val)\ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val) +#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_GROUP_ENC_ALG(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val) +#endif + +/* GTK_OFFLOAD */ +#define SET_88E_H2CCMD_AOAC_GLOBAL_INFO_PAIRWISE_ENC_ALG(__ph2ccmd, __val)\ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_88E_H2CCMD_AOAC_GLOBAL_INFO_GROUP_ENC_ALG(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val) + +/* AOAC_RSVDPAGE_LOC */ +#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_REM_WAKE_CTRL_INFO(__ph2ccmd, __val)\ + SET_BITS_TO_LE_1BYTE((__ph2ccmd), 0, 8, __val) +#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_ARP_RSP(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val) +#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_NEIGHBOR_ADV(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val) +#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_RSP(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+3, 0, 8, __val) +#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_INFO(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+4, 0, 8, __val) + +void rtl8723be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); +void rtl8723be_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw, + u8 ap_offload_enable); +void rtl8723be_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, + u32 cmd_len, u8 *p_cmdbuffer); +void rtl8723be_firmware_selfreset(struct ieee80211_hw *hw); +void rtl8723be_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, + bool dl_finished); +void rtl8723be_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); +int rtl8723be_download_fw(struct ieee80211_hw *hw, + bool buse_wake_on_wlan_fw); +void rtl8723be_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, + u8 p2p_ps_state); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c new file mode 100644 index 000000000000..a500d266fae5 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c @@ -0,0 +1,2529 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../efuse.h" +#include "../base.h" +#include "../regd.h" +#include "../cam.h" +#include "../ps.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "../rtl8723com/dm_common.h" +#include "fw.h" +#include "../rtl8723com/fw_common.h" +#include "led.h" +#include "hw.h" +#include "pwrseqcmd.h" +#include "pwrseq.h" +#include "../btcoexist/rtl_btc.h" + +#define LLT_CONFIG 5 + +static void _rtl8723be_return_beacon_queue_skb(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE]; + + while (skb_queue_len(&ring->queue)) { + struct rtl_tx_desc *entry = &ring->desc[ring->idx]; + struct sk_buff *skb = __skb_dequeue(&ring->queue); + + pci_unmap_single(rtlpci->pdev, + rtlpriv->cfg->ops->get_desc( + (u8 *)entry, true, HW_DESC_TXBUFF_ADDR), + skb->len, PCI_DMA_TODEVICE); + kfree_skb(skb); + ring->idx = (ring->idx + 1) % ring->entries; + } +} + +static void _rtl8723be_set_bcn_ctrl_reg(struct ieee80211_hw *hw, + u8 set_bits, u8 clear_bits) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpci->reg_bcn_ctrl_val |= set_bits; + rtlpci->reg_bcn_ctrl_val &= ~clear_bits; + + rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlpci->reg_bcn_ctrl_val); +} + +static void _rtl8723be_stop_tx_beacon(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp1byte; + + tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte & (~BIT(6))); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0x64); + tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2); + tmp1byte &= ~(BIT(0)); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte); +} + +static void _rtl8723be_resume_tx_beacon(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmp1byte; + + tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte | BIT(6)); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff); + tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2); + tmp1byte |= BIT(1); + rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte); +} + +static void _rtl8723be_enable_bcn_sub_func(struct ieee80211_hw *hw) +{ + _rtl8723be_set_bcn_ctrl_reg(hw, 0, BIT(1)); +} + +static void _rtl8723be_disable_bcn_sub_func(struct ieee80211_hw *hw) +{ + _rtl8723be_set_bcn_ctrl_reg(hw, BIT(1), 0); +} + +static void _rtl8723be_set_fw_clock_on(struct ieee80211_hw *hw, u8 rpwm_val, + bool need_turn_off_ckk) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool support_remote_wake_up; + u32 count = 0, isr_regaddr, content; + bool schedule_timer = need_turn_off_ckk; + rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN, + (u8 *)(&support_remote_wake_up)); + + if (!rtlhal->fw_ready) + return; + if (!rtlpriv->psc.fw_current_inpsmode) + return; + + while (1) { + spin_lock_bh(&rtlpriv->locks.fw_ps_lock); + if (rtlhal->fw_clk_change_in_progress) { + while (rtlhal->fw_clk_change_in_progress) { + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + count++; + udelay(100); + if (count > 1000) + return; + spin_lock_bh(&rtlpriv->locks.fw_ps_lock); + } + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + } else { + rtlhal->fw_clk_change_in_progress = false; + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + break; + } + } + if (IS_IN_LOW_POWER_STATE_88E(rtlhal->fw_ps_state)) { + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_SET_RPWM, + (u8 *)(&rpwm_val)); + if (FW_PS_IS_ACK(rpwm_val)) { + isr_regaddr = REG_HISR; + content = rtl_read_dword(rtlpriv, isr_regaddr); + while (!(content & IMR_CPWM) && (count < 500)) { + udelay(50); + count++; + content = rtl_read_dword(rtlpriv, isr_regaddr); + } + + if (content & IMR_CPWM) { + rtl_write_word(rtlpriv, isr_regaddr, 0x0100); + rtlhal->fw_ps_state = FW_PS_STATE_RF_ON_88E; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Receive CPWM INT!!! Set " + "pHalData->FwPSState = %X\n", + rtlhal->fw_ps_state); + } + } + spin_lock_bh(&rtlpriv->locks.fw_ps_lock); + rtlhal->fw_clk_change_in_progress = false; + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + if (schedule_timer) { + mod_timer(&rtlpriv->works.fw_clockoff_timer, + jiffies + MSECS(10)); + } + } else { + spin_lock_bh(&rtlpriv->locks.fw_ps_lock); + rtlhal->fw_clk_change_in_progress = false; + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + } +} + +static void _rtl8723be_set_fw_clock_off(struct ieee80211_hw *hw, u8 rpwm_val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring; + enum rf_pwrstate rtstate; + bool schedule_timer = false; + u8 queue; + + if (!rtlhal->fw_ready) + return; + if (!rtlpriv->psc.fw_current_inpsmode) + return; + if (!rtlhal->allow_sw_to_change_hwclc) + return; + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RF_STATE, (u8 *)(&rtstate)); + if (rtstate == ERFOFF || rtlpriv->psc.inactive_pwrstate == ERFOFF) + return; + + for (queue = 0; queue < RTL_PCI_MAX_TX_QUEUE_COUNT; queue++) { + ring = &rtlpci->tx_ring[queue]; + if (skb_queue_len(&ring->queue)) { + schedule_timer = true; + break; + } + } + if (schedule_timer) { + mod_timer(&rtlpriv->works.fw_clockoff_timer, + jiffies + MSECS(10)); + return; + } + if (FW_PS_STATE(rtlhal->fw_ps_state) != + FW_PS_STATE_RF_OFF_LOW_PWR_88E) { + spin_lock_bh(&rtlpriv->locks.fw_ps_lock); + if (!rtlhal->fw_clk_change_in_progress) { + rtlhal->fw_clk_change_in_progress = true; + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + rtlhal->fw_ps_state = FW_PS_STATE(rpwm_val); + rtl_write_word(rtlpriv, REG_HISR, 0x0100); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, + (u8 *)(&rpwm_val)); + spin_lock_bh(&rtlpriv->locks.fw_ps_lock); + rtlhal->fw_clk_change_in_progress = false; + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + } else { + spin_unlock_bh(&rtlpriv->locks.fw_ps_lock); + mod_timer(&rtlpriv->works.fw_clockoff_timer, + jiffies + MSECS(10)); + } + } +} + +static void _rtl8723be_set_fw_ps_rf_on(struct ieee80211_hw *hw) +{ + u8 rpwm_val = 0; + rpwm_val |= (FW_PS_STATE_RF_OFF_88E | FW_PS_ACK); + _rtl8723be_set_fw_clock_on(hw, rpwm_val, true); +} + +static void _rtl8723be_fwlps_leave(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool fw_current_inps = false; + u8 rpwm_val = 0, fw_pwrmode = FW_PS_ACTIVE_MODE; + + if (ppsc->low_power_enable) { + rpwm_val = (FW_PS_STATE_ALL_ON_88E | FW_PS_ACK);/* RF on */ + _rtl8723be_set_fw_clock_on(hw, rpwm_val, false); + rtlhal->allow_sw_to_change_hwclc = false; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE, + (u8 *)(&fw_pwrmode)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, + (u8 *)(&fw_current_inps)); + } else { + rpwm_val = FW_PS_STATE_ALL_ON_88E; /* RF on */ + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, + (u8 *)(&rpwm_val)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE, + (u8 *)(&fw_pwrmode)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, + (u8 *)(&fw_current_inps)); + } +} + +static void _rtl8723be_fwlps_enter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool fw_current_inps = true; + u8 rpwm_val; + + if (ppsc->low_power_enable) { + rpwm_val = FW_PS_STATE_RF_OFF_LOW_PWR_88E; /* RF off */ + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, + (u8 *)(&fw_current_inps)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE, + (u8 *)(&ppsc->fwctrl_psmode)); + rtlhal->allow_sw_to_change_hwclc = true; + _rtl8723be_set_fw_clock_off(hw, rpwm_val); + + } else { + rpwm_val = FW_PS_STATE_RF_OFF_88E; /* RF off */ + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, + (u8 *)(&fw_current_inps)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE, + (u8 *)(&ppsc->fwctrl_psmode)); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, + (u8 *)(&rpwm_val)); + } +} + +void rtl8723be_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + switch (variable) { + case HW_VAR_RCR: + *((u32 *)(val)) = rtlpci->receive_config; + break; + case HW_VAR_RF_STATE: + *((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state; + break; + case HW_VAR_FWLPS_RF_ON: { + enum rf_pwrstate rfstate; + u32 val_rcr; + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RF_STATE, + (u8 *)(&rfstate)); + if (rfstate == ERFOFF) { + *((bool *)(val)) = true; + } else { + val_rcr = rtl_read_dword(rtlpriv, REG_RCR); + val_rcr &= 0x00070000; + if (val_rcr) + *((bool *)(val)) = false; + else + *((bool *)(val)) = true; + } + break; } + case HW_VAR_FW_PSMODE_STATUS: + *((bool *)(val)) = ppsc->fw_current_inpsmode; + break; + case HW_VAR_CORRECT_TSF: { + u64 tsf; + u32 *ptsf_low = (u32 *)&tsf; + u32 *ptsf_high = ((u32 *)&tsf) + 1; + + *ptsf_high = rtl_read_dword(rtlpriv, (REG_TSFTR + 4)); + *ptsf_low = rtl_read_dword(rtlpriv, REG_TSFTR); + + *((u64 *)(val)) = tsf; + + break; } + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not process %x\n", variable); + break; + } +} + +void rtl8723be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + u8 idx; + + switch (variable) { + case HW_VAR_ETHER_ADDR: + for (idx = 0; idx < ETH_ALEN; idx++) + rtl_write_byte(rtlpriv, (REG_MACID + idx), val[idx]); + break; + case HW_VAR_BASIC_RATE: { + u16 rate_cfg = ((u16 *)val)[0]; + u8 rate_index = 0; + rate_cfg = rate_cfg & 0x15f; + rate_cfg |= 0x01; + rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff); + rtl_write_byte(rtlpriv, REG_RRSR + 1, (rate_cfg >> 8) & 0xff); + while (rate_cfg > 0x1) { + rate_cfg = (rate_cfg >> 1); + rate_index++; + } + rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, rate_index); + break; } + case HW_VAR_BSSID: + for (idx = 0; idx < ETH_ALEN; idx++) + rtl_write_byte(rtlpriv, (REG_BSSID + idx), val[idx]); + break; + case HW_VAR_SIFS: + rtl_write_byte(rtlpriv, REG_SIFS_CTX + 1, val[0]); + rtl_write_byte(rtlpriv, REG_SIFS_TRX + 1, val[1]); + + rtl_write_byte(rtlpriv, REG_SPEC_SIFS + 1, val[0]); + rtl_write_byte(rtlpriv, REG_MAC_SPEC_SIFS + 1, val[0]); + + if (!mac->ht_enable) + rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM, 0x0e0e); + else + rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM, + *((u16 *)val)); + break; + case HW_VAR_SLOT_TIME: { + u8 e_aci; + + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + "HW_VAR_SLOT_TIME %x\n", val[0]); + + rtl_write_byte(rtlpriv, REG_SLOT, val[0]); + + for (e_aci = 0; e_aci < AC_MAX; e_aci++) { + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM, + (u8 *)(&e_aci)); + } + break; } + case HW_VAR_ACK_PREAMBLE: { + u8 reg_tmp; + u8 short_preamble = (bool) (*(u8 *)val); + reg_tmp = rtl_read_byte(rtlpriv, REG_TRXPTCL_CTL + 2); + if (short_preamble) { + reg_tmp |= 0x02; + rtl_write_byte(rtlpriv, REG_TRXPTCL_CTL + 2, reg_tmp); + } else { + reg_tmp &= 0xFD; + rtl_write_byte(rtlpriv, REG_TRXPTCL_CTL + 2, reg_tmp); + } + break; } + case HW_VAR_WPA_CONFIG: + rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *)val)); + break; + case HW_VAR_AMPDU_MIN_SPACE: { + u8 min_spacing_to_set; + u8 sec_min_space; + + min_spacing_to_set = *((u8 *)val); + if (min_spacing_to_set <= 7) { + sec_min_space = 0; + + if (min_spacing_to_set < sec_min_space) + min_spacing_to_set = sec_min_space; + + mac->min_space_cfg = ((mac->min_space_cfg & 0xf8) | + min_spacing_to_set); + + *val = min_spacing_to_set; + + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + "Set HW_VAR_AMPDU_MIN_SPACE: %#x\n", + mac->min_space_cfg); + + rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, + mac->min_space_cfg); + } + break; } + case HW_VAR_SHORTGI_DENSITY: { + u8 density_to_set; + + density_to_set = *((u8 *)val); + mac->min_space_cfg |= (density_to_set << 3); + + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + "Set HW_VAR_SHORTGI_DENSITY: %#x\n", + mac->min_space_cfg); + + rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, + mac->min_space_cfg); + break; } + case HW_VAR_AMPDU_FACTOR: { + u8 regtoset_normal[4] = {0x41, 0xa8, 0x72, 0xb9}; + u8 factor_toset; + u8 *p_regtoset = NULL; + u8 index = 0; + + p_regtoset = regtoset_normal; + + factor_toset = *((u8 *)val); + if (factor_toset <= 3) { + factor_toset = (1 << (factor_toset + 2)); + if (factor_toset > 0xf) + factor_toset = 0xf; + + for (index = 0; index < 4; index++) { + if ((p_regtoset[index] & 0xf0) > + (factor_toset << 4)) + p_regtoset[index] = + (p_regtoset[index] & 0x0f) | + (factor_toset << 4); + + if ((p_regtoset[index] & 0x0f) > factor_toset) + p_regtoset[index] = + (p_regtoset[index] & 0xf0) | + (factor_toset); + + rtl_write_byte(rtlpriv, + (REG_AGGLEN_LMT + index), + p_regtoset[index]); + } + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + "Set HW_VAR_AMPDU_FACTOR: %#x\n", + factor_toset); + } + break; } + case HW_VAR_AC_PARAM: { + u8 e_aci = *((u8 *)val); + rtl8723_dm_init_edca_turbo(hw); + + if (rtlpci->acm_method != EACMWAY2_SW) + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL, + (u8 *)(&e_aci)); + break; } + case HW_VAR_ACM_CTRL: { + u8 e_aci = *((u8 *)val); + union aci_aifsn *p_aci_aifsn = + (union aci_aifsn *)(&(mac->ac[0].aifs)); + u8 acm = p_aci_aifsn->f.acm; + u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL); + + acm_ctrl = + acm_ctrl | ((rtlpci->acm_method == 2) ? 0x0 : 0x1); + + if (acm) { + switch (e_aci) { + case AC0_BE: + acm_ctrl |= ACMHW_BEQEN; + break; + case AC2_VI: + acm_ctrl |= ACMHW_VIQEN; + break; + case AC3_VO: + acm_ctrl |= ACMHW_VOQEN; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "HW_VAR_ACM_CTRL acm set " + "failed: eACI is %d\n", acm); + break; + } + } else { + switch (e_aci) { + case AC0_BE: + acm_ctrl &= (~ACMHW_BEQEN); + break; + case AC2_VI: + acm_ctrl &= (~ACMHW_VIQEN); + break; + case AC3_VO: + acm_ctrl &= (~ACMHW_BEQEN); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not process\n"); + break; + } + } + RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE, + "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] " + "Write 0x%X\n", acm_ctrl); + rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl); + break; } + case HW_VAR_RCR: + rtl_write_dword(rtlpriv, REG_RCR, ((u32 *)(val))[0]); + rtlpci->receive_config = ((u32 *)(val))[0]; + break; + case HW_VAR_RETRY_LIMIT: { + u8 retry_limit = ((u8 *)(val))[0]; + + rtl_write_word(rtlpriv, REG_RL, + retry_limit << RETRY_LIMIT_SHORT_SHIFT | + retry_limit << RETRY_LIMIT_LONG_SHIFT); + break; } + case HW_VAR_DUAL_TSF_RST: + rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, (BIT(0) | BIT(1))); + break; + case HW_VAR_EFUSE_BYTES: + rtlefuse->efuse_usedbytes = *((u16 *)val); + break; + case HW_VAR_EFUSE_USAGE: + rtlefuse->efuse_usedpercentage = *((u8 *)val); + break; + case HW_VAR_IO_CMD: + rtl8723be_phy_set_io_cmd(hw, (*(enum io_type *)val)); + break; + case HW_VAR_SET_RPWM: { + u8 rpwm_val; + + rpwm_val = rtl_read_byte(rtlpriv, REG_PCIE_HRPWM); + udelay(1); + + if (rpwm_val & BIT(7)) { + rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, (*(u8 *)val)); + } else { + rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, + ((*(u8 *)val) | BIT(7))); + } + break; } + case HW_VAR_H2C_FW_PWRMODE: + rtl8723be_set_fw_pwrmode_cmd(hw, (*(u8 *)val)); + break; + case HW_VAR_FW_PSMODE_STATUS: + ppsc->fw_current_inpsmode = *((bool *)val); + break; + case HW_VAR_RESUME_CLK_ON: + _rtl8723be_set_fw_ps_rf_on(hw); + break; + case HW_VAR_FW_LPS_ACTION: { + bool enter_fwlps = *((bool *)val); + + if (enter_fwlps) + _rtl8723be_fwlps_enter(hw); + else + _rtl8723be_fwlps_leave(hw); + + break; } + case HW_VAR_H2C_FW_JOINBSSRPT: { + u8 mstatus = (*(u8 *)val); + u8 tmp_regcr, tmp_reg422, bcnvalid_reg; + u8 count = 0, dlbcn_count = 0; + bool recover = false; + + if (mstatus == RT_MEDIA_CONNECT) { + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID, NULL); + + tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1); + rtl_write_byte(rtlpriv, REG_CR + 1, + (tmp_regcr | BIT(0))); + + _rtl8723be_set_bcn_ctrl_reg(hw, 0, BIT(3)); + _rtl8723be_set_bcn_ctrl_reg(hw, BIT(4), 0); + + tmp_reg422 = rtl_read_byte(rtlpriv, + REG_FWHW_TXQ_CTRL + 2); + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, + tmp_reg422 & (~BIT(6))); + if (tmp_reg422 & BIT(6)) + recover = true; + + do { + bcnvalid_reg = rtl_read_byte(rtlpriv, + REG_TDECTRL + 2); + rtl_write_byte(rtlpriv, REG_TDECTRL + 2, + (bcnvalid_reg | BIT(0))); + _rtl8723be_return_beacon_queue_skb(hw); + + rtl8723be_set_fw_rsvdpagepkt(hw, 0); + bcnvalid_reg = rtl_read_byte(rtlpriv, + REG_TDECTRL + 2); + count = 0; + while (!(bcnvalid_reg & BIT(0)) && count < 20) { + count++; + udelay(10); + bcnvalid_reg = rtl_read_byte(rtlpriv, + REG_TDECTRL + 2); + } + dlbcn_count++; + } while (!(bcnvalid_reg & BIT(0)) && dlbcn_count < 5); + + if (bcnvalid_reg & BIT(0)) + rtl_write_byte(rtlpriv, REG_TDECTRL+2, BIT(0)); + + _rtl8723be_set_bcn_ctrl_reg(hw, BIT(3), 0); + _rtl8723be_set_bcn_ctrl_reg(hw, 0, BIT(4)); + + if (recover) { + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, + tmp_reg422); + } + rtl_write_byte(rtlpriv, REG_CR + 1, + (tmp_regcr & ~(BIT(0)))); + } + rtl8723be_set_fw_joinbss_report_cmd(hw, (*(u8 *)val)); + break; } + case HW_VAR_H2C_FW_P2P_PS_OFFLOAD: + rtl8723be_set_p2p_ps_offload_cmd(hw, (*(u8 *)val)); + break; + case HW_VAR_AID: { + u16 u2btmp; + u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT); + u2btmp &= 0xC000; + rtl_write_word(rtlpriv, REG_BCN_PSR_RPT, + (u2btmp | mac->assoc_id)); + break; } + case HW_VAR_CORRECT_TSF: { + u8 btype_ibss = ((u8 *)(val))[0]; + + if (btype_ibss) + _rtl8723be_stop_tx_beacon(hw); + + _rtl8723be_set_bcn_ctrl_reg(hw, 0, BIT(3)); + + rtl_write_dword(rtlpriv, REG_TSFTR, + (u32) (mac->tsf & 0xffffffff)); + rtl_write_dword(rtlpriv, REG_TSFTR + 4, + (u32) ((mac->tsf >> 32) & 0xffffffff)); + + _rtl8723be_set_bcn_ctrl_reg(hw, BIT(3), 0); + + if (btype_ibss) + _rtl8723be_resume_tx_beacon(hw); + break; } + case HW_VAR_KEEP_ALIVE: { + u8 array[2]; + array[0] = 0xff; + array[1] = *((u8 *)val); + rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_KEEP_ALIVE_CTRL, + 2, array); + break; } + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not process %x\n", + variable); + break; + } +} + +static bool _rtl8723be_llt_write(struct ieee80211_hw *hw, u32 address, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool status = true; + int count = 0; + u32 value = _LLT_INIT_ADDR(address) | _LLT_INIT_DATA(data) | + _LLT_OP(_LLT_WRITE_ACCESS); + + rtl_write_dword(rtlpriv, REG_LLT_INIT, value); + + do { + value = rtl_read_dword(rtlpriv, REG_LLT_INIT); + if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value)) + break; + + if (count > POLLING_LLT_THRESHOLD) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Failed to polling write LLT done at " + "address %d!\n", address); + status = false; + break; + } + } while (++count); + + return status; +} + +static bool _rtl8723be_llt_table_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + unsigned short i; + u8 txpktbuf_bndy; + u8 maxpage; + bool status; + + maxpage = 255; + txpktbuf_bndy = 245; + + rtl_write_dword(rtlpriv, REG_TRXFF_BNDY, + (0x27FF0000 | txpktbuf_bndy)); + rtl_write_byte(rtlpriv, REG_TDECTRL + 1, txpktbuf_bndy); + + rtl_write_byte(rtlpriv, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy); + rtl_write_byte(rtlpriv, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy); + + rtl_write_byte(rtlpriv, 0x45D, txpktbuf_bndy); + rtl_write_byte(rtlpriv, REG_PBP, 0x31); + rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, 0x4); + + for (i = 0; i < (txpktbuf_bndy - 1); i++) { + status = _rtl8723be_llt_write(hw, i, i + 1); + if (!status) + return status; + } + status = _rtl8723be_llt_write(hw, (txpktbuf_bndy - 1), 0xFF); + + if (!status) + return status; + + for (i = txpktbuf_bndy; i < maxpage; i++) { + status = _rtl8723be_llt_write(hw, i, (i + 1)); + if (!status) + return status; + } + status = _rtl8723be_llt_write(hw, maxpage, txpktbuf_bndy); + if (!status) + return status; + + rtl_write_dword(rtlpriv, REG_RQPN, 0x80e40808); + rtl_write_byte(rtlpriv, REG_RQPN_NPQ, 0x00); + + return true; +} + +static void _rtl8723be_gen_refresh_led_state(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_led *pled0 = &(pcipriv->ledctl.sw_led0); + + if (rtlpriv->rtlhal.up_first_time) + return; + + if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) + rtl8723be_sw_led_on(hw, pled0); + else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT) + rtl8723be_sw_led_on(hw, pled0); + else + rtl8723be_sw_led_off(hw, pled0); +} + +static bool _rtl8723be_init_mac(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + unsigned char bytetmp; + unsigned short wordtmp; + u16 retry = 0; + bool mac_func_enable; + + rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00); + + /*Auto Power Down to CHIP-off State*/ + bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1) & (~BIT(7)); + rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, bytetmp); + + bytetmp = rtl_read_byte(rtlpriv, REG_CR); + if (bytetmp == 0xFF) + mac_func_enable = true; + else + mac_func_enable = false; + + /* HW Power on sequence */ + if (!rtlbe_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, + PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, + RTL8723_NIC_ENABLE_FLOW)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "init MAC Fail as power on failure\n"); + return false; + } + bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO) | BIT(4); + rtl_write_byte(rtlpriv, REG_APS_FSMCO, bytetmp); + + bytetmp = rtl_read_byte(rtlpriv, REG_CR); + bytetmp = 0xff; + rtl_write_byte(rtlpriv, REG_CR, bytetmp); + mdelay(2); + + bytetmp = rtl_read_byte(rtlpriv, REG_HWSEQ_CTRL); + bytetmp |= 0x7f; + rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, bytetmp); + mdelay(2); + + bytetmp = rtl_read_byte(rtlpriv, REG_SYS_CFG + 3); + if (bytetmp & BIT(0)) { + bytetmp = rtl_read_byte(rtlpriv, 0x7c); + bytetmp |= BIT(6); + rtl_write_byte(rtlpriv, 0x7c, bytetmp); + } + bytetmp = rtl_read_byte(rtlpriv, REG_SYS_CLKR); + bytetmp |= BIT(3); + rtl_write_byte(rtlpriv, REG_SYS_CLKR, bytetmp); + bytetmp = rtl_read_byte(rtlpriv, REG_GPIO_MUXCFG + 1); + bytetmp &= ~BIT(4); + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG + 1, bytetmp); + + bytetmp = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG+3); + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG+3, bytetmp | 0x77); + + rtl_write_word(rtlpriv, REG_CR, 0x2ff); + + if (!mac_func_enable) { + if (!_rtl8723be_llt_table_init(hw)) + return false; + } + rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff); + rtl_write_dword(rtlpriv, REG_HISRE, 0xffffffff); + + /* Enable FW Beamformer Interrupt */ + bytetmp = rtl_read_byte(rtlpriv, REG_FWIMR + 3); + rtl_write_byte(rtlpriv, REG_FWIMR + 3, bytetmp | BIT(6)); + + wordtmp = rtl_read_word(rtlpriv, REG_TRXDMA_CTRL); + wordtmp &= 0xf; + wordtmp |= 0xF5B1; + rtl_write_word(rtlpriv, REG_TRXDMA_CTRL, wordtmp); + + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 1, 0x1F); + rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config); + rtl_write_word(rtlpriv, REG_RXFLTMAP2, 0xFFFF); + rtl_write_dword(rtlpriv, REG_TCR, rtlpci->transmit_config); + + rtl_write_byte(rtlpriv, 0x4d0, 0x0); + + rtl_write_dword(rtlpriv, REG_BCNQ_DESA, + ((u64) rtlpci->tx_ring[BEACON_QUEUE].dma) & + DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_MGQ_DESA, + (u64) rtlpci->tx_ring[MGNT_QUEUE].dma & + DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_VOQ_DESA, + (u64) rtlpci->tx_ring[VO_QUEUE].dma & DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_VIQ_DESA, + (u64) rtlpci->tx_ring[VI_QUEUE].dma & DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_BEQ_DESA, + (u64) rtlpci->tx_ring[BE_QUEUE].dma & DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_BKQ_DESA, + (u64) rtlpci->tx_ring[BK_QUEUE].dma & DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_HQ_DESA, + (u64) rtlpci->tx_ring[HIGH_QUEUE].dma & + DMA_BIT_MASK(32)); + rtl_write_dword(rtlpriv, REG_RX_DESA, + (u64) rtlpci->rx_ring[RX_MPDU_QUEUE].dma & + DMA_BIT_MASK(32)); + + bytetmp = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG + 3); + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 3, bytetmp | 0x77); + + rtl_write_dword(rtlpriv, REG_INT_MIG, 0); + + bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL); + rtl_write_byte(rtlpriv, REG_APSD_CTRL, bytetmp & ~BIT(6)); + + rtl_write_byte(rtlpriv, REG_SECONDARY_CCA_CTRL, 0x3); + + do { + retry++; + bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL); + } while ((retry < 200) && (bytetmp & BIT(7))); + + _rtl8723be_gen_refresh_led_state(hw); + + rtl_write_dword(rtlpriv, REG_MCUTST_1, 0x0); + + bytetmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL); + rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, bytetmp & ~BIT(2)); + + return true; +} + +static void _rtl8723be_hw_configure(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 reg_bw_opmode; + u32 reg_ratr, reg_prsr; + + reg_bw_opmode = BW_OPMODE_20MHZ; + reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG | + RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; + reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + + rtl_write_dword(rtlpriv, REG_RRSR, reg_prsr); + rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, 0xFF); +} + +static void _rtl8723be_enable_aspm_back_door(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + rtl_write_byte(rtlpriv, 0x34b, 0x93); + rtl_write_word(rtlpriv, 0x350, 0x870c); + rtl_write_byte(rtlpriv, 0x352, 0x1); + + if (ppsc->support_backdoor) + rtl_write_byte(rtlpriv, 0x349, 0x1b); + else + rtl_write_byte(rtlpriv, 0x349, 0x03); + + rtl_write_word(rtlpriv, 0x350, 0x2718); + rtl_write_byte(rtlpriv, 0x352, 0x1); +} + +void rtl8723be_enable_hw_security_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 sec_reg_value; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "PairwiseEncAlgorithm = %d GroupEncAlgorithm = %d\n", + rtlpriv->sec.pairwise_enc_algorithm, + rtlpriv->sec.group_enc_algorithm); + + if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "not open hw encryption\n"); + return; + } + sec_reg_value = SCR_TXENCENABLE | SCR_RXDECENABLE; + + if (rtlpriv->sec.use_defaultkey) { + sec_reg_value |= SCR_TXUSEDK; + sec_reg_value |= SCR_RXUSEDK; + } + sec_reg_value |= (SCR_RXBCUSEDK | SCR_TXBCUSEDK); + + rtl_write_byte(rtlpriv, REG_CR + 1, 0x02); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "The SECR-value %x\n", + sec_reg_value); + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value); +} + +int rtl8723be_hw_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + bool rtstatus = true; + int err; + u8 tmp_u1b; + unsigned long flags; + + /* reenable interrupts to not interfere with other devices */ + local_save_flags(flags); + local_irq_enable(); + + rtlpriv->rtlhal.being_init_adapter = true; + rtlpriv->intf_ops->disable_aspm(hw); + rtstatus = _rtl8723be_init_mac(hw); + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n"); + err = 1; + goto exit; + } + tmp_u1b = rtl_read_byte(rtlpriv, REG_SYS_CFG); + tmp_u1b &= 0x7F; + rtl_write_byte(rtlpriv, REG_SYS_CFG, tmp_u1b); + + err = rtl8723_download_fw(hw, true); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Failed to download FW. Init HW without FW now..\n"); + err = 1; + rtlhal->fw_ready = false; + goto exit; + } else { + rtlhal->fw_ready = true; + } + rtlhal->last_hmeboxnum = 0; + rtl8723be_phy_mac_config(hw); + /* because last function modify RCR, so we update + * rcr var here, or TP will unstable for receive_config + * is wrong, RX RCR_ACRC32 will cause TP unstabel & Rx + * RCR_APP_ICV will cause mac80211 unassoc for cisco 1252 + */ + rtlpci->receive_config = rtl_read_dword(rtlpriv, REG_RCR); + rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV); + rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config); + + rtl8723be_phy_bb_config(hw); + rtlphy->rf_mode = RF_OP_BY_SW_3WIRE; + rtl8723be_phy_rf_config(hw); + + rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0, + RF_CHNLBW, RFREG_OFFSET_MASK); + rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, (enum radio_path)1, + RF_CHNLBW, RFREG_OFFSET_MASK); + rtlphy->rfreg_chnlval[0] &= 0xFFF03FF; + rtlphy->rfreg_chnlval[0] |= (BIT(10) | BIT(11)); + + rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1); + rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1); + _rtl8723be_hw_configure(hw); + rtl_cam_reset_all_entry(hw); + rtl8723be_enable_hw_security_config(hw); + + ppsc->rfpwr_state = ERFON; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); + _rtl8723be_enable_aspm_back_door(hw); + rtlpriv->intf_ops->enable_aspm(hw); + + rtl8723be_bt_hw_init(hw); + + rtl_set_bbreg(hw, 0x64, BIT(20), 0); + rtl_set_bbreg(hw, 0x64, BIT(24), 0); + + rtl_set_bbreg(hw, 0x40, BIT(4), 0); + rtl_set_bbreg(hw, 0x40, BIT(3), 1); + + rtl_set_bbreg(hw, 0x944, BIT(0)|BIT(1), 0x3); + rtl_set_bbreg(hw, 0x930, 0xff, 0x77); + + rtl_set_bbreg(hw, 0x38, BIT(11), 0x1); + + rtl_set_bbreg(hw, 0xb2c, 0xffffffff, 0x80000000); + + if (ppsc->rfpwr_state == ERFON) { + rtl8723be_dm_check_txpower_tracking(hw); + rtl8723be_phy_lc_calibrate(hw); + } + tmp_u1b = efuse_read_1byte(hw, 0x1FA); + if (!(tmp_u1b & BIT(0))) { + rtl_set_rfreg(hw, RF90_PATH_A, 0x15, 0x0F, 0x05); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "PA BIAS path A\n"); + } + if (!(tmp_u1b & BIT(4))) { + tmp_u1b = rtl_read_byte(rtlpriv, 0x16); + tmp_u1b &= 0x0F; + rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x80); + udelay(10); + rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x90); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n"); + } + rtl8723be_dm_init(hw); +exit: + local_irq_restore(flags); + rtlpriv->rtlhal.being_init_adapter = false; + return err; +} + +static enum version_8723e _rtl8723be_read_chip_version(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + enum version_8723e version = VERSION_UNKNOWN; + u8 count = 0; + u8 value8; + u32 value32; + + rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0); + + value8 = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 2); + rtl_write_byte(rtlpriv, REG_APS_FSMCO + 2, value8 | BIT(0)); + + value8 = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1); + rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, value8 | BIT(0)); + + value8 = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1); + while (((value8 & BIT(0))) && (count++ < 100)) { + udelay(10); + value8 = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1); + } + count = 0; + value8 = rtl_read_byte(rtlpriv, REG_ROM_VERSION); + while ((value8 == 0) && (count++ < 50)) { + value8 = rtl_read_byte(rtlpriv, REG_ROM_VERSION); + mdelay(1); + } + value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG1); + if ((value32 & (CHIP_8723B)) != CHIP_8723B) + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "unkown chip version\n"); + else + version = (enum version_8723e) VERSION_TEST_CHIP_1T1R_8723B; + + rtlphy->rf_type = RF_1T1R; + + value8 = rtl_read_byte(rtlpriv, REG_ROM_VERSION); + if (value8 >= 0x02) + version |= BIT(3); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Chip RF Type: %s\n", (rtlphy->rf_type == RF_2T2R) ? + "RF_2T2R" : "RF_1T1R"); + + return version; +} + +static int _rtl8723be_set_media_status(struct ieee80211_hw *hw, + enum nl80211_iftype type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 bt_msr = rtl_read_byte(rtlpriv, MSR) & 0xfc; + enum led_ctl_mode ledaction = LED_CTL_NO_LINK; + + rtl_write_dword(rtlpriv, REG_BCN_CTRL, 0); + RT_TRACE(rtlpriv, COMP_BEACON, DBG_LOUD, + "clear 0x550 when set HW_VAR_MEDIA_STATUS\n"); + + if (type == NL80211_IFTYPE_UNSPECIFIED || + type == NL80211_IFTYPE_STATION) { + _rtl8723be_stop_tx_beacon(hw); + _rtl8723be_enable_bcn_sub_func(hw); + } else if (type == NL80211_IFTYPE_ADHOC || type == NL80211_IFTYPE_AP) { + _rtl8723be_resume_tx_beacon(hw); + _rtl8723be_disable_bcn_sub_func(hw); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Set HW_VAR_MEDIA_STATUS: " + "No such media status(%x).\n", type); + } + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + bt_msr |= MSR_NOLINK; + ledaction = LED_CTL_LINK; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to NO LINK!\n"); + break; + case NL80211_IFTYPE_ADHOC: + bt_msr |= MSR_ADHOC; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to Ad Hoc!\n"); + break; + case NL80211_IFTYPE_STATION: + bt_msr |= MSR_INFRA; + ledaction = LED_CTL_LINK; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to STA!\n"); + break; + case NL80211_IFTYPE_AP: + bt_msr |= MSR_AP; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Set Network type to AP!\n"); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Network type %d not support!\n", type); + return 1; + } + rtl_write_byte(rtlpriv, (MSR), bt_msr); + rtlpriv->cfg->ops->led_control(hw, ledaction); + if ((bt_msr & 0x03) == MSR_AP) + rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); + else + rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); + return 0; +} + +void rtl8723be_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u32 reg_rcr = rtlpci->receive_config; + + if (rtlpriv->psc.rfpwr_state != ERFON) + return; + + if (check_bssid) { + reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, + (u8 *)(®_rcr)); + _rtl8723be_set_bcn_ctrl_reg(hw, 0, BIT(4)); + } else if (!check_bssid) { + reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); + _rtl8723be_set_bcn_ctrl_reg(hw, BIT(4), 0); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, + (u8 *)(®_rcr)); + } +} + +int rtl8723be_set_network_type(struct ieee80211_hw *hw, + enum nl80211_iftype type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (_rtl8723be_set_media_status(hw, type)) + return -EOPNOTSUPP; + + if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { + if (type != NL80211_IFTYPE_AP) + rtl8723be_set_check_bssid(hw, true); + } else { + rtl8723be_set_check_bssid(hw, false); + } + return 0; +} + +/* don't set REG_EDCA_BE_PARAM here + * because mac80211 will send pkt when scan + */ +void rtl8723be_set_qos(struct ieee80211_hw *hw, int aci) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + rtl8723_dm_init_edca_turbo(hw); + switch (aci) { + case AC1_BK: + rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f); + break; + case AC0_BE: + break; + case AC2_VI: + rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322); + break; + case AC3_VO: + rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222); + break; + default: + RT_ASSERT(false, "invalid aci: %d !\n", aci); + break; + } +} + +void rtl8723be_enable_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF); + rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF); + rtlpci->irq_enabled = true; + /* there are some C2H CMDs have been sent + * before system interrupt is enabled, e.g., C2H, CPWM. + * So we need to clear all C2H events that FW has notified, + * otherwise FW won't schedule any commands anymore. + */ + rtl_write_byte(rtlpriv, REG_C2HEVT_CLEAR, 0); + /*enable system interrupt*/ + rtl_write_dword(rtlpriv, REG_HSIMR, rtlpci->sys_irq_mask & 0xFFFFFFFF); +} + +void rtl8723be_disable_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + rtl_write_dword(rtlpriv, REG_HIMR, IMR_DISABLED); + rtl_write_dword(rtlpriv, REG_HIMRE, IMR_DISABLED); + rtlpci->irq_enabled = false; + synchronize_irq(rtlpci->pdev->irq); +} + +static void _rtl8723be_poweroff_adapter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 u1b_tmp; + + /* Combo (PCIe + USB) Card and PCIe-MF Card */ + /* 1. Run LPS WL RFOFF flow */ + rtlbe_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, + PWR_INTF_PCI_MSK, RTL8723_NIC_LPS_ENTER_FLOW); + + /* 2. 0x1F[7:0] = 0 */ + /* turn off RF */ + rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00); + if ((rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) && + rtlhal->fw_ready) + rtl8723be_firmware_selfreset(hw); + + /* Reset MCU. Suggested by Filen. */ + u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2)))); + + /* g. MCUFWDL 0x80[1:0]= 0 */ + /* reset MCU ready status */ + rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); + + /* HW card disable configuration. */ + rtlbe_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, + PWR_INTF_PCI_MSK, RTL8723_NIC_DISABLE_FLOW); + + /* Reset MCU IO Wrapper */ + u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1); + rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0)))); + u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1); + rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, u1b_tmp | BIT(0)); + + /* 7. RSV_CTRL 0x1C[7:0] = 0x0E */ + /* lock ISO/CLK/Power control register */ + rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e); +} + +void rtl8723be_card_disable(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + enum nl80211_iftype opmode; + + mac->link_state = MAC80211_NOLINK; + opmode = NL80211_IFTYPE_UNSPECIFIED; + _rtl8723be_set_media_status(hw, opmode); + if (rtlpriv->rtlhal.driver_is_goingto_unload || + ppsc->rfoff_reason > RF_CHANGE_BY_PS) + rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + _rtl8723be_poweroff_adapter(hw); + + /* after power off we should do iqk again */ + rtlpriv->phy.iqk_initialized = false; +} + +void rtl8723be_interrupt_recognized(struct ieee80211_hw *hw, + u32 *p_inta, u32 *p_intb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + *p_inta = rtl_read_dword(rtlpriv, ISR) & rtlpci->irq_mask[0]; + rtl_write_dword(rtlpriv, ISR, *p_inta); + + *p_intb = rtl_read_dword(rtlpriv, REG_HISRE) & + rtlpci->irq_mask[1]; + rtl_write_dword(rtlpriv, REG_HISRE, *p_intb); +} + +void rtl8723be_set_beacon_related_registers(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 bcn_interval, atim_window; + + bcn_interval = mac->beacon_interval; + atim_window = 2; /*FIX MERGE */ + rtl8723be_disable_interrupt(hw); + rtl_write_word(rtlpriv, REG_ATIMWND, atim_window); + rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); + rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660f); + rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x18); + rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x18); + rtl_write_byte(rtlpriv, 0x606, 0x30); + rtl8723be_enable_interrupt(hw); +} + +void rtl8723be_set_beacon_interval(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 bcn_interval = mac->beacon_interval; + + RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG, + "beacon_interval:%d\n", bcn_interval); + rtl8723be_disable_interrupt(hw); + rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); + rtl8723be_enable_interrupt(hw); +} + +void rtl8723be_update_interrupt_mask(struct ieee80211_hw *hw, + u32 add_msr, u32 rm_msr) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, + "add_msr:%x, rm_msr:%x\n", add_msr, rm_msr); + + if (add_msr) + rtlpci->irq_mask[0] |= add_msr; + if (rm_msr) + rtlpci->irq_mask[0] &= (~rm_msr); + rtl8723be_disable_interrupt(hw); + rtl8723be_enable_interrupt(hw); +} + +static u8 _rtl8723be_get_chnl_group(u8 chnl) +{ + u8 group; + + if (chnl < 3) + group = 0; + else if (chnl < 9) + group = 1; + else + group = 2; + return group; +} + +static void _rtl8723be_read_power_value_fromprom(struct ieee80211_hw *hw, + struct txpower_info_2g *pw2g, + struct txpower_info_5g *pw5g, + bool autoload_fail, u8 *hwinfo) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 path, addr = EEPROM_TX_PWR_INX, group, cnt = 0; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "hal_ReadPowerValueFromPROM8723BE(): " + "PROMContent[0x%x]= 0x%x\n", + (addr + 1), hwinfo[addr + 1]); + if (0xFF == hwinfo[addr + 1]) /*YJ, add, 120316*/ + autoload_fail = true; + + if (autoload_fail) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "auto load fail : Use Default value!\n"); + for (path = 0; path < MAX_RF_PATH; path++) { + /* 2.4G default value */ + for (group = 0; group < MAX_CHNL_GROUP_24G; group++) { + pw2g->index_cck_base[path][group] = 0x2D; + pw2g->index_bw40_base[path][group] = 0x2D; + } + for (cnt = 0; cnt < MAX_TX_COUNT; cnt++) { + if (cnt == 0) { + pw2g->bw20_diff[path][0] = 0x02; + pw2g->ofdm_diff[path][0] = 0x04; + } else { + pw2g->bw20_diff[path][cnt] = 0xFE; + pw2g->bw40_diff[path][cnt] = 0xFE; + pw2g->cck_diff[path][cnt] = 0xFE; + pw2g->ofdm_diff[path][cnt] = 0xFE; + } + } + } + return; + } + for (path = 0; path < MAX_RF_PATH; path++) { + /*2.4G default value*/ + for (group = 0; group < MAX_CHNL_GROUP_24G; group++) { + pw2g->index_cck_base[path][group] = hwinfo[addr++]; + if (pw2g->index_cck_base[path][group] == 0xFF) + pw2g->index_cck_base[path][group] = 0x2D; + } + for (group = 0; group < MAX_CHNL_GROUP_24G - 1; group++) { + pw2g->index_bw40_base[path][group] = hwinfo[addr++]; + if (pw2g->index_bw40_base[path][group] == 0xFF) + pw2g->index_bw40_base[path][group] = 0x2D; + } + for (cnt = 0; cnt < MAX_TX_COUNT; cnt++) { + if (cnt == 0) { + pw2g->bw40_diff[path][cnt] = 0; + if (hwinfo[addr] == 0xFF) { + pw2g->bw20_diff[path][cnt] = 0x02; + } else { + pw2g->bw20_diff[path][cnt] = + (hwinfo[addr] & 0xf0) >> 4; + /*bit sign number to 8 bit sign number*/ + if (pw2g->bw20_diff[path][cnt] & BIT(3)) + pw2g->bw20_diff[path][cnt] |= 0xF0; + } + if (hwinfo[addr] == 0xFF) { + pw2g->ofdm_diff[path][cnt] = 0x04; + } else { + pw2g->ofdm_diff[path][cnt] = + (hwinfo[addr] & 0x0f); + /*bit sign number to 8 bit sign number*/ + if (pw2g->ofdm_diff[path][cnt] & BIT(3)) + pw2g->ofdm_diff[path][cnt] |= + 0xF0; + } + pw2g->cck_diff[path][cnt] = 0; + addr++; + } else { + if (hwinfo[addr] == 0xFF) { + pw2g->bw40_diff[path][cnt] = 0xFE; + } else { + pw2g->bw40_diff[path][cnt] = + (hwinfo[addr] & 0xf0) >> 4; + if (pw2g->bw40_diff[path][cnt] & BIT(3)) + pw2g->bw40_diff[path][cnt] |= + 0xF0; + } + if (hwinfo[addr] == 0xFF) { + pw2g->bw20_diff[path][cnt] = 0xFE; + } else { + pw2g->bw20_diff[path][cnt] = + (hwinfo[addr] & 0x0f); + if (pw2g->bw20_diff[path][cnt] & BIT(3)) + pw2g->bw20_diff[path][cnt] |= + 0xF0; + } + addr++; + + if (hwinfo[addr] == 0xFF) { + pw2g->ofdm_diff[path][cnt] = 0xFE; + } else { + pw2g->ofdm_diff[path][cnt] = + (hwinfo[addr] & 0xf0) >> 4; + if (pw2g->ofdm_diff[path][cnt] & BIT(3)) + pw2g->ofdm_diff[path][cnt] |= + 0xF0; + } + if (hwinfo[addr] == 0xFF) { + pw2g->cck_diff[path][cnt] = 0xFE; + } else { + pw2g->cck_diff[path][cnt] = + (hwinfo[addr] & 0x0f); + if (pw2g->cck_diff[path][cnt] & BIT(3)) + pw2g->cck_diff[path][cnt] |= + 0xF0; + } + addr++; + } + } + /*5G default value*/ + for (group = 0; group < MAX_CHNL_GROUP_5G; group++) { + pw5g->index_bw40_base[path][group] = hwinfo[addr++]; + if (pw5g->index_bw40_base[path][group] == 0xFF) + pw5g->index_bw40_base[path][group] = 0xFE; + } + for (cnt = 0; cnt < MAX_TX_COUNT; cnt++) { + if (cnt == 0) { + pw5g->bw40_diff[path][cnt] = 0; + + if (hwinfo[addr] == 0xFF) { + pw5g->bw20_diff[path][cnt] = 0; + } else { + pw5g->bw20_diff[path][0] = + (hwinfo[addr] & 0xf0) >> 4; + if (pw5g->bw20_diff[path][cnt] & BIT(3)) + pw5g->bw20_diff[path][cnt] |= + 0xF0; + } + if (hwinfo[addr] == 0xFF) { + pw5g->ofdm_diff[path][cnt] = 0x04; + } else { + pw5g->ofdm_diff[path][0] = + (hwinfo[addr] & 0x0f); + if (pw5g->ofdm_diff[path][cnt] & BIT(3)) + pw5g->ofdm_diff[path][cnt] |= + 0xF0; + } + addr++; + } else { + if (hwinfo[addr] == 0xFF) { + pw5g->bw40_diff[path][cnt] = 0xFE; + } else { + pw5g->bw40_diff[path][cnt] = + (hwinfo[addr] & 0xf0) >> 4; + if (pw5g->bw40_diff[path][cnt] & BIT(3)) + pw5g->bw40_diff[path][cnt] |= 0xF0; + } + if (hwinfo[addr] == 0xFF) { + pw5g->bw20_diff[path][cnt] = 0xFE; + } else { + pw5g->bw20_diff[path][cnt] = + (hwinfo[addr] & 0x0f); + if (pw5g->bw20_diff[path][cnt] & BIT(3)) + pw5g->bw20_diff[path][cnt] |= 0xF0; + } + addr++; + } + } + if (hwinfo[addr] == 0xFF) { + pw5g->ofdm_diff[path][1] = 0xFE; + pw5g->ofdm_diff[path][2] = 0xFE; + } else { + pw5g->ofdm_diff[path][1] = (hwinfo[addr] & 0xf0) >> 4; + pw5g->ofdm_diff[path][2] = (hwinfo[addr] & 0x0f); + } + addr++; + + if (hwinfo[addr] == 0xFF) + pw5g->ofdm_diff[path][3] = 0xFE; + else + pw5g->ofdm_diff[path][3] = (hwinfo[addr] & 0x0f); + addr++; + + for (cnt = 1; cnt < MAX_TX_COUNT; cnt++) { + if (pw5g->ofdm_diff[path][cnt] == 0xFF) + pw5g->ofdm_diff[path][cnt] = 0xFE; + else if (pw5g->ofdm_diff[path][cnt] & BIT(3)) + pw5g->ofdm_diff[path][cnt] |= 0xF0; + } + } +} + +static void _rtl8723be_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, + u8 *hwinfo) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct txpower_info_2g pw2g; + struct txpower_info_5g pw5g; + u8 rf_path, index; + u8 i; + + _rtl8723be_read_power_value_fromprom(hw, &pw2g, &pw5g, autoload_fail, + hwinfo); + + for (rf_path = 0; rf_path < 2; rf_path++) { + for (i = 0; i < 14; i++) { + index = _rtl8723be_get_chnl_group(i+1); + + rtlefuse->txpwrlevel_cck[rf_path][i] = + pw2g.index_cck_base[rf_path][index]; + rtlefuse->txpwrlevel_ht40_1s[rf_path][i] = + pw2g.index_bw40_base[rf_path][index]; + } + for (i = 0; i < MAX_TX_COUNT; i++) { + rtlefuse->txpwr_ht20diff[rf_path][i] = + pw2g.bw20_diff[rf_path][i]; + rtlefuse->txpwr_ht40diff[rf_path][i] = + pw2g.bw40_diff[rf_path][i]; + rtlefuse->txpwr_legacyhtdiff[rf_path][i] = + pw2g.ofdm_diff[rf_path][i]; + } + for (i = 0; i < 14; i++) { + RTPRINT(rtlpriv, FINIT, INIT_EEPROM, + "RF(%d)-Ch(%d) [CCK / HT40_1S ] = " + "[0x%x / 0x%x ]\n", rf_path, i, + rtlefuse->txpwrlevel_cck[rf_path][i], + rtlefuse->txpwrlevel_ht40_1s[rf_path][i]); + } + } + if (!autoload_fail) + rtlefuse->eeprom_thermalmeter = + hwinfo[EEPROM_THERMAL_METER_88E]; + else + rtlefuse->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER; + + if (rtlefuse->eeprom_thermalmeter == 0xff || autoload_fail) { + rtlefuse->apk_thermalmeterignore = true; + rtlefuse->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER; + } + rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter; + RTPRINT(rtlpriv, FINIT, INIT_EEPROM, + "thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter); + + if (!autoload_fail) { + rtlefuse->eeprom_regulatory = + hwinfo[EEPROM_RF_BOARD_OPTION_88E] & 0x07;/*bit0~2*/ + if (hwinfo[EEPROM_RF_BOARD_OPTION_88E] == 0xFF) + rtlefuse->eeprom_regulatory = 0; + } else { + rtlefuse->eeprom_regulatory = 0; + } + RTPRINT(rtlpriv, FINIT, INIT_EEPROM, + "eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory); +} + +static void _rtl8723be_read_adapter_info(struct ieee80211_hw *hw, + bool pseudo_test) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u16 i, usvalue; + u8 hwinfo[HWSET_MAX_SIZE]; + u16 eeprom_id; + bool is_toshiba_smid1 = false; + bool is_toshiba_smid2 = false; + bool is_samsung_smid = false; + bool is_lenovo_smid = false; + u16 toshiba_smid1[] = { + 0x6151, 0x6152, 0x6154, 0x6155, 0x6177, 0x6178, 0x6179, 0x6180, + 0x7151, 0x7152, 0x7154, 0x7155, 0x7177, 0x7178, 0x7179, 0x7180, + 0x8151, 0x8152, 0x8154, 0x8155, 0x8181, 0x8182, 0x8184, 0x8185, + 0x9151, 0x9152, 0x9154, 0x9155, 0x9181, 0x9182, 0x9184, 0x9185 + }; + u16 toshiba_smid2[] = { + 0x6181, 0x6184, 0x6185, 0x7181, 0x7182, 0x7184, 0x7185, 0x8181, + 0x8182, 0x8184, 0x8185, 0x9181, 0x9182, 0x9184, 0x9185 + }; + u16 samsung_smid[] = { + 0x6191, 0x6192, 0x6193, 0x7191, 0x7192, 0x7193, 0x8191, 0x8192, + 0x8193, 0x9191, 0x9192, 0x9193 + }; + u16 lenovo_smid[] = { + 0x8195, 0x9195, 0x7194, 0x8200, 0x8201, 0x8202, 0x9199, 0x9200 + }; + + if (pseudo_test) { + /* needs to be added */ + return; + } + if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { + rtl_efuse_shadow_map_update(hw); + + memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + HWSET_MAX_SIZE); + } else if (rtlefuse->epromtype == EEPROM_93C46) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "RTL819X Not boot from eeprom, check it !!"); + } + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"), + hwinfo, HWSET_MAX_SIZE); + + eeprom_id = *((u16 *)&hwinfo[0]); + if (eeprom_id != RTL8723BE_EEPROM_ID) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "EEPROM ID(%#x) is invalid!!\n", eeprom_id); + rtlefuse->autoload_failflag = true; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); + rtlefuse->autoload_failflag = false; + } + if (rtlefuse->autoload_failflag) + return; + + rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID]; + rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID]; + rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID]; + rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID]; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROMId = 0x%4x\n", eeprom_id); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid); + + for (i = 0; i < 6; i += 2) { + usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i]; + *((u16 *)(&rtlefuse->dev_addr[i])) = usvalue; + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "dev_addr: %pM\n", + rtlefuse->dev_addr); + + /*parse xtal*/ + rtlefuse->crystalcap = hwinfo[EEPROM_XTAL_8723BE]; + if (rtlefuse->crystalcap == 0xFF) + rtlefuse->crystalcap = 0x20; + + _rtl8723be_read_txpower_info_from_hwpg(hw, rtlefuse->autoload_failflag, + hwinfo); + + rtl8723be_read_bt_coexist_info_from_hwpg(hw, + rtlefuse->autoload_failflag, + hwinfo); + + rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN]; + rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION]; + rtlefuse->txpwr_fromeprom = true; + rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID]; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid); + + /* set channel plan to world wide 13 */ + rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13; + + if (rtlhal->oem_id == RT_CID_DEFAULT) { + /* Does this one have a Toshiba SMID from group 1? */ + for (i = 0; i < sizeof(toshiba_smid1) / sizeof(u16); i++) { + if (rtlefuse->eeprom_smid == toshiba_smid1[i]) { + is_toshiba_smid1 = true; + break; + } + } + /* Does this one have a Toshiba SMID from group 2? */ + for (i = 0; i < sizeof(toshiba_smid2) / sizeof(u16); i++) { + if (rtlefuse->eeprom_smid == toshiba_smid2[i]) { + is_toshiba_smid2 = true; + break; + } + } + /* Does this one have a Samsung SMID? */ + for (i = 0; i < sizeof(samsung_smid) / sizeof(u16); i++) { + if (rtlefuse->eeprom_smid == samsung_smid[i]) { + is_samsung_smid = true; + break; + } + } + /* Does this one have a Lenovo SMID? */ + for (i = 0; i < sizeof(lenovo_smid) / sizeof(u16); i++) { + if (rtlefuse->eeprom_smid == lenovo_smid[i]) { + is_lenovo_smid = true; + break; + } + } + switch (rtlefuse->eeprom_oemid) { + case EEPROM_CID_DEFAULT: + if (rtlefuse->eeprom_did == 0x8176) { + if (rtlefuse->eeprom_svid == 0x10EC && + is_toshiba_smid1) { + rtlhal->oem_id = RT_CID_TOSHIBA; + } else if (rtlefuse->eeprom_svid == 0x1025) { + rtlhal->oem_id = RT_CID_819X_ACER; + } else if (rtlefuse->eeprom_svid == 0x10EC && + is_samsung_smid) { + rtlhal->oem_id = RT_CID_819X_SAMSUNG; + } else if (rtlefuse->eeprom_svid == 0x10EC && + is_lenovo_smid) { + rtlhal->oem_id = RT_CID_819X_LENOVO; + } else if ((rtlefuse->eeprom_svid == 0x10EC && + rtlefuse->eeprom_smid == 0x8197) || + (rtlefuse->eeprom_svid == 0x10EC && + rtlefuse->eeprom_smid == 0x9196)) { + rtlhal->oem_id = RT_CID_819X_CLEVO; + } else if ((rtlefuse->eeprom_svid == 0x1028 && + rtlefuse->eeprom_smid == 0x8194) || + (rtlefuse->eeprom_svid == 0x1028 && + rtlefuse->eeprom_smid == 0x8198) || + (rtlefuse->eeprom_svid == 0x1028 && + rtlefuse->eeprom_smid == 0x9197) || + (rtlefuse->eeprom_svid == 0x1028 && + rtlefuse->eeprom_smid == 0x9198)) { + rtlhal->oem_id = RT_CID_819X_DELL; + } else if ((rtlefuse->eeprom_svid == 0x103C && + rtlefuse->eeprom_smid == 0x1629)) { + rtlhal->oem_id = RT_CID_819X_HP; + } else if ((rtlefuse->eeprom_svid == 0x1A32 && + rtlefuse->eeprom_smid == 0x2315)) { + rtlhal->oem_id = RT_CID_819X_QMI; + } else if ((rtlefuse->eeprom_svid == 0x10EC && + rtlefuse->eeprom_smid == 0x8203)) { + rtlhal->oem_id = RT_CID_819X_PRONETS; + } else if ((rtlefuse->eeprom_svid == 0x1043 && + rtlefuse->eeprom_smid == 0x84B5)) { + rtlhal->oem_id = RT_CID_819X_EDIMAX_ASUS; + } else { + rtlhal->oem_id = RT_CID_DEFAULT; + } + } else if (rtlefuse->eeprom_did == 0x8178) { + if (rtlefuse->eeprom_svid == 0x10EC && + is_toshiba_smid2) + rtlhal->oem_id = RT_CID_TOSHIBA; + else if (rtlefuse->eeprom_svid == 0x1025) + rtlhal->oem_id = RT_CID_819X_ACER; + else if ((rtlefuse->eeprom_svid == 0x10EC && + rtlefuse->eeprom_smid == 0x8186)) + rtlhal->oem_id = RT_CID_819X_PRONETS; + else if ((rtlefuse->eeprom_svid == 0x1043 && + rtlefuse->eeprom_smid == 0x84B6)) + rtlhal->oem_id = + RT_CID_819X_EDIMAX_ASUS; + else + rtlhal->oem_id = RT_CID_DEFAULT; + } else { + rtlhal->oem_id = RT_CID_DEFAULT; + } + break; + case EEPROM_CID_TOSHIBA: + rtlhal->oem_id = RT_CID_TOSHIBA; + break; + case EEPROM_CID_CCX: + rtlhal->oem_id = RT_CID_CCX; + break; + case EEPROM_CID_QMI: + rtlhal->oem_id = RT_CID_819X_QMI; + break; + case EEPROM_CID_WHQL: + break; + default: + rtlhal->oem_id = RT_CID_DEFAULT; + break; + } + } +} + +static void _rtl8723be_hal_customized_behavior(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + pcipriv->ledctl.led_opendrain = true; + switch (rtlhal->oem_id) { + case RT_CID_819X_HP: + pcipriv->ledctl.led_opendrain = true; + break; + case RT_CID_819X_LENOVO: + case RT_CID_DEFAULT: + case RT_CID_TOSHIBA: + case RT_CID_CCX: + case RT_CID_819X_ACER: + case RT_CID_WHQL: + default: + break; + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + "RT Customized ID: 0x%02X\n", rtlhal->oem_id); +} + +void rtl8723be_read_eeprom_info(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 tmp_u1b; + + rtlhal->version = _rtl8723be_read_chip_version(hw); + if (get_rf_type(rtlphy) == RF_1T1R) + rtlpriv->dm.rfpath_rxenable[0] = true; + else + rtlpriv->dm.rfpath_rxenable[0] = + rtlpriv->dm.rfpath_rxenable[1] = true; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "VersionID = 0x%4x\n", + rtlhal->version); + tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR); + if (tmp_u1b & BIT(4)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EEPROM\n"); + rtlefuse->epromtype = EEPROM_93C46; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EFUSE\n"); + rtlefuse->epromtype = EEPROM_BOOT_EFUSE; + } + if (tmp_u1b & BIT(5)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n"); + rtlefuse->autoload_failflag = false; + _rtl8723be_read_adapter_info(hw, false); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Autoload ERR!!\n"); + } + _rtl8723be_hal_customized_behavior(hw); +} + +static void rtl8723be_update_hal_rate_table(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 ratr_value; + u8 ratr_index = 0; + u8 nmode = mac->ht_enable; + u8 mimo_ps = IEEE80211_SMPS_OFF; + u16 shortgi_rate; + u32 tmp_ratr_value; + u8 curtxbw_40mhz = mac->bw_40; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = mac->mode; + + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_value = sta->supp_rates[1] << 4; + else + ratr_value = sta->supp_rates[0]; + if (mac->opmode == NL80211_IFTYPE_ADHOC) + ratr_value = 0xfff; + ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); + switch (wirelessmode) { + case WIRELESS_MODE_B: + if (ratr_value & 0x0000000c) + ratr_value &= 0x0000000d; + else + ratr_value &= 0x0000000f; + break; + case WIRELESS_MODE_G: + ratr_value &= 0x00000FF5; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + nmode = 1; + if (mimo_ps == IEEE80211_SMPS_STATIC) { + ratr_value &= 0x0007F005; + } else { + u32 ratr_mask; + + if (get_rf_type(rtlphy) == RF_1T2R || + get_rf_type(rtlphy) == RF_1T1R) + ratr_mask = 0x000ff005; + else + ratr_mask = 0x0f0ff005; + ratr_value &= ratr_mask; + } + break; + default: + if (rtlphy->rf_type == RF_1T2R) + ratr_value &= 0x000ff0ff; + else + ratr_value &= 0x0f0ff0ff; + break; + } + if ((rtlpriv->btcoexist.bt_coexistence) && + (rtlpriv->btcoexist.bt_coexist_type == BT_CSR_BC4) && + (rtlpriv->btcoexist.bt_cur_state) && + (rtlpriv->btcoexist.bt_ant_isolation) && + ((rtlpriv->btcoexist.bt_service == BT_SCO) || + (rtlpriv->btcoexist.bt_service == BT_BUSY))) + ratr_value &= 0x0fffcfc0; + else + ratr_value &= 0x0FFFFFFF; + + if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) || + (!curtxbw_40mhz && curshortgi_20mhz))) { + ratr_value |= 0x10000000; + tmp_ratr_value = (ratr_value >> 12); + + for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) { + if ((1 << shortgi_rate) & tmp_ratr_value) + break; + } + shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) | + (shortgi_rate << 4) | (shortgi_rate); + } + rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value); + + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, + "%x\n", rtl_read_dword(rtlpriv, REG_ARFR0)); +} + +static u8 _rtl8723be_mrate_idx_to_arfr_id(struct ieee80211_hw *hw, + u8 rate_index) +{ + u8 ret = 0; + + switch (rate_index) { + case RATR_INX_WIRELESS_NGB: + ret = 1; + break; + case RATR_INX_WIRELESS_N: + case RATR_INX_WIRELESS_NG: + ret = 5; + break; + case RATR_INX_WIRELESS_NB: + ret = 3; + break; + case RATR_INX_WIRELESS_GB: + ret = 6; + break; + case RATR_INX_WIRELESS_G: + ret = 7; + break; + case RATR_INX_WIRELESS_B: + ret = 8; + break; + default: + ret = 0; + break; + } + return ret; +} + +static void rtl8723be_update_hal_rate_mask(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 rssi_level) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; + u32 ratr_bitmap; + u8 ratr_index; + u8 curtxbw_40mhz = (sta->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40) ? 1 : 0; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = 0; + bool shortgi = false; + u8 rate_mask[7]; + u8 macid = 0; + u8 mimo_ps = IEEE80211_SMPS_OFF; + + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + wirelessmode = sta_entry->wireless_mode; + if (mac->opmode == NL80211_IFTYPE_STATION || + mac->opmode == NL80211_IFTYPE_MESH_POINT) + curtxbw_40mhz = mac->bw_40; + else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) + macid = sta->aid + 1; + + ratr_bitmap = sta->supp_rates[0]; + + if (mac->opmode == NL80211_IFTYPE_ADHOC) + ratr_bitmap = 0xfff; + + ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); + switch (wirelessmode) { + case WIRELESS_MODE_B: + ratr_index = RATR_INX_WIRELESS_B; + if (ratr_bitmap & 0x0000000c) + ratr_bitmap &= 0x0000000d; + else + ratr_bitmap &= 0x0000000f; + break; + case WIRELESS_MODE_G: + ratr_index = RATR_INX_WIRELESS_GB; + + if (rssi_level == 1) + ratr_bitmap &= 0x00000f00; + else if (rssi_level == 2) + ratr_bitmap &= 0x00000ff0; + else + ratr_bitmap &= 0x00000ff5; + break; + case WIRELESS_MODE_A: + ratr_index = RATR_INX_WIRELESS_A; + ratr_bitmap &= 0x00000ff0; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + ratr_index = RATR_INX_WIRELESS_NGB; + + if (mimo_ps == IEEE80211_SMPS_STATIC || + mimo_ps == IEEE80211_SMPS_DYNAMIC) { + if (rssi_level == 1) + ratr_bitmap &= 0x00070000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0007f000; + else + ratr_bitmap &= 0x0007f005; + } else { + if (rtlphy->rf_type == RF_1T1R) { + if (curtxbw_40mhz) { + if (rssi_level == 1) + ratr_bitmap &= 0x000f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x000ff000; + else + ratr_bitmap &= 0x000ff015; + } else { + if (rssi_level == 1) + ratr_bitmap &= 0x000f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x000ff000; + else + ratr_bitmap &= 0x000ff005; + } + } else { + if (curtxbw_40mhz) { + if (rssi_level == 1) + ratr_bitmap &= 0x0f8f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0f8ff000; + else + ratr_bitmap &= 0x0f8ff015; + } else { + if (rssi_level == 1) + ratr_bitmap &= 0x0f8f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0f8ff000; + else + ratr_bitmap &= 0x0f8ff005; + } + } + } + if ((curtxbw_40mhz && curshortgi_40mhz) || + (!curtxbw_40mhz && curshortgi_20mhz)) { + if (macid == 0) + shortgi = true; + else if (macid == 1) + shortgi = false; + } + break; + default: + ratr_index = RATR_INX_WIRELESS_NGB; + + if (rtlphy->rf_type == RF_1T2R) + ratr_bitmap &= 0x000ff0ff; + else + ratr_bitmap &= 0x0f0ff0ff; + break; + } + sta_entry->ratr_index = ratr_index; + + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, + "ratr_bitmap :%x\n", ratr_bitmap); + *(u32 *)&rate_mask = EF4BYTE((ratr_bitmap & 0x0fffffff) | + (ratr_index << 28)); + rate_mask[0] = macid; + rate_mask[1] = _rtl8723be_mrate_idx_to_arfr_id(hw, ratr_index) | + (shortgi ? 0x80 : 0x00); + rate_mask[2] = curtxbw_40mhz; + /* if (prox_priv->proxim_modeinfo->power_output > 0) + * rate_mask[2] |= BIT(6); + */ + + rate_mask[3] = (u8)(ratr_bitmap & 0x000000ff); + rate_mask[4] = (u8)((ratr_bitmap & 0x0000ff00) >> 8); + rate_mask[5] = (u8)((ratr_bitmap & 0x00ff0000) >> 16); + rate_mask[6] = (u8)((ratr_bitmap & 0xff000000) >> 24); + + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, + "Rate_index:%x, ratr_val:%x, %x:%x:%x:%x:%x:%x:%x\n", + ratr_index, ratr_bitmap, + rate_mask[0], rate_mask[1], + rate_mask[2], rate_mask[3], + rate_mask[4], rate_mask[5], + rate_mask[6]); + rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_RA_MASK, 7, rate_mask); + _rtl8723be_set_bcn_ctrl_reg(hw, BIT(3), 0); +} + +void rtl8723be_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 rssi_level) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + if (rtlpriv->dm.useramask) + rtl8723be_update_hal_rate_mask(hw, sta, rssi_level); + else + rtl8723be_update_hal_rate_table(hw, sta); +} + +void rtl8723be_update_channel_access_setting(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 sifs_timer; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, + (u8 *)&mac->slot_time); + if (!mac->ht_enable) + sifs_timer = 0x0a0a; + else + sifs_timer = 0x0e0e; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer); +} + +bool rtl8723be_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate; + u8 u1tmp; + bool actuallyset = false; + + if (rtlpriv->rtlhal.being_init_adapter) + return false; + + if (ppsc->swrf_processing) + return false; + + spin_lock(&rtlpriv->locks.rf_ps_lock); + if (ppsc->rfchange_inprogress) { + spin_unlock(&rtlpriv->locks.rf_ps_lock); + return false; + } else { + ppsc->rfchange_inprogress = true; + spin_unlock(&rtlpriv->locks.rf_ps_lock); + } + cur_rfstate = ppsc->rfpwr_state; + + rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL_2, + rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL_2) & ~(BIT(1))); + + u1tmp = rtl_read_byte(rtlpriv, REG_GPIO_PIN_CTRL_2); + + if (rtlphy->polarity_ctl) + e_rfpowerstate_toset = (u1tmp & BIT(1)) ? ERFOFF : ERFON; + else + e_rfpowerstate_toset = (u1tmp & BIT(1)) ? ERFON : ERFOFF; + + if (ppsc->hwradiooff && + (e_rfpowerstate_toset == ERFON)) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "GPIOChangeRF - HW Radio ON, RF ON\n"); + + e_rfpowerstate_toset = ERFON; + ppsc->hwradiooff = false; + actuallyset = true; + } else if (!ppsc->hwradiooff && + (e_rfpowerstate_toset == ERFOFF)) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "GPIOChangeRF - HW Radio OFF, RF OFF\n"); + + e_rfpowerstate_toset = ERFOFF; + ppsc->hwradiooff = true; + actuallyset = true; + } + if (actuallyset) { + spin_lock(&rtlpriv->locks.rf_ps_lock); + ppsc->rfchange_inprogress = false; + spin_unlock(&rtlpriv->locks.rf_ps_lock); + } else { + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + + spin_lock(&rtlpriv->locks.rf_ps_lock); + ppsc->rfchange_inprogress = false; + spin_unlock(&rtlpriv->locks.rf_ps_lock); + } + *valid = 1; + return !ppsc->hwradiooff; +} + +void rtl8723be_set_key(struct ieee80211_hw *hw, u32 key_index, + u8 *p_macaddr, bool is_group, u8 enc_algo, + bool is_wepkey, bool clear_all) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 *macaddr = p_macaddr; + u32 entry_id = 0; + bool is_pairwise = false; + + static u8 cam_const_addr[4][6] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x03} + }; + static u8 cam_const_broad[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + if (clear_all) { + u8 idx = 0; + u8 cam_offset = 0; + u8 clear_number = 5; + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "clear_all\n"); + + for (idx = 0; idx < clear_number; idx++) { + rtl_cam_mark_invalid(hw, cam_offset + idx); + rtl_cam_empty_entry(hw, cam_offset + idx); + + if (idx < 5) { + memset(rtlpriv->sec.key_buf[idx], 0, + MAX_KEY_LEN); + rtlpriv->sec.key_len[idx] = 0; + } + } + } else { + switch (enc_algo) { + case WEP40_ENCRYPTION: + enc_algo = CAM_WEP40; + break; + case WEP104_ENCRYPTION: + enc_algo = CAM_WEP104; + break; + case TKIP_ENCRYPTION: + enc_algo = CAM_TKIP; + break; + case AESCCMP_ENCRYPTION: + enc_algo = CAM_AES; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not process\n"); + enc_algo = CAM_TKIP; + break; + } + + if (is_wepkey || rtlpriv->sec.use_defaultkey) { + macaddr = cam_const_addr[key_index]; + entry_id = key_index; + } else { + if (is_group) { + macaddr = cam_const_broad; + entry_id = key_index; + } else { + if (mac->opmode == NL80211_IFTYPE_AP) { + entry_id = rtl_cam_get_free_entry(hw, + p_macaddr); + if (entry_id >= TOTAL_CAM_ENTRY) { + RT_TRACE(rtlpriv, COMP_SEC, + DBG_EMERG, + "Can not find free" + " hw security cam " + "entry\n"); + return; + } + } else { + entry_id = CAM_PAIRWISE_KEY_POSITION; + } + key_index = PAIRWISE_KEYIDX; + is_pairwise = true; + } + } + if (rtlpriv->sec.key_len[key_index] == 0) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "delete one entry, entry_id is %d\n", + entry_id); + if (mac->opmode == NL80211_IFTYPE_AP) + rtl_cam_del_entry(hw, p_macaddr); + rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); + } else { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "add one entry\n"); + if (is_pairwise) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "set Pairwise key\n"); + + rtl_cam_add_one_entry(hw, macaddr, key_index, + entry_id, enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf[key_index]); + } else { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "set group key\n"); + + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + rtl_cam_add_one_entry(hw, + rtlefuse->dev_addr, + PAIRWISE_KEYIDX, + CAM_PAIRWISE_KEY_POSITION, + enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf + [entry_id]); + } + rtl_cam_add_one_entry(hw, macaddr, key_index, + entry_id, enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf[entry_id]); + } + } + } +} + +void rtl8723be_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, + bool auto_load_fail, u8 *hwinfo) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 value; + u32 tmpu_32; + + if (!auto_load_fail) { + tmpu_32 = rtl_read_dword(rtlpriv, REG_MULTI_FUNC_CTRL); + if (tmpu_32 & BIT(18)) + rtlpriv->btcoexist.btc_info.btcoexist = 1; + else + rtlpriv->btcoexist.btc_info.btcoexist = 0; + value = hwinfo[RF_OPTION4]; + rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8723B; + rtlpriv->btcoexist.btc_info.ant_num = (value & 0x1); + } else { + rtlpriv->btcoexist.btc_info.btcoexist = 0; + rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8723B; + rtlpriv->btcoexist.btc_info.ant_num = ANT_X2; + } +} + +void rtl8723be_bt_reg_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /* 0:Low, 1:High, 2:From Efuse. */ + rtlpriv->btcoexist.reg_bt_iso = 2; + /* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */ + rtlpriv->btcoexist.reg_bt_sco = 3; + /* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */ + rtlpriv->btcoexist.reg_bt_sco = 0; +} + +void rtl8723be_bt_hw_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_init_hw_config(rtlpriv); +} + +void rtl8723be_suspend(struct ieee80211_hw *hw) +{ +} + +void rtl8723be_resume(struct ieee80211_hw *hw) +{ +} + +/* Turn on AAP (RCR:bit 0) for promicuous mode. */ +void rtl8723be_allow_all_destaddr(struct ieee80211_hw *hw, bool allow_all_da, + bool write_into_reg) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + if (allow_all_da) /* Set BIT0 */ + rtlpci->receive_config |= RCR_AAP; + else /* Clear BIT0 */ + rtlpci->receive_config &= ~RCR_AAP; + + if (write_into_reg) + rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config); + + RT_TRACE(rtlpriv, COMP_TURBO | COMP_INIT, DBG_LOUD, + "receive_config = 0x%08X, write_into_reg =%d\n", + rtlpci->receive_config, write_into_reg); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/hw.h b/drivers/net/wireless/rtlwifi/rtl8723be/hw.h new file mode 100644 index 000000000000..b7449a9b57e4 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/hw.h @@ -0,0 +1,64 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8723BE_HW_H__ +#define __RTL8723BE_HW_H__ + +void rtl8723be_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl8723be_read_eeprom_info(struct ieee80211_hw *hw); + +void rtl8723be_interrupt_recognized(struct ieee80211_hw *hw, + u32 *p_inta, u32 *p_intb); +int rtl8723be_hw_init(struct ieee80211_hw *hw); +void rtl8723be_card_disable(struct ieee80211_hw *hw); +void rtl8723be_enable_interrupt(struct ieee80211_hw *hw); +void rtl8723be_disable_interrupt(struct ieee80211_hw *hw); +int rtl8723be_set_network_type(struct ieee80211_hw *hw, + enum nl80211_iftype type); +void rtl8723be_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); +void rtl8723be_set_qos(struct ieee80211_hw *hw, int aci); +void rtl8723be_set_beacon_related_registers(struct ieee80211_hw *hw); +void rtl8723be_set_beacon_interval(struct ieee80211_hw *hw); +void rtl8723be_update_interrupt_mask(struct ieee80211_hw *hw, + u32 add_msr, u32 rm_msr); +void rtl8723be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl8723be_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 rssi_level); +void rtl8723be_update_channel_access_setting(struct ieee80211_hw *hw); +bool rtl8723be_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid); +void rtl8723be_enable_hw_security_config(struct ieee80211_hw *hw); +void rtl8723be_set_key(struct ieee80211_hw *hw, u32 key_index, + u8 *p_macaddr, bool is_group, u8 enc_algo, + bool is_wepkey, bool clear_all); +void rtl8723be_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo); +void rtl8723be_bt_reg_init(struct ieee80211_hw *hw); +void rtl8723be_bt_hw_init(struct ieee80211_hw *hw); +void rtl8723be_suspend(struct ieee80211_hw *hw); +void rtl8723be_resume(struct ieee80211_hw *hw); +void rtl8723be_allow_all_destaddr(struct ieee80211_hw *hw, bool allow_all_da, + bool write_into_reg); +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/led.c b/drivers/net/wireless/rtlwifi/rtl8723be/led.c new file mode 100644 index 000000000000..cb931a38dc48 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/led.c @@ -0,0 +1,153 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "reg.h" +#include "led.h" + +static void _rtl8723be_init_led(struct ieee80211_hw *hw, struct rtl_led *pled, + enum rtl_led_pin ledpin) +{ + pled->hw = hw; + pled->ledpin = ledpin; + pled->ledon = false; +} + +void rtl8723be_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + u8 ledcfg; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, + "LedAddr:%X ledpin =%d\n", REG_LEDCFG2, pled->ledpin); + + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); + ledcfg &= ~BIT(6); + rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0xf0) | BIT(5)); + break; + case LED_PIN_LED1: + ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1); + rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg & 0x10); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not process\n"); + break; + } + pled->ledon = true; +} + +void rtl8723be_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + u8 ledcfg; + + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, + "LedAddr:%X ledpin =%d\n", REG_LEDCFG2, pled->ledpin); + + ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); + + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + ledcfg &= 0xf0; + if (pcipriv->ledctl.led_opendrain) { + ledcfg &= 0x90; /* Set to software control. */ + rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg|BIT(3))); + ledcfg = rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG); + ledcfg &= 0xFE; + rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, ledcfg); + } else { + ledcfg &= ~BIT(6); + rtl_write_byte(rtlpriv, REG_LEDCFG2, + (ledcfg | BIT(3) | BIT(5))); + } + break; + case LED_PIN_LED1: + ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1); + ledcfg &= 0x10; /* Set to software control. */ + rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg|BIT(3)); + + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not processed\n"); + break; + } + pled->ledon = false; +} + +void rtl8723be_init_sw_leds(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + _rtl8723be_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0); + _rtl8723be_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1); +} + +static void _rtl8723be_sw_led_control(struct ieee80211_hw *hw, + enum led_ctl_mode ledaction) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_led *pled0 = &(pcipriv->ledctl.sw_led0); + switch (ledaction) { + case LED_CTL_POWER_ON: + case LED_CTL_LINK: + case LED_CTL_NO_LINK: + rtl8723be_sw_led_on(hw, pled0); + break; + case LED_CTL_POWER_OFF: + rtl8723be_sw_led_off(hw, pled0); + break; + default: + break; + } +} + +void rtl8723be_led_control(struct ieee80211_hw *hw, + enum led_ctl_mode ledaction) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) && + (ledaction == LED_CTL_TX || + ledaction == LED_CTL_RX || + ledaction == LED_CTL_SITE_SURVEY || + ledaction == LED_CTL_LINK || + ledaction == LED_CTL_NO_LINK || + ledaction == LED_CTL_START_TO_LINK || + ledaction == LED_CTL_POWER_ON)) { + return; + } + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "ledaction %d,\n", ledaction); + _rtl8723be_sw_led_control(hw, ledaction); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/led.h b/drivers/net/wireless/rtlwifi/rtl8723be/led.h new file mode 100644 index 000000000000..c57de379ee8d --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/led.h @@ -0,0 +1,35 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8723BE_LED_H__ +#define __RTL8723BE_LED_H__ + +void rtl8723be_init_sw_leds(struct ieee80211_hw *hw); +void rtl8723be_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl8723be_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl8723be_led_control(struct ieee80211_hw *hw, + enum led_ctl_mode ledaction); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/phy.c b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c new file mode 100644 index 000000000000..ebc1e2788fca --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c @@ -0,0 +1,2175 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../ps.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "../rtl8723com/phy_common.h" +#include "rf.h" +#include "dm.h" +#include "table.h" +#include "trx.h" + +static bool _rtl8723be_phy_bb8723b_config_parafile(struct ieee80211_hw *hw); +static bool _rtl8723be_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, + u8 configtype); +static bool rtl8723be_phy_sw_chn_step_by_step(struct ieee80211_hw *hw, + u8 channel, u8 *stage, + u8 *step, u32 *delay); +static void _rtl8723be_config_bb_reg(struct ieee80211_hw *hw, + u32 addr, u32 data); + +static bool _rtl8723be_check_condition(struct ieee80211_hw *hw, + const u32 condition) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u32 _board = rtlefuse->board_type; /*need efuse define*/ + u32 _interface = rtlhal->interface; + u32 _platform = 0x08;/*SupportPlatform */ + u32 cond = condition; + + if (condition == 0xCDCDCDCD) + return true; + + cond = condition & 0xFF; + if ((_board & cond) == 0 && cond != 0x1F) + return false; + + cond = condition & 0xFF00; + cond = cond >> 8; + if ((_interface & cond) == 0 && cond != 0x07) + return false; + + cond = condition & 0xFF0000; + cond = cond >> 16; + if ((_platform & cond) == 0 && cond != 0x0F) + return false; + return true; +} + +static bool _rtl8723be_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + u32 arraylength; + u32 *ptrarray; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read rtl8723beMACPHY_Array\n"); + arraylength = RTL8723BEMAC_1T_ARRAYLEN; + ptrarray = RTL8723BEMAC_1T_ARRAY; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Img:RTL8723bEMAC_1T_ARRAY LEN %d\n", arraylength); + for (i = 0; i < arraylength; i = i + 2) + rtl_write_byte(rtlpriv, ptrarray[i], (u8) ptrarray[i + 1]); + return true; +} + +static bool _rtl8723be_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, + u8 configtype) +{ + #define READ_NEXT_PAIR(v1, v2, i) \ + do { \ + i += 2; \ + v1 = array_table[i];\ + v2 = array_table[i+1]; \ + } while (0) + + int i; + u32 *array_table; + u16 arraylen; + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 v1 = 0, v2 = 0; + + if (configtype == BASEBAND_CONFIG_PHY_REG) { + arraylen = RTL8723BEPHY_REG_1TARRAYLEN; + array_table = RTL8723BEPHY_REG_1TARRAY; + + for (i = 0; i < arraylen; i = i + 2) { + v1 = array_table[i]; + v2 = array_table[i+1]; + if (v1 < 0xcdcdcdcd) { + _rtl8723be_config_bb_reg(hw, v1, v2); + } else {/*This line is the start line of branch.*/ + if (!_rtl8723be_check_condition(hw, array_table[i])) { + /*Discard the following (offset, data) pairs*/ + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && + i < arraylen - 2) { + READ_NEXT_PAIR(v1, v2, i); + } + i -= 2; /* prevent from for-loop += 2*/ + /* Configure matched pairs and + * skip to end of if-else. + */ + } else { + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && + i < arraylen - 2) { + _rtl8723be_config_bb_reg(hw, + v1, v2); + READ_NEXT_PAIR(v1, v2, i); + } + + while (v2 != 0xDEAD && i < arraylen - 2) + READ_NEXT_PAIR(v1, v2, i); + } + } + } + } else if (configtype == BASEBAND_CONFIG_AGC_TAB) { + arraylen = RTL8723BEAGCTAB_1TARRAYLEN; + array_table = RTL8723BEAGCTAB_1TARRAY; + + for (i = 0; i < arraylen; i = i + 2) { + v1 = array_table[i]; + v2 = array_table[i+1]; + if (v1 < 0xCDCDCDCD) { + rtl_set_bbreg(hw, array_table[i], + MASKDWORD, + array_table[i + 1]); + udelay(1); + continue; + } else {/*This line is the start line of branch.*/ + if (!_rtl8723be_check_condition(hw, array_table[i])) { + /* Discard the following + * (offset, data) pairs + */ + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && + i < arraylen - 2) { + READ_NEXT_PAIR(v1, v2, i); + } + i -= 2; /* prevent from for-loop += 2*/ + /*Configure matched pairs and + *skip to end of if-else. + */ + } else { + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && + i < arraylen - 2) { + rtl_set_bbreg(hw, array_table[i], + MASKDWORD, + array_table[i + 1]); + udelay(1); + READ_NEXT_PAIR(v1, v2, i); + } + + while (v2 != 0xDEAD && i < arraylen - 2) + READ_NEXT_PAIR(v1, v2, i); + } + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "The agctab_array_table[0] is " + "%x Rtl818EEPHY_REGArray[1] is %x\n", + array_table[i], array_table[i + 1]); + } + } + return true; +} + +static u8 _rtl8723be_get_rate_section_index(u32 regaddr) +{ + u8 index = 0; + + switch (regaddr) { + case RTXAGC_A_RATE18_06: + case RTXAGC_B_RATE18_06: + index = 0; + break; + case RTXAGC_A_RATE54_24: + case RTXAGC_B_RATE54_24: + index = 1; + break; + case RTXAGC_A_CCK1_MCS32: + case RTXAGC_B_CCK1_55_MCS32: + index = 2; + break; + case RTXAGC_B_CCK11_A_CCK2_11: + index = 3; + break; + case RTXAGC_A_MCS03_MCS00: + case RTXAGC_B_MCS03_MCS00: + index = 4; + break; + case RTXAGC_A_MCS07_MCS04: + case RTXAGC_B_MCS07_MCS04: + index = 5; + break; + case RTXAGC_A_MCS11_MCS08: + case RTXAGC_B_MCS11_MCS08: + index = 6; + break; + case RTXAGC_A_MCS15_MCS12: + case RTXAGC_B_MCS15_MCS12: + index = 7; + break; + default: + regaddr &= 0xFFF; + if (regaddr >= 0xC20 && regaddr <= 0xC4C) + index = (u8) ((regaddr - 0xC20) / 4); + else if (regaddr >= 0xE20 && regaddr <= 0xE4C) + index = (u8) ((regaddr - 0xE20) / 4); + break; + }; + return index; +} + +u32 rtl8723be_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 original_value, readback_value, bitshift; + unsigned long flags; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n", + regaddr, rfpath, bitmask); + + spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + + original_value = rtl8723_phy_rf_serial_read(hw, rfpath, regaddr); + bitshift = rtl8723_phy_calculate_bit_shift(bitmask); + readback_value = (original_value & bitmask) >> bitshift; + + spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), rfpath(%#x), " + "bitmask(%#x), original_value(%#x)\n", + regaddr, rfpath, bitmask, original_value); + + return readback_value; +} + +void rtl8723be_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path path, + u32 regaddr, u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 original_value, bitshift; + unsigned long flags; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", + regaddr, bitmask, data, path); + + spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + + if (bitmask != RFREG_OFFSET_MASK) { + original_value = rtl8723_phy_rf_serial_read(hw, path, + regaddr); + bitshift = rtl8723_phy_calculate_bit_shift(bitmask); + data = ((original_value & (~bitmask)) | + (data << bitshift)); + } + + rtl8723_phy_rf_serial_write(hw, path, regaddr, data); + + spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", + regaddr, bitmask, data, path); +} + +bool rtl8723be_phy_mac_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool rtstatus = _rtl8723be_phy_config_mac_with_headerfile(hw); + + rtl_write_byte(rtlpriv, 0x04CA, 0x0B); + return rtstatus; +} + +bool rtl8723be_phy_bb_config(struct ieee80211_hw *hw) +{ + bool rtstatus = true; + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 regval; + u8 reg_hwparafile = 1; + u32 tmp; + u8 crystalcap = rtlpriv->efuse.crystalcap; + rtl8723_phy_init_bb_rf_reg_def(hw); + regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, + regval | BIT(13) | BIT(0) | BIT(1)); + + rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, + FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE | + FEN_BB_GLB_RSTN | FEN_BBRSTB); + tmp = rtl_read_dword(rtlpriv, 0x4c); + rtl_write_dword(rtlpriv, 0x4c, tmp | BIT(23)); + + rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80); + + if (reg_hwparafile == 1) + rtstatus = _rtl8723be_phy_bb8723b_config_parafile(hw); + + crystalcap = crystalcap & 0x3F; + rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0xFFF000, + (crystalcap | crystalcap << 6)); + + return rtstatus; +} + +bool rtl8723be_phy_rf_config(struct ieee80211_hw *hw) +{ + return rtl8723be_phy_rf6052_config(hw); +} + +static void _rtl8723be_config_rf_reg(struct ieee80211_hw *hw, u32 addr, + u32 data, enum radio_path rfpath, + u32 regaddr) +{ + if (addr == 0xfe || addr == 0xffe) { + mdelay(50); + } else { + rtl_set_rfreg(hw, rfpath, regaddr, RFREG_OFFSET_MASK, data); + udelay(1); + } +} + +static void _rtl8723be_config_rf_radio_a(struct ieee80211_hw *hw, + u32 addr, u32 data) +{ + u32 content = 0x1000; /*RF Content: radio_a_txt*/ + u32 maskforphyset = (u32)(content & 0xE000); + + _rtl8723be_config_rf_reg(hw, addr, data, RF90_PATH_A, + addr | maskforphyset); +} + +static void _rtl8723be_phy_init_tx_power_by_rate(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + u8 band, path, txnum, section; + + for (band = BAND_ON_2_4G; band <= BAND_ON_5G; ++band) + for (path = 0; path < TX_PWR_BY_RATE_NUM_RF; ++path) + for (txnum = 0; txnum < TX_PWR_BY_RATE_NUM_RF; ++txnum) + for (section = 0; + section < TX_PWR_BY_RATE_NUM_SECTION; + ++section) + rtlphy->tx_power_by_rate_offset[band] + [path][txnum][section] = 0; +} + +static void _rtl8723be_config_bb_reg(struct ieee80211_hw *hw, + u32 addr, u32 data) +{ + if (addr == 0xfe) { + mdelay(50); + } else if (addr == 0xfd) { + mdelay(5); + } else if (addr == 0xfc) { + mdelay(1); + } else if (addr == 0xfb) { + udelay(50); + } else if (addr == 0xfa) { + udelay(5); + } else if (addr == 0xf9) { + udelay(1); + } else { + rtl_set_bbreg(hw, addr, MASKDWORD, data); + udelay(1); + } +} + +static void phy_set_txpwr_by_rate_base(struct ieee80211_hw *hw, u8 band, + u8 path, u8 rate_section, + u8 txnum, u8 value) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + if (path > RF90_PATH_D) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Invalid Rf Path %d in phy_SetTxPowerByRatBase()\n", + path); + return; + } + + if (band == BAND_ON_2_4G) { + switch (rate_section) { + case CCK: + rtlphy->txpwr_by_rate_base_24g[path][txnum][0] = value; + break; + case OFDM: + rtlphy->txpwr_by_rate_base_24g[path][txnum][1] = value; + break; + case HT_MCS0_MCS7: + rtlphy->txpwr_by_rate_base_24g[path][txnum][2] = value; + break; + case HT_MCS8_MCS15: + rtlphy->txpwr_by_rate_base_24g[path][txnum][3] = value; + break; + default: + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Invalid RateSection %d in Band 2.4G, Rf Path" + " %d, %dTx in PHY_SetTxPowerByRateBase()\n", + rate_section, path, txnum); + break; + }; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Invalid Band %d in PHY_SetTxPowerByRateBase()\n", + band); + } +} + +static u8 phy_get_txpwr_by_rate_base(struct ieee80211_hw *hw, u8 band, u8 path, + u8 txnum, u8 rate_section) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 value = 0; + if (path > RF90_PATH_D) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Invalid Rf Path %d in PHY_GetTxPowerByRateBase()\n", + path); + return 0; + } + + if (band == BAND_ON_2_4G) { + switch (rate_section) { + case CCK: + value = rtlphy->txpwr_by_rate_base_24g[path][txnum][0]; + break; + case OFDM: + value = rtlphy->txpwr_by_rate_base_24g[path][txnum][1]; + break; + case HT_MCS0_MCS7: + value = rtlphy->txpwr_by_rate_base_24g[path][txnum][2]; + break; + case HT_MCS8_MCS15: + value = rtlphy->txpwr_by_rate_base_24g[path][txnum][3]; + break; + default: + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Invalid RateSection %d in Band 2.4G, Rf Path" + " %d, %dTx in PHY_GetTxPowerByRateBase()\n", + rate_section, path, txnum); + break; + }; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Invalid Band %d in PHY_GetTxPowerByRateBase()\n", + band); + } + + return value; +} + +static void _rtl8723be_phy_store_txpower_by_rate_base(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u16 raw_value = 0; + u8 base = 0, path = 0; + + for (path = RF90_PATH_A; path <= RF90_PATH_B; ++path) { + if (path == RF90_PATH_A) { + raw_value = (u16) (rtlphy->tx_power_by_rate_offset + [BAND_ON_2_4G][path][RF_1TX][3] >> 24) & 0xFF; + base = (raw_value >> 4) * 10 + (raw_value & 0xF); + phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path, CCK, + RF_1TX, base); + } else if (path == RF90_PATH_B) { + raw_value = (u16) (rtlphy->tx_power_by_rate_offset + [BAND_ON_2_4G][path][RF_1TX][3] >> 0) & 0xFF; + base = (raw_value >> 4) * 10 + (raw_value & 0xF); + phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path, + CCK, RF_1TX, base); + } + raw_value = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G] + [path][RF_1TX][1] >> 24) & 0xFF; + base = (raw_value >> 4) * 10 + (raw_value & 0xF); + phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path, OFDM, RF_1TX, + base); + + raw_value = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G] + [path][RF_1TX][5] >> 24) & 0xFF; + base = (raw_value >> 4) * 10 + (raw_value & 0xF); + phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path, HT_MCS0_MCS7, + RF_1TX, base); + + raw_value = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G] + [path][RF_2TX][7] >> 24) & 0xFF; + base = (raw_value >> 4) * 10 + (raw_value & 0xF); + phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path, + HT_MCS8_MCS15, RF_2TX, base); + } +} + +static void phy_conv_dbm_to_rel(u32 *data, u8 start, u8 end, u8 base_val) +{ + char i = 0; + u8 temp_value = 0; + u32 temp_data = 0; + + for (i = 3; i >= 0; --i) { + if (i >= start && i <= end) { + /* Get the exact value */ + temp_value = (u8) (*data >> (i * 8)) & 0xF; + temp_value += ((u8) ((*data >> (i*8 + 4)) & 0xF)) * 10; + + /* Change the value to a relative value */ + temp_value = (temp_value > base_val) ? + temp_value - base_val : + base_val - temp_value; + } else { + temp_value = (u8) (*data >> (i * 8)) & 0xFF; + } + temp_data <<= 8; + temp_data |= temp_value; + } + *data = temp_data; +} + +static void conv_dbm_to_rel(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 base = 0, rfpath = RF90_PATH_A; + + base = phy_get_txpwr_by_rate_base(hw, BAND_ON_2_4G, rfpath, + RF_1TX, CCK); + phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G] + [rfpath][RF_1TX][2]), 1, 1, base); + phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G] + [rfpath][RF_1TX][3]), 1, 3, base); + + base = phy_get_txpwr_by_rate_base(hw, BAND_ON_2_4G, rfpath, + RF_1TX, OFDM); + phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G] + [rfpath][RF_1TX][0]), 0, 3, base); + phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G] + [rfpath][RF_1TX][1]), 0, 3, base); + + base = phy_get_txpwr_by_rate_base(hw, BAND_ON_2_4G, rfpath, + RF_1TX, HT_MCS0_MCS7); + phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G] + [rfpath][RF_1TX][4]), 0, 3, base); + phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G] + [rfpath][RF_1TX][5]), 0, 3, base); + + base = phy_get_txpwr_by_rate_base(hw, BAND_ON_2_4G, rfpath, + RF_2TX, HT_MCS8_MCS15); + phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G] + [rfpath][RF_2TX][6]), 0, 3, base); + + phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G] + [rfpath][RF_2TX][7]), 0, 3, base); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + "<=== conv_dbm_to_rel()\n"); +} + +static void _rtl8723be_phy_txpower_by_rate_configuration( + struct ieee80211_hw *hw) +{ + _rtl8723be_phy_store_txpower_by_rate_base(hw); + conv_dbm_to_rel(hw); +} + +static bool _rtl8723be_phy_bb8723b_config_parafile(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + bool rtstatus; + + rtstatus = _rtl8723be_phy_config_bb_with_headerfile(hw, + BASEBAND_CONFIG_PHY_REG); + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!"); + return false; + } + _rtl8723be_phy_init_tx_power_by_rate(hw); + if (!rtlefuse->autoload_failflag) { + rtlphy->pwrgroup_cnt = 0; + rtstatus = _rtl8723be_phy_config_bb_with_pgheaderfile(hw, + BASEBAND_CONFIG_PHY_REG); + } + _rtl8723be_phy_txpower_by_rate_configuration(hw); + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!"); + return false; + } + rtstatus = _rtl8723be_phy_config_bb_with_headerfile(hw, + BASEBAND_CONFIG_AGC_TAB); + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AGC Table Fail\n"); + return false; + } + rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER2, + 0x200)); + return true; +} + +static void _rtl8723be_store_tx_power_by_rate(struct ieee80211_hw *hw, + u32 band, u32 rfpath, + u32 txnum, u32 regaddr, + u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 rate_section = _rtl8723be_get_rate_section_index(regaddr); + + if (band != BAND_ON_2_4G && band != BAND_ON_5G) + RT_TRACE(rtlpriv, COMP_POWER, PHY_TXPWR, + "Invalid Band %d\n", band); + + if (rfpath > MAX_RF_PATH) + RT_TRACE(rtlpriv, COMP_POWER, PHY_TXPWR, + "Invalid RfPath %d\n", rfpath); + + if (txnum > MAX_RF_PATH) + RT_TRACE(rtlpriv, COMP_POWER, PHY_TXPWR, + "Invalid TxNum %d\n", txnum); + + rtlphy->tx_power_by_rate_offset[band][rfpath][txnum][rate_section] = + data; +} + +static bool _rtl8723be_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, + u8 configtype) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int i; + u32 *phy_regarray_table_pg; + u16 phy_regarray_pg_len; + u32 v1 = 0, v2 = 0, v3 = 0, v4 = 0, v5 = 0, v6 = 0; + + phy_regarray_pg_len = RTL8723BEPHY_REG_ARRAY_PGLEN; + phy_regarray_table_pg = RTL8723BEPHY_REG_ARRAY_PG; + + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_regarray_pg_len; i = i + 6) { + v1 = phy_regarray_table_pg[i]; + v2 = phy_regarray_table_pg[i+1]; + v3 = phy_regarray_table_pg[i+2]; + v4 = phy_regarray_table_pg[i+3]; + v5 = phy_regarray_table_pg[i+4]; + v6 = phy_regarray_table_pg[i+5]; + + if (v1 < 0xcdcdcdcd) { + if (phy_regarray_table_pg[i] == 0xfe || + phy_regarray_table_pg[i] == 0xffe) + mdelay(50); + else + _rtl8723be_store_tx_power_by_rate(hw, + v1, v2, v3, v4, v5, v6); + continue; + } else { + /*don't need the hw_body*/ + if (!_rtl8723be_check_condition(hw, + phy_regarray_table_pg[i])) { + i += 2; /* skip the pair of expression*/ + v1 = phy_regarray_table_pg[i]; + v2 = phy_regarray_table_pg[i+1]; + v3 = phy_regarray_table_pg[i+2]; + while (v2 != 0xDEAD) { + i += 3; + v1 = phy_regarray_table_pg[i]; + v2 = phy_regarray_table_pg[i+1]; + v3 = phy_regarray_table_pg[i+2]; + } + } + } + } + } else { + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, + "configtype != BaseBand_Config_PHY_REG\n"); + } + return true; +} + +bool rtl8723be_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, + enum radio_path rfpath) +{ + #define READ_NEXT_RF_PAIR(v1, v2, i) \ + do { \ + i += 2; \ + v1 = radioa_array_table[i]; \ + v2 = radioa_array_table[i+1]; \ + } while (0) + + int i; + bool rtstatus = true; + u32 *radioa_array_table; + u16 radioa_arraylen; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 v1 = 0, v2 = 0; + + radioa_arraylen = RTL8723BE_RADIOA_1TARRAYLEN; + radioa_array_table = RTL8723BE_RADIOA_1TARRAY; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Radio_A:RTL8723BE_RADIOA_1TARRAY %d\n", radioa_arraylen); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio No %x\n", rfpath); + rtstatus = true; + switch (rfpath) { + case RF90_PATH_A: + for (i = 0; i < radioa_arraylen; i = i + 2) { + v1 = radioa_array_table[i]; + v2 = radioa_array_table[i+1]; + if (v1 < 0xcdcdcdcd) { + _rtl8723be_config_rf_radio_a(hw, v1, v2); + } else { /*This line is the start line of branch.*/ + if (!_rtl8723be_check_condition(hw, + radioa_array_table[i])) { + /* Discard the following + * (offset, data) pairs + */ + READ_NEXT_RF_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && + i < radioa_arraylen - 2) + READ_NEXT_RF_PAIR(v1, v2, i); + i -= 2; /* prevent from for-loop += 2*/ + } else { + /* Configure matched pairs + * and skip to end of if-else. + */ + READ_NEXT_RF_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && + i < radioa_arraylen - 2) { + _rtl8723be_config_rf_radio_a(hw, + v1, v2); + READ_NEXT_RF_PAIR(v1, v2, i); + } + + while (v2 != 0xDEAD && + i < radioa_arraylen - 2) { + READ_NEXT_RF_PAIR(v1, v2, i); + } + } + } + } + + if (rtlhal->oem_id == RT_CID_819X_HP) + _rtl8723be_config_rf_radio_a(hw, 0x52, 0x7E4BD); + + break; + case RF90_PATH_B: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not process\n"); + break; + case RF90_PATH_C: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not process\n"); + break; + case RF90_PATH_D: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not process\n"); + break; + } + return true; +} + +void rtl8723be_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + rtlphy->default_initialgain[0] = + (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0); + rtlphy->default_initialgain[1] = + (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0); + rtlphy->default_initialgain[2] = + (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0); + rtlphy->default_initialgain[3] = + (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Default initial gain (c50 = 0x%x, " + "c58 = 0x%x, c60 = 0x%x, c68 = 0x%x\n", + rtlphy->default_initialgain[0], + rtlphy->default_initialgain[1], + rtlphy->default_initialgain[2], + rtlphy->default_initialgain[3]); + + rtlphy->framesync = (u8) rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3, + MASKBYTE0); + rtlphy->framesync_c34 = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR2, + MASKDWORD); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Default framesync (0x%x) = 0x%x\n", + ROFDM0_RXDETECTOR3, rtlphy->framesync); +} + +void rtl8723be_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 txpwr_level; + long txpwr_dbm; + + txpwr_level = rtlphy->cur_cck_txpwridx; + txpwr_dbm = rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_B, + txpwr_level); + txpwr_level = rtlphy->cur_ofdm24g_txpwridx; + if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, txpwr_level) > + txpwr_dbm) + txpwr_dbm = + rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, + txpwr_level); + txpwr_level = rtlphy->cur_ofdm24g_txpwridx; + if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, + txpwr_level) > txpwr_dbm) + txpwr_dbm = + rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, + txpwr_level); + *powerlevel = txpwr_dbm; +} + +static u8 _rtl8723be_phy_get_ratesection_intxpower_byrate(enum radio_path path, + u8 rate) +{ + u8 rate_section = 0; + + switch (rate) { + case DESC92C_RATE1M: + rate_section = 2; + break; + case DESC92C_RATE2M: + case DESC92C_RATE5_5M: + if (path == RF90_PATH_A) + rate_section = 3; + else if (path == RF90_PATH_B) + rate_section = 2; + break; + case DESC92C_RATE11M: + rate_section = 3; + break; + case DESC92C_RATE6M: + case DESC92C_RATE9M: + case DESC92C_RATE12M: + case DESC92C_RATE18M: + rate_section = 0; + break; + case DESC92C_RATE24M: + case DESC92C_RATE36M: + case DESC92C_RATE48M: + case DESC92C_RATE54M: + rate_section = 1; + break; + case DESC92C_RATEMCS0: + case DESC92C_RATEMCS1: + case DESC92C_RATEMCS2: + case DESC92C_RATEMCS3: + rate_section = 4; + break; + case DESC92C_RATEMCS4: + case DESC92C_RATEMCS5: + case DESC92C_RATEMCS6: + case DESC92C_RATEMCS7: + rate_section = 5; + break; + case DESC92C_RATEMCS8: + case DESC92C_RATEMCS9: + case DESC92C_RATEMCS10: + case DESC92C_RATEMCS11: + rate_section = 6; + break; + case DESC92C_RATEMCS12: + case DESC92C_RATEMCS13: + case DESC92C_RATEMCS14: + case DESC92C_RATEMCS15: + rate_section = 7; + break; + default: + RT_ASSERT(true, "Rate_Section is Illegal\n"); + break; + } + return rate_section; +} + +static u8 _rtl8723be_get_txpower_by_rate(struct ieee80211_hw *hw, + enum band_type band, + enum radio_path rfpath, u8 rate) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 shift = 0, rate_section, tx_num; + char tx_pwr_diff = 0; + + rate_section = _rtl8723be_phy_get_ratesection_intxpower_byrate(rfpath, + rate); + tx_num = RF_TX_NUM_NONIMPLEMENT; + + if (tx_num == RF_TX_NUM_NONIMPLEMENT) { + if (rate >= DESC92C_RATEMCS8 && rate <= DESC92C_RATEMCS15) + tx_num = RF_2TX; + else + tx_num = RF_1TX; + } + + switch (rate) { + case DESC92C_RATE6M: + case DESC92C_RATE24M: + case DESC92C_RATEMCS0: + case DESC92C_RATEMCS4: + case DESC92C_RATEMCS8: + case DESC92C_RATEMCS12: + shift = 0; + break; + case DESC92C_RATE1M: + case DESC92C_RATE2M: + case DESC92C_RATE9M: + case DESC92C_RATE36M: + case DESC92C_RATEMCS1: + case DESC92C_RATEMCS5: + case DESC92C_RATEMCS9: + case DESC92C_RATEMCS13: + shift = 8; + break; + case DESC92C_RATE5_5M: + case DESC92C_RATE12M: + case DESC92C_RATE48M: + case DESC92C_RATEMCS2: + case DESC92C_RATEMCS6: + case DESC92C_RATEMCS10: + case DESC92C_RATEMCS14: + shift = 16; + break; + case DESC92C_RATE11M: + case DESC92C_RATE18M: + case DESC92C_RATE54M: + case DESC92C_RATEMCS3: + case DESC92C_RATEMCS7: + case DESC92C_RATEMCS11: + case DESC92C_RATEMCS15: + shift = 24; + break; + default: + RT_ASSERT(true, "Rate_Section is Illegal\n"); + break; + } + tx_pwr_diff = (u8)(rtlphy->tx_power_by_rate_offset[band][rfpath][tx_num] + [rate_section] >> shift) & 0xff; + + return tx_pwr_diff; +} + +static u8 _rtl8723be_get_txpower_index(struct ieee80211_hw *hw, u8 path, + u8 rate, u8 bandwidth, u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 index = (channel - 1); + u8 txpower; + u8 power_diff_byrate = 0; + + if (channel > 14 || channel < 1) { + index = 0; + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "Illegal channel!\n"); + } + if (RTL8723E_RX_HAL_IS_CCK_RATE(rate)) + txpower = rtlefuse->txpwrlevel_cck[path][index]; + else if (DESC92C_RATE6M <= rate) + txpower = rtlefuse->txpwrlevel_ht40_1s[path][index]; + else + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + "invalid rate\n"); + + if (DESC92C_RATE6M <= rate && rate <= DESC92C_RATE54M && + !RTL8723E_RX_HAL_IS_CCK_RATE(rate)) + txpower += rtlefuse->txpwr_legacyhtdiff[0][TX_1S]; + + if (bandwidth == HT_CHANNEL_WIDTH_20) { + if (DESC92C_RATEMCS0 <= rate && rate <= DESC92C_RATEMCS15) + txpower += rtlefuse->txpwr_ht20diff[0][TX_1S]; + if (DESC92C_RATEMCS8 <= rate && rate <= DESC92C_RATEMCS15) + txpower += rtlefuse->txpwr_ht20diff[0][TX_2S]; + } else if (bandwidth == HT_CHANNEL_WIDTH_20_40) { + if (DESC92C_RATEMCS0 <= rate && rate <= DESC92C_RATEMCS15) + txpower += rtlefuse->txpwr_ht40diff[0][TX_1S]; + if (DESC92C_RATEMCS8 <= rate && rate <= DESC92C_RATEMCS15) + txpower += rtlefuse->txpwr_ht40diff[0][TX_2S]; + } + if (rtlefuse->eeprom_regulatory != 2) + power_diff_byrate = _rtl8723be_get_txpower_by_rate(hw, + BAND_ON_2_4G, + path, rate); + + txpower += power_diff_byrate; + + if (txpower > MAX_POWER_INDEX) + txpower = MAX_POWER_INDEX; + + return txpower; +} + +static void _rtl8723be_phy_set_txpower_index(struct ieee80211_hw *hw, + u8 power_index, u8 path, u8 rate) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + if (path == RF90_PATH_A) { + switch (rate) { + case DESC92C_RATE1M: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_CCK1_MCS32, + MASKBYTE1, power_index); + break; + case DESC92C_RATE2M: + rtl8723_phy_set_bb_reg(hw, RTXAGC_B_CCK11_A_CCK2_11, + MASKBYTE1, power_index); + break; + case DESC92C_RATE5_5M: + rtl8723_phy_set_bb_reg(hw, RTXAGC_B_CCK11_A_CCK2_11, + MASKBYTE2, power_index); + break; + case DESC92C_RATE11M: + rtl8723_phy_set_bb_reg(hw, RTXAGC_B_CCK11_A_CCK2_11, + MASKBYTE3, power_index); + break; + case DESC92C_RATE6M: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE18_06, + MASKBYTE0, power_index); + break; + case DESC92C_RATE9M: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE18_06, + MASKBYTE1, power_index); + break; + case DESC92C_RATE12M: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE18_06, + MASKBYTE2, power_index); + break; + case DESC92C_RATE18M: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE18_06, + MASKBYTE3, power_index); + break; + case DESC92C_RATE24M: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE54_24, + MASKBYTE0, power_index); + break; + case DESC92C_RATE36M: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE54_24, + MASKBYTE1, power_index); + break; + case DESC92C_RATE48M: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE54_24, + MASKBYTE2, power_index); + break; + case DESC92C_RATE54M: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE54_24, + MASKBYTE3, power_index); + break; + case DESC92C_RATEMCS0: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS03_MCS00, + MASKBYTE0, power_index); + break; + case DESC92C_RATEMCS1: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS03_MCS00, + MASKBYTE1, power_index); + break; + case DESC92C_RATEMCS2: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS03_MCS00, + MASKBYTE2, power_index); + break; + case DESC92C_RATEMCS3: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS03_MCS00, + MASKBYTE3, power_index); + break; + case DESC92C_RATEMCS4: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS07_MCS04, + MASKBYTE0, power_index); + break; + case DESC92C_RATEMCS5: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS07_MCS04, + MASKBYTE1, power_index); + break; + case DESC92C_RATEMCS6: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS07_MCS04, + MASKBYTE2, power_index); + break; + case DESC92C_RATEMCS7: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS07_MCS04, + MASKBYTE3, power_index); + break; + case DESC92C_RATEMCS8: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS11_MCS08, + MASKBYTE0, power_index); + break; + case DESC92C_RATEMCS9: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS11_MCS08, + MASKBYTE1, power_index); + break; + case DESC92C_RATEMCS10: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS11_MCS08, + MASKBYTE2, power_index); + break; + case DESC92C_RATEMCS11: + rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS11_MCS08, + MASKBYTE3, power_index); + break; + default: + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Invalid Rate!!\n"); + break; + } + } else { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "Invalid RFPath!!\n"); + } +} + +void rtl8723be_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 cck_rates[] = {DESC92C_RATE1M, DESC92C_RATE2M, + DESC92C_RATE5_5M, DESC92C_RATE11M}; + u8 ofdm_rates[] = {DESC92C_RATE6M, DESC92C_RATE9M, + DESC92C_RATE12M, DESC92C_RATE18M, + DESC92C_RATE24M, DESC92C_RATE36M, + DESC92C_RATE48M, DESC92C_RATE54M}; + u8 ht_rates_1t[] = {DESC92C_RATEMCS0, DESC92C_RATEMCS1, + DESC92C_RATEMCS2, DESC92C_RATEMCS3, + DESC92C_RATEMCS4, DESC92C_RATEMCS5, + DESC92C_RATEMCS6, DESC92C_RATEMCS7}; + u8 i, size; + u8 power_index; + + if (!rtlefuse->txpwr_fromeprom) + return; + + size = sizeof(cck_rates) / sizeof(u8); + for (i = 0; i < size; i++) { + power_index = _rtl8723be_get_txpower_index(hw, RF90_PATH_A, + cck_rates[i], + rtl_priv(hw)->phy.current_chan_bw, + channel); + _rtl8723be_phy_set_txpower_index(hw, power_index, RF90_PATH_A, + cck_rates[i]); + } + size = sizeof(ofdm_rates) / sizeof(u8); + for (i = 0; i < size; i++) { + power_index = _rtl8723be_get_txpower_index(hw, RF90_PATH_A, + ofdm_rates[i], + rtl_priv(hw)->phy.current_chan_bw, + channel); + _rtl8723be_phy_set_txpower_index(hw, power_index, RF90_PATH_A, + ofdm_rates[i]); + } + size = sizeof(ht_rates_1t) / sizeof(u8); + for (i = 0; i < size; i++) { + power_index = _rtl8723be_get_txpower_index(hw, RF90_PATH_A, + ht_rates_1t[i], + rtl_priv(hw)->phy.current_chan_bw, + channel); + _rtl8723be_phy_set_txpower_index(hw, power_index, RF90_PATH_A, + ht_rates_1t[i]); + } +} + +void rtl8723be_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + enum io_type iotype; + + if (!is_hal_stop(rtlhal)) { + switch (operation) { + case SCAN_OPT_BACKUP: + iotype = IO_CMD_PAUSE_DM_BY_SCAN; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_IO_CMD, + (u8 *)&iotype); + break; + case SCAN_OPT_RESTORE: + iotype = IO_CMD_RESUME_DM_BY_SCAN; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_IO_CMD, + (u8 *)&iotype); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Unknown Scan Backup operation.\n"); + break; + } + } +} + +void rtl8723be_phy_set_bw_mode_callback(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u8 reg_bw_opmode; + u8 reg_prsr_rsc; + + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, + "Switch to %s bandwidth\n", + rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ? + "20MHz" : "40MHz"); + + if (is_hal_stop(rtlhal)) { + rtlphy->set_bwmode_inprogress = false; + return; + } + + reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE); + reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2); + + switch (rtlphy->current_chan_bw) { + case HT_CHANNEL_WIDTH_20: + reg_bw_opmode |= BW_OPMODE_20MHZ; + rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); + break; + case HT_CHANNEL_WIDTH_20_40: + reg_bw_opmode &= ~BW_OPMODE_20MHZ; + rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); + reg_prsr_rsc = (reg_prsr_rsc & 0x90) | + (mac->cur_40_prime_sc << 5); + rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "unknown bandwidth: %#X\n", rtlphy->current_chan_bw); + break; + } + + switch (rtlphy->current_chan_bw) { + case HT_CHANNEL_WIDTH_20: + rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0); + rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0); + break; + case HT_CHANNEL_WIDTH_20_40: + rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1); + rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1); + rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND, + (mac->cur_40_prime_sc >> 1)); + rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc); + rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)), + (mac->cur_40_prime_sc == + HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "unknown bandwidth: %#X\n", rtlphy->current_chan_bw); + break; + } + rtl8723be_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); + rtlphy->set_bwmode_inprogress = false; + RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, "\n"); +} + +void rtl8723be_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 tmp_bw = rtlphy->current_chan_bw; + + if (rtlphy->set_bwmode_inprogress) + return; + rtlphy->set_bwmode_inprogress = true; + if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { + rtl8723be_phy_set_bw_mode_callback(hw); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "false driver sleep or unload\n"); + rtlphy->set_bwmode_inprogress = false; + rtlphy->current_chan_bw = tmp_bw; + } +} + +void rtl8723be_phy_sw_chnl_callback(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 delay; + + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, + "switch to channel%d\n", rtlphy->current_channel); + if (is_hal_stop(rtlhal)) + return; + do { + if (!rtlphy->sw_chnl_inprogress) + break; + if (!rtl8723be_phy_sw_chn_step_by_step(hw, + rtlphy->current_channel, + &rtlphy->sw_chnl_stage, + &rtlphy->sw_chnl_step, + &delay)) { + if (delay > 0) + mdelay(delay); + else + continue; + } else { + rtlphy->sw_chnl_inprogress = false; + } + break; + } while (true); + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "\n"); +} + +u8 rtl8723be_phy_sw_chnl(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if (rtlphy->sw_chnl_inprogress) + return 0; + if (rtlphy->set_bwmode_inprogress) + return 0; + RT_ASSERT((rtlphy->current_channel <= 14), + "WIRELESS_MODE_G but channel>14"); + rtlphy->sw_chnl_inprogress = true; + rtlphy->sw_chnl_stage = 0; + rtlphy->sw_chnl_step = 0; + if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { + rtl8723be_phy_sw_chnl_callback(hw); + RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, + "sw_chnl_inprogress false schdule " + "workitem current channel %d\n", + rtlphy->current_channel); + rtlphy->sw_chnl_inprogress = false; + } else { + RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, + "sw_chnl_inprogress false driver sleep or" + " unload\n"); + rtlphy->sw_chnl_inprogress = false; + } + return 1; +} + +static bool rtl8723be_phy_sw_chn_step_by_step(struct ieee80211_hw *hw, + u8 channel, u8 *stage, + u8 *step, u32 *delay) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct swchnlcmd precommoncmd[MAX_PRECMD_CNT]; + u32 precommoncmdcnt; + struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT]; + u32 postcommoncmdcnt; + struct swchnlcmd rfdependcmd[MAX_RFDEPENDCMD_CNT]; + u32 rfdependcmdcnt; + struct swchnlcmd *currentcmd = NULL; + u8 rfpath; + u8 num_total_rfpath = rtlphy->num_total_rfpath; + + precommoncmdcnt = 0; + rtl8723_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, + MAX_PRECMD_CNT, + CMDID_SET_TXPOWEROWER_LEVEL, + 0, 0, 0); + rtl8723_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, + MAX_PRECMD_CNT, CMDID_END, 0, 0, 0); + postcommoncmdcnt = 0; + rtl8723_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++, + MAX_POSTCMD_CNT, CMDID_END, + 0, 0, 0); + rfdependcmdcnt = 0; + + RT_ASSERT((channel >= 1 && channel <= 14), + "illegal channel for Zebra: %d\n", channel); + + rtl8723_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, + MAX_RFDEPENDCMD_CNT, + CMDID_RF_WRITEREG, + RF_CHNLBW, channel, 10); + + rtl8723_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, + MAX_RFDEPENDCMD_CNT, + CMDID_END, 0, 0, 0); + + do { + switch (*stage) { + case 0: + currentcmd = &precommoncmd[*step]; + break; + case 1: + currentcmd = &rfdependcmd[*step]; + break; + case 2: + currentcmd = &postcommoncmd[*step]; + break; + } + + if (currentcmd->cmdid == CMDID_END) { + if ((*stage) == 2) { + return true; + } else { + (*stage)++; + (*step) = 0; + continue; + } + } + + switch (currentcmd->cmdid) { + case CMDID_SET_TXPOWEROWER_LEVEL: + rtl8723be_phy_set_txpower_level(hw, channel); + break; + case CMDID_WRITEPORT_ULONG: + rtl_write_dword(rtlpriv, currentcmd->para1, + currentcmd->para2); + break; + case CMDID_WRITEPORT_USHORT: + rtl_write_word(rtlpriv, currentcmd->para1, + (u16) currentcmd->para2); + break; + case CMDID_WRITEPORT_UCHAR: + rtl_write_byte(rtlpriv, currentcmd->para1, + (u8) currentcmd->para2); + break; + case CMDID_RF_WRITEREG: + for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) { + rtlphy->rfreg_chnlval[rfpath] = + ((rtlphy->rfreg_chnlval[rfpath] & + 0xfffffc00) | currentcmd->para2); + + rtl_set_rfreg(hw, (enum radio_path)rfpath, + currentcmd->para1, + RFREG_OFFSET_MASK, + rtlphy->rfreg_chnlval[rfpath]); + } + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not process\n"); + break; + } + + break; + } while (true); + + (*delay) = currentcmd->msdelay; + (*step)++; + return false; +} + +static u8 _rtl8723be_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb) +{ + u32 reg_eac, reg_e94, reg_e9c, reg_ea4; + u8 result = 0x00; + + rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c1c); + rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x30008c1c); + rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x8214032a); + rtl_set_bbreg(hw, 0xe3c, MASKDWORD, 0x28160000); + + rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x00462911); + rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf9000000); + rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000); + + mdelay(IQK_DELAY_TIME); + + reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD); + reg_e94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD); + reg_e9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD); + reg_ea4 = rtl_get_bbreg(hw, 0xea4, MASKDWORD); + + if (!(reg_eac & BIT(28)) && + (((reg_e94 & 0x03FF0000) >> 16) != 0x142) && + (((reg_e9c & 0x03FF0000) >> 16) != 0x42)) + result |= 0x01; + return result; +} + +static bool phy_similarity_cmp(struct ieee80211_hw *hw, long result[][8], + u8 c1, u8 c2) +{ + u32 i, j, diff, simularity_bitmap, bound; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + u8 final_candidate[2] = { 0xFF, 0xFF }; + bool bresult = true, is2t = IS_92C_SERIAL(rtlhal->version); + + if (is2t) + bound = 8; + else + bound = 4; + + simularity_bitmap = 0; + + for (i = 0; i < bound; i++) { + diff = (result[c1][i] > result[c2][i]) ? + (result[c1][i] - result[c2][i]) : + (result[c2][i] - result[c1][i]); + + if (diff > MAX_TOLERANCE) { + if ((i == 2 || i == 6) && !simularity_bitmap) { + if (result[c1][i] + result[c1][i + 1] == 0) + final_candidate[(i / 4)] = c2; + else if (result[c2][i] + result[c2][i + 1] == 0) + final_candidate[(i / 4)] = c1; + else + simularity_bitmap |= (1 << i); + } else { + simularity_bitmap |= (1 << i); + } + } + } + + if (simularity_bitmap == 0) { + for (i = 0; i < (bound / 4); i++) { + if (final_candidate[i] != 0xFF) { + for (j = i * 4; j < (i + 1) * 4 - 2; j++) + result[3][j] = + result[final_candidate[i]][j]; + bresult = false; + } + } + return bresult; + } else if (!(simularity_bitmap & 0x0F)) { + for (i = 0; i < 4; i++) + result[3][i] = result[c1][i]; + return false; + } else if (!(simularity_bitmap & 0xF0) && is2t) { + for (i = 4; i < 8; i++) + result[3][i] = result[c1][i]; + return false; + } else { + return false; + } +} + +static void _rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw, + long result[][8], u8 t, bool is2t) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 i; + u8 patha_ok; + u32 adda_reg[IQK_ADDA_REG_NUM] = { + 0x85c, 0xe6c, 0xe70, 0xe74, + 0xe78, 0xe7c, 0xe80, 0xe84, + 0xe88, 0xe8c, 0xed0, 0xed4, + 0xed8, 0xedc, 0xee0, 0xeec + }; + + u32 iqk_mac_reg[IQK_MAC_REG_NUM] = { + 0x522, 0x550, 0x551, 0x040 + }; + u32 iqk_bb_reg[IQK_BB_REG_NUM] = { + ROFDM0_TRXPATHENABLE, ROFDM0_TRMUXPAR, + RFPGA0_XCD_RFINTERFACESW, 0xb68, 0xb6c, + 0x870, 0x860, + 0x864, 0x800 + }; + const u32 retrycount = 2; + u32 path_sel_bb, path_sel_rf; + u8 tmp_reg_c50, tmp_reg_c58; + + tmp_reg_c50 = rtl_get_bbreg(hw, 0xc50, MASKBYTE0); + tmp_reg_c58 = rtl_get_bbreg(hw, 0xc58, MASKBYTE0); + + if (t == 0) { + rtl8723_save_adda_registers(hw, adda_reg, + rtlphy->adda_backup, 16); + rtl8723_phy_save_mac_registers(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); + rtl8723_save_adda_registers(hw, iqk_bb_reg, + rtlphy->iqk_bb_backup, + IQK_BB_REG_NUM); + } + rtl8723_phy_path_adda_on(hw, adda_reg, true, is2t); + if (t == 0) { + rtlphy->rfpi_enable = (u8) rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER1, + BIT(8)); + } + if (!rtlphy->rfpi_enable) + rtl8723_phy_pi_mode_switch(hw, true); + + path_sel_bb = rtl_get_bbreg(hw, 0x948, MASKDWORD); + path_sel_rf = rtl_get_rfreg(hw, RF90_PATH_A, 0xb0, 0xfffff); + + /*BB Setting*/ + rtl_set_bbreg(hw, 0x800, BIT(24), 0x00); + rtl_set_bbreg(hw, 0xc04, MASKDWORD, 0x03a05600); + rtl_set_bbreg(hw, 0xc08, MASKDWORD, 0x000800e4); + rtl_set_bbreg(hw, 0x874, MASKDWORD, 0x22204000); + + rtl_set_bbreg(hw, 0x870, BIT(10), 0x01); + rtl_set_bbreg(hw, 0x870, BIT(26), 0x01); + rtl_set_bbreg(hw, 0x860, BIT(10), 0x00); + rtl_set_bbreg(hw, 0x864, BIT(10), 0x00); + + if (is2t) + rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASKDWORD, 0x10000); + rtl8723_phy_mac_setting_calibration(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); + rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x0f600000); + + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000); + rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x01007c00); + rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x81004800); + for (i = 0; i < retrycount; i++) { + patha_ok = _rtl8723be_phy_path_a_iqk(hw, is2t); + if (patha_ok == 0x01) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Path A Tx IQK Success!!\n"); + result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) & + 0x3FF0000) >> 16; + result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & + 0x3FF0000) >> 16; + break; + } + } + + if (0 == patha_ok) + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Path A IQK Success!!\n"); + if (is2t) { + rtl8723_phy_path_a_standby(hw); + rtl8723_phy_path_adda_on(hw, adda_reg, false, is2t); + } + + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0); + + if (t != 0) { + if (!rtlphy->rfpi_enable) + rtl8723_phy_pi_mode_switch(hw, false); + rtl8723_phy_reload_adda_registers(hw, adda_reg, + rtlphy->adda_backup, 16); + rtl8723_phy_reload_mac_registers(hw, iqk_mac_reg, + rtlphy->iqk_mac_backup); + rtl8723_phy_reload_adda_registers(hw, iqk_bb_reg, + rtlphy->iqk_bb_backup, + IQK_BB_REG_NUM); + + rtl_set_bbreg(hw, 0x948, MASKDWORD, path_sel_bb); + rtl_set_rfreg(hw, RF90_PATH_B, 0xb0, 0xfffff, path_sel_rf); + + rtl_set_bbreg(hw, 0xc50, MASKBYTE0, 0x50); + rtl_set_bbreg(hw, 0xc50, MASKBYTE0, tmp_reg_c50); + if (is2t) { + rtl_set_bbreg(hw, 0xc58, MASKBYTE0, 0x50); + rtl_set_bbreg(hw, 0xc58, MASKBYTE0, tmp_reg_c58); + } + rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x01008c00); + rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x01008c00); + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "8723be IQK Finish!!\n"); +} + +static void _rtl8723be_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 tmpreg; + u32 rf_a_mode = 0, rf_b_mode = 0, lc_cal; + + tmpreg = rtl_read_byte(rtlpriv, 0xd03); + + if ((tmpreg & 0x70) != 0) + rtl_write_byte(rtlpriv, 0xd03, tmpreg & 0x8F); + else + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); + + if ((tmpreg & 0x70) != 0) { + rf_a_mode = rtl_get_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS); + + if (is2t) + rf_b_mode = rtl_get_rfreg(hw, RF90_PATH_B, 0x00, + MASK12BITS); + + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS, + (rf_a_mode & 0x8FFFF) | 0x10000); + + if (is2t) + rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS, + (rf_b_mode & 0x8FFFF) | 0x10000); + } + lc_cal = rtl_get_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS); + + rtl_set_rfreg(hw, RF90_PATH_A, 0xb0, RFREG_OFFSET_MASK, 0xdfbe0); + rtl_set_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS, 0x8c0a); + + mdelay(100); + + rtl_set_rfreg(hw, RF90_PATH_A, 0xb0, RFREG_OFFSET_MASK, 0xdffe0); + + if ((tmpreg & 0x70) != 0) { + rtl_write_byte(rtlpriv, 0xd03, tmpreg); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS, rf_a_mode); + + if (is2t) + rtl_set_rfreg(hw, RF90_PATH_B, 0x00, + MASK12BITS, rf_b_mode); + } else { + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); + } + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "\n"); +} + +static void _rtl8723be_phy_set_rfpath_switch(struct ieee80211_hw *hw, + bool bmain, bool is2t) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "\n"); + + if (is_hal_stop(rtlhal)) { + u8 u1btmp; + u1btmp = rtl_read_byte(rtlpriv, REG_LEDCFG0); + rtl_write_byte(rtlpriv, REG_LEDCFG0, u1btmp | BIT(7)); + rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(13), 0x01); + } + if (is2t) { + if (bmain) + rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, + BIT(5) | BIT(6), 0x1); + else + rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, + BIT(5) | BIT(6), 0x2); + } else { + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BIT(8) | BIT(9), 0); + rtl_set_bbreg(hw, 0x914, MASKLWORD, 0x0201); + + /* We use the RF definition of MAIN and AUX, + * left antenna and right antenna repectively. + * Default output at AUX. + */ + if (bmain) { + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, + BIT(14) | BIT(13) | BIT(12), 0); + rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, + BIT(5) | BIT(4) | BIT(3), 0); + if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV) + rtl_set_bbreg(hw, CONFIG_RAM64X16, BIT(31), 0); + } else { + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, + BIT(14) | BIT(13) | BIT(12), 1); + rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, + BIT(5) | BIT(4) | BIT(3), 1); + if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV) + rtl_set_bbreg(hw, CONFIG_RAM64X16, BIT(31), 1); + } + } +} + +#undef IQK_ADDA_REG_NUM +#undef IQK_DELAY_TIME + +void rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + long result[4][8]; + u8 i, final_candidate; + bool patha_ok, pathb_ok; + long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, + reg_ecc, reg_tmp = 0; + bool is12simular, is13simular, is23simular; + u32 iqk_bb_reg[9] = { + ROFDM0_XARXIQIMBALANCE, + ROFDM0_XBRXIQIMBALANCE, + ROFDM0_ECCATHRESHOLD, + ROFDM0_AGCRSSITABLE, + ROFDM0_XATXIQIMBALANCE, + ROFDM0_XBTXIQIMBALANCE, + ROFDM0_XCTXAFE, + ROFDM0_XDTXAFE, + ROFDM0_RXIQEXTANTA + }; + + if (recovery) { + rtl8723_phy_reload_adda_registers(hw, iqk_bb_reg, + rtlphy->iqk_bb_backup, 9); + return; + } + + for (i = 0; i < 8; i++) { + result[0][i] = 0; + result[1][i] = 0; + result[2][i] = 0; + result[3][i] = 0; + } + final_candidate = 0xff; + patha_ok = false; + pathb_ok = false; + is12simular = false; + is23simular = false; + is13simular = false; + for (i = 0; i < 3; i++) { + if (get_rf_type(rtlphy) == RF_2T2R) + _rtl8723be_phy_iq_calibrate(hw, result, i, true); + else + _rtl8723be_phy_iq_calibrate(hw, result, i, false); + if (i == 1) { + is12simular = phy_similarity_cmp(hw, result, 0, 1); + if (is12simular) { + final_candidate = 0; + break; + } + } + if (i == 2) { + is13simular = phy_similarity_cmp(hw, result, 0, 2); + if (is13simular) { + final_candidate = 0; + break; + } + is23simular = phy_similarity_cmp(hw, result, 1, 2); + if (is23simular) { + final_candidate = 1; + } else { + for (i = 0; i < 8; i++) + reg_tmp += result[3][i]; + + if (reg_tmp != 0) + final_candidate = 3; + else + final_candidate = 0xFF; + } + } + } + for (i = 0; i < 4; i++) { + reg_e94 = result[i][0]; + reg_e9c = result[i][1]; + reg_ea4 = result[i][2]; + reg_eac = result[i][3]; + reg_eb4 = result[i][4]; + reg_ebc = result[i][5]; + reg_ec4 = result[i][6]; + reg_ecc = result[i][7]; + } + if (final_candidate != 0xff) { + reg_e94 = result[final_candidate][0]; + rtlphy->reg_e94 = reg_e94; + reg_e9c = result[final_candidate][1]; + rtlphy->reg_e9c = reg_e9c; + reg_ea4 = result[final_candidate][2]; + reg_eac = result[final_candidate][3]; + reg_eb4 = result[final_candidate][4]; + rtlphy->reg_eb4 = reg_eb4; + reg_ebc = result[final_candidate][5]; + rtlphy->reg_ebc = reg_ebc; + reg_ec4 = result[final_candidate][6]; + reg_ecc = result[final_candidate][7]; + patha_ok = true; + pathb_ok = true; + } else { + rtlphy->reg_e94 = 0x100; + rtlphy->reg_eb4 = 0x100; + rtlphy->reg_e9c = 0x0; + rtlphy->reg_ebc = 0x0; + } + if (reg_e94 != 0) /*&&(reg_ea4 != 0) */ + rtl8723_phy_path_a_fill_iqk_matrix(hw, patha_ok, result, + final_candidate, + (reg_ea4 == 0)); + if (final_candidate != 0xFF) { + for (i = 0; i < IQK_MATRIX_REG_NUM; i++) + rtlphy->iqk_matrix[0].value[0][i] = + result[final_candidate][i]; + rtlphy->iqk_matrix[0].iqk_done = true; + } + rtl8723_save_adda_registers(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 9); +} + +void rtl8723be_phy_lc_calibrate(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = &(rtlpriv->rtlhal); + u32 timeout = 2000, timecount = 0; + + while (rtlpriv->mac80211.act_scanning && timecount < timeout) { + udelay(50); + timecount += 50; + } + + rtlphy->lck_inprogress = true; + RTPRINT(rtlpriv, FINIT, INIT_EEPROM, + "LCK:Start!!! currentband %x delay %d ms\n", + rtlhal->current_bandtype, timecount); + + _rtl8723be_phy_lc_calibrate(hw, false); + + rtlphy->lck_inprogress = false; +} + +void rtl23b_phy_ap_calibrate(struct ieee80211_hw *hw, char delta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + if (rtlphy->apk_done) + return; + + return; +} + +void rtl8723be_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain) +{ + _rtl8723be_phy_set_rfpath_switch(hw, bmain, false); +} + +static void rtl8723be_phy_set_io(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, + "--->Cmd(%#x), set_io_inprogress(%d)\n", + rtlphy->current_io_type, rtlphy->set_io_inprogress); + switch (rtlphy->current_io_type) { + case IO_CMD_RESUME_DM_BY_SCAN: + rtlpriv->dm_digtable.cur_igvalue = + rtlphy->initgain_backup.xaagccore1; + /*rtl92c_dm_write_dig(hw);*/ + rtl8723be_phy_set_txpower_level(hw, rtlphy->current_channel); + rtl_set_bbreg(hw, RCCK0_CCA, 0xff0000, 0x83); + break; + case IO_CMD_PAUSE_DM_BY_SCAN: + rtlphy->initgain_backup.xaagccore1 = + rtlpriv->dm_digtable.cur_igvalue; + rtlpriv->dm_digtable.cur_igvalue = 0x17; + rtl_set_bbreg(hw, RCCK0_CCA, 0xff0000, 0x40); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not process\n"); + break; + } + rtlphy->set_io_inprogress = false; + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, + "(%#x)\n", rtlphy->current_io_type); +} + +bool rtl8723be_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + bool postprocessing = false; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, + "-->IO Cmd(%#x), set_io_inprogress(%d)\n", + iotype, rtlphy->set_io_inprogress); + do { + switch (iotype) { + case IO_CMD_RESUME_DM_BY_SCAN: + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, + "[IO CMD] Resume DM after scan.\n"); + postprocessing = true; + break; + case IO_CMD_PAUSE_DM_BY_SCAN: + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, + "[IO CMD] Pause DM before scan.\n"); + postprocessing = true; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not process\n"); + break; + } + } while (false); + if (postprocessing && !rtlphy->set_io_inprogress) { + rtlphy->set_io_inprogress = true; + rtlphy->current_io_type = iotype; + } else { + return false; + } + rtl8723be_phy_set_io(hw); + RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "IO Type(%#x)\n", iotype); + return true; +} + +static void rtl8723be_phy_set_rf_on(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); +} + +static void _rtl8723be_phy_set_rf_sleep(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22); +} + +static bool _rtl8723be_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool bresult = true; + u8 i, queue_id; + struct rtl8192_tx_ring *ring = NULL; + + switch (rfpwr_state) { + case ERFON: + if ((ppsc->rfpwr_state == ERFOFF) && + RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) { + bool rtstatus; + u32 initialize_count = 0; + do { + initialize_count++; + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "IPS Set eRf nic enable\n"); + rtstatus = rtl_ps_enable_nic(hw); + } while (!rtstatus && (initialize_count < 10)); + RT_CLEAR_PS_LEVEL(ppsc, + RT_RF_OFF_LEVL_HALT_NIC); + } else { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "Set ERFON sleeped:%d ms\n", + jiffies_to_msecs(jiffies - + ppsc->last_sleep_jiffies)); + ppsc->last_awake_jiffies = jiffies; + rtl8723be_phy_set_rf_on(hw); + } + if (mac->link_state == MAC80211_LINKED) + rtlpriv->cfg->ops->led_control(hw, LED_CTL_LINK); + else + rtlpriv->cfg->ops->led_control(hw, LED_CTL_NO_LINK); + break; + case ERFOFF: + for (queue_id = 0, i = 0; + queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { + ring = &pcipriv->dev.tx_ring[queue_id]; + if (skb_queue_len(&ring->queue) == 0) { + queue_id++; + continue; + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "eRf Off/Sleep: %d times " + "TcbBusyQueue[%d] =%d before " + "doze!\n", (i + 1), queue_id, + skb_queue_len(&ring->queue)); + + udelay(10); + i++; + } + if (i >= MAX_DOZE_WAITING_TIMES_9x) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "\n ERFSLEEP: %d times " + "TcbBusyQueue[%d] = %d !\n", + MAX_DOZE_WAITING_TIMES_9x, + queue_id, + skb_queue_len(&ring->queue)); + break; + } + } + + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "IPS Set eRf nic disable\n"); + rtl_ps_disable_nic(hw); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + } else { + if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) { + rtlpriv->cfg->ops->led_control(hw, + LED_CTL_NO_LINK); + } else { + rtlpriv->cfg->ops->led_control(hw, + LED_CTL_POWER_OFF); + } + } + break; + case ERFSLEEP: + if (ppsc->rfpwr_state == ERFOFF) + break; + for (queue_id = 0, i = 0; + queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { + ring = &pcipriv->dev.tx_ring[queue_id]; + if (skb_queue_len(&ring->queue) == 0) { + queue_id++; + continue; + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "eRf Off/Sleep: %d times " + "TcbBusyQueue[%d] =%d before " + "doze!\n", (i + 1), queue_id, + skb_queue_len(&ring->queue)); + + udelay(10); + i++; + } + if (i >= MAX_DOZE_WAITING_TIMES_9x) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "\n ERFSLEEP: %d times " + "TcbBusyQueue[%d] = %d !\n", + MAX_DOZE_WAITING_TIMES_9x, + queue_id, + skb_queue_len(&ring->queue)); + break; + } + } + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + "Set ERFSLEEP awaked:%d ms\n", + jiffies_to_msecs(jiffies - + ppsc->last_awake_jiffies)); + ppsc->last_sleep_jiffies = jiffies; + _rtl8723be_phy_set_rf_sleep(hw); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "switch case not process\n"); + bresult = false; + break; + } + if (bresult) + ppsc->rfpwr_state = rfpwr_state; + return bresult; +} + +bool rtl8723be_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state) +{ + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + bool bresult = false; + + if (rfpwr_state == ppsc->rfpwr_state) + return bresult; + bresult = _rtl8723be_phy_set_rf_power_state(hw, rfpwr_state); + return bresult; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/phy.h b/drivers/net/wireless/rtlwifi/rtl8723be/phy.h new file mode 100644 index 000000000000..444ef95bb6af --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/phy.h @@ -0,0 +1,217 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8723BE_PHY_H__ +#define __RTL8723BE_PHY_H__ + +/*It must always set to 4, otherwise read efuse table secquence will be wrong.*/ +#define MAX_TX_COUNT 4 +#define TX_1S 0 +#define TX_2S 1 + +#define MAX_POWER_INDEX 0x3F + +#define MAX_PRECMD_CNT 16 +#define MAX_RFDEPENDCMD_CNT 16 +#define MAX_POSTCMD_CNT 16 + +#define MAX_DOZE_WAITING_TIMES_9x 64 + +#define RT_CANNOT_IO(hw) false +#define HIGHPOWER_RADIOA_ARRAYLEN 22 + +#define IQK_ADDA_REG_NUM 16 +#define IQK_BB_REG_NUM 9 +#define MAX_TOLERANCE 5 +#define IQK_DELAY_TIME 10 +#define index_mapping_NUM 15 + +#define APK_BB_REG_NUM 5 +#define APK_AFE_REG_NUM 16 +#define APK_CURVE_REG_NUM 4 +#define PATH_NUM 1 + +#define LOOP_LIMIT 5 +#define MAX_STALL_TIME 50 +#define ANTENNADIVERSITYVALUE 0x80 +#define MAX_TXPWR_IDX_NMODE_92S 63 +#define RESET_CNT_LIMIT 3 + +#define IQK_ADDA_REG_NUM 16 +#define IQK_MAC_REG_NUM 4 + +#define RF6052_MAX_PATH 2 + +#define CT_OFFSET_MAC_ADDR 0X16 + +#define CT_OFFSET_CCK_TX_PWR_IDX 0x5A +#define CT_OFFSET_HT401S_TX_PWR_IDX 0x60 +#define CT_OFFSET_HT402S_TX_PWR_IDX_DIFF 0x66 +#define CT_OFFSET_HT20_TX_PWR_IDX_DIFF 0x69 +#define CT_OFFSET_OFDM_TX_PWR_IDX_DIFF 0x6C + +#define CT_OFFSET_HT40_MAX_PWR_OFFSET 0x6F +#define CT_OFFSET_HT20_MAX_PWR_OFFSET 0x72 + +#define CT_OFFSET_CHANNEL_PLAH 0x75 +#define CT_OFFSET_THERMAL_METER 0x78 +#define CT_OFFSET_RF_OPTION 0x79 +#define CT_OFFSET_VERSION 0x7E +#define CT_OFFSET_CUSTOMER_ID 0x7F + +#define RTL92C_MAX_PATH_NUM 2 + +enum hw90_block_e { + HW90_BLOCK_MAC = 0, + HW90_BLOCK_PHY0 = 1, + HW90_BLOCK_PHY1 = 2, + HW90_BLOCK_RF = 3, + HW90_BLOCK_MAXIMUM = 4, +}; + +enum baseband_config_type { + BASEBAND_CONFIG_PHY_REG = 0, + BASEBAND_CONFIG_AGC_TAB = 1, +}; + +enum ra_offset_area { + RA_OFFSET_LEGACY_OFDM1, + RA_OFFSET_LEGACY_OFDM2, + RA_OFFSET_HT_OFDM1, + RA_OFFSET_HT_OFDM2, + RA_OFFSET_HT_OFDM3, + RA_OFFSET_HT_OFDM4, + RA_OFFSET_HT_CCK, +}; + +enum antenna_path { + ANTENNA_NONE, + ANTENNA_D, + ANTENNA_C, + ANTENNA_CD, + ANTENNA_B, + ANTENNA_BD, + ANTENNA_BC, + ANTENNA_BCD, + ANTENNA_A, + ANTENNA_AD, + ANTENNA_AC, + ANTENNA_ACD, + ANTENNA_AB, + ANTENNA_ABD, + ANTENNA_ABC, + ANTENNA_ABCD +}; + +struct r_antenna_select_ofdm { + u32 r_tx_antenna:4; + u32 r_ant_l:4; + u32 r_ant_non_ht:4; + u32 r_ant_ht1:4; + u32 r_ant_ht2:4; + u32 r_ant_ht_s1:4; + u32 r_ant_non_ht_s1:4; + u32 ofdm_txsc:2; + u32 reserved:2; +}; + +struct r_antenna_select_cck { + u8 r_cckrx_enable_2:2; + u8 r_cckrx_enable:2; + u8 r_ccktx_enable:4; +}; + + +struct efuse_contents { + u8 mac_addr[ETH_ALEN]; + u8 cck_tx_power_idx[6]; + u8 ht40_1s_tx_power_idx[6]; + u8 ht40_2s_tx_power_idx_diff[3]; + u8 ht20_tx_power_idx_diff[3]; + u8 ofdm_tx_power_idx_diff[3]; + u8 ht40_max_power_offset[3]; + u8 ht20_max_power_offset[3]; + u8 channel_plan; + u8 thermal_meter; + u8 rf_option[5]; + u8 version; + u8 oem_id; + u8 regulatory; +}; + +struct tx_power_struct { + u8 cck[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 ht40_1s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 ht40_2s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 ht20_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 legacy_ht_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 legacy_ht_txpowerdiff; + u8 groupht20[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 groupht40[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; + u8 pwrgroup_cnt; + u32 mcs_original_offset[4][16]; +}; + +enum _ANT_DIV_TYPE { + NO_ANTDIV = 0xFF, + CG_TRX_HW_ANTDIV = 0x01, + CGCS_RX_HW_ANTDIV = 0x02, + FIXED_HW_ANTDIV = 0x03, + CG_TRX_SMART_ANTDIV = 0x04, + CGCS_RX_SW_ANTDIV = 0x05, +}; + +u32 rtl8723be_phy_query_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, + u32 regaddr, u32 bitmask); +void rtl8723be_phy_set_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data); +bool rtl8723be_phy_mac_config(struct ieee80211_hw *hw); +bool rtl8723be_phy_bb_config(struct ieee80211_hw *hw); +bool rtl8723be_phy_rf_config(struct ieee80211_hw *hw); +void rtl8723be_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +void rtl8723be_phy_get_txpower_level(struct ieee80211_hw *hw, + long *powerlevel); +void rtl8723be_phy_set_txpower_level(struct ieee80211_hw *hw, + u8 channel); +void rtl8723be_phy_scan_operation_backup(struct ieee80211_hw *hw, + u8 operation); +void rtl8723be_phy_set_bw_mode_callback(struct ieee80211_hw *hw); +void rtl8723be_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type); +void rtl8723be_phy_sw_chnl_callback(struct ieee80211_hw *hw); +u8 rtl8723be_phy_sw_chnl(struct ieee80211_hw *hw); +void rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw, + bool b_recovery); +void rtl23b_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); +void rtl8723be_phy_lc_calibrate(struct ieee80211_hw *hw); +void rtl8723be_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); +bool rtl8723be_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, + enum radio_path rfpath); +bool rtl8723be_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); +bool rtl8723be_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state); +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.c b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.c new file mode 100644 index 000000000000..b5167e73fecf --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.c @@ -0,0 +1,106 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "pwrseqcmd.h" +#include "pwrseq.h" + + +/* drivers should parse below arrays and do the corresponding actions */ +/*3 Power on Array*/ +struct wlan_pwr_cfg rtl8723B_power_on_flow[RTL8723B_TRANS_CARDEMU_TO_ACT_STEPS + + RTL8723B_TRANS_END_STEPS] = { + RTL8723B_TRANS_CARDEMU_TO_ACT + RTL8723B_TRANS_END +}; + +/*3Radio off GPIO Array */ +struct wlan_pwr_cfg rtl8723B_radio_off_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8723B_TRANS_END_STEPS] = { + RTL8723B_TRANS_ACT_TO_CARDEMU + RTL8723B_TRANS_END +}; + +/*3Card Disable Array*/ +struct wlan_pwr_cfg rtl8723B_card_disable_flow + [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS + + RTL8723B_TRANS_END_STEPS] = { + RTL8723B_TRANS_ACT_TO_CARDEMU + RTL8723B_TRANS_CARDEMU_TO_CARDDIS + RTL8723B_TRANS_END +}; + +/*3 Card Enable Array*/ +struct wlan_pwr_cfg rtl8723B_card_enable_flow + [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS + + RTL8723B_TRANS_END_STEPS] = { + RTL8723B_TRANS_CARDDIS_TO_CARDEMU + RTL8723B_TRANS_CARDEMU_TO_ACT + RTL8723B_TRANS_END +}; + +/*3Suspend Array*/ +struct wlan_pwr_cfg rtl8723B_suspend_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS + + RTL8723B_TRANS_END_STEPS] = { + RTL8723B_TRANS_ACT_TO_CARDEMU + RTL8723B_TRANS_CARDEMU_TO_SUS + RTL8723B_TRANS_END +}; + +/*3 Resume Array*/ +struct wlan_pwr_cfg rtl8723B_resume_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS + + RTL8723B_TRANS_END_STEPS] = { + RTL8723B_TRANS_SUS_TO_CARDEMU + RTL8723B_TRANS_CARDEMU_TO_ACT + RTL8723B_TRANS_END +}; + +/*3HWPDN Array*/ +struct wlan_pwr_cfg rtl8723B_hwpdn_flow[RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS + + RTL8723B_TRANS_END_STEPS] = { + RTL8723B_TRANS_ACT_TO_CARDEMU + RTL8723B_TRANS_CARDEMU_TO_PDN + RTL8723B_TRANS_END +}; + +/*3 Enter LPS */ +struct wlan_pwr_cfg rtl8723B_enter_lps_flow[RTL8723B_TRANS_ACT_TO_LPS_STEPS + + RTL8723B_TRANS_END_STEPS] = { + /*FW behavior*/ + RTL8723B_TRANS_ACT_TO_LPS + RTL8723B_TRANS_END +}; + +/*3 Leave LPS */ +struct wlan_pwr_cfg rtl8723B_leave_lps_flow[RTL8723B_TRANS_LPS_TO_ACT_STEPS + + RTL8723B_TRANS_END_STEPS] = { + /*FW behavior*/ + RTL8723B_TRANS_LPS_TO_ACT + RTL8723B_TRANS_END +}; diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h new file mode 100644 index 000000000000..960b408216df --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h @@ -0,0 +1,305 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8723BE_PWRSEQ_H__ +#define __RTL8723BE_PWRSEQ_H__ + +#include "pwrseqcmd.h" +/* Check document WM-20130425-JackieLau-RTL8723B_Power_Architecture v05.vsd + * There are 6 HW Power States: + * 0: POFF--Power Off + * 1: PDN--Power Down + * 2: CARDEMU--Card Emulation + * 3: ACT--Active Mode + * 4: LPS--Low Power State + * 5: SUS--Suspend + * + * The transition from different states are defined below + * TRANS_CARDEMU_TO_ACT + * TRANS_ACT_TO_CARDEMU + * TRANS_CARDEMU_TO_SUS + * TRANS_SUS_TO_CARDEMU + * TRANS_CARDEMU_TO_PDN + * TRANS_ACT_TO_LPS + * TRANS_LPS_TO_ACT + * + * TRANS_END + */ +#define RTL8723B_TRANS_CARDEMU_TO_ACT_STEPS 23 +#define RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS 15 +#define RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS 15 +#define RTL8723B_TRANS_SUS_TO_CARDEMU_STEPS 15 +#define RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS 15 +#define RTL8723B_TRANS_PDN_TO_CARDEMU_STEPS 15 +#define RTL8723B_TRANS_ACT_TO_LPS_STEPS 15 +#define RTL8723B_TRANS_LPS_TO_ACT_STEPS 15 +#define RTL8723B_TRANS_END_STEPS 1 + +#define RTL8723B_TRANS_CARDEMU_TO_ACT \ + {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \ + PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)}, \ + {0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \ + PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, \ + {0x0001, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \ + PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_DELAY, 1, PWRSEQ_DELAY_MS}, \ + {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \ + PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), 0}, \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT(4)|BIT(3)|BIT(2)), 0}, \ + {0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0) , 0}, \ + {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), BIT(1)}, \ + {0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0) , BIT(0)}, \ + {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)}, \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0}, \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT(4)|BIT(3)), 0}, \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)}, \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(0), 0}, \ + {0x0010, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6), BIT(6)}, \ + {0x0049, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)}, \ + {0x0063, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)}, \ + {0x0062, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0}, \ + {0x0058, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)}, \ + {0x005A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)}, \ + {0x0068, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3), BIT(3)}, \ + {0x0069, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6), BIT(6)}, + +#define RTL8723B_TRANS_ACT_TO_CARDEMU \ + {0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, \ + {0x004F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0}, \ + {0x0049, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0}, \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)}, \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), 0}, \ + {0x0010, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6), 0}, \ + {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \ + PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, \ + PWR_CMD_WRITE, BIT(5), BIT(5)}, \ + {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \ + PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, \ + PWR_CMD_WRITE, BIT(0), 0}, + +#define RTL8723B_TRANS_CARDEMU_TO_SUS \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4) | BIT(3), (BIT(4) | BIT(3))}, \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \ + PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, \ + PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3)}, \ + {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, \ + {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3) | BIT(4)},\ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)}, \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0}, + +#define RTL8723B_TRANS_SUS_TO_CARDEMU \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(7), 0}, \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0}, \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)}, \ + {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0}, + +#define RTL8723B_TRANS_CARDEMU_TO_CARDDIS \ + {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \ + PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)}, \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(2), BIT(2)}, \ + {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 1}, \ + {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)}, \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0}, + +#define RTL8723B_TRANS_CARDDIS_TO_CARDEMU \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(7), 0}, \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0}, \ + {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)}, \ + {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0}, \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0}, \ + {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, \ + {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, + +#define RTL8723B_TRANS_CARDEMU_TO_PDN \ + {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, \ + {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \ + PWR_INTF_SDIO_MSK | PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, \ + PWR_CMD_WRITE, 0xFF, 0x20}, \ + {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0}, \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)}, + +#define RTL8723B_TRANS_PDN_TO_CARDEMU \ + {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0}, + +#define RTL8723B_TRANS_ACT_TO_LPS \ + {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, \ + {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, \ + {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0}, \ + {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0}, \ + {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0}, \ + {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0}, \ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0}, \ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US}, \ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0}, \ + {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x03}, \ + {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0}, \ + {0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00}, \ + {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), BIT(5)}, + +#define RTL8723B_TRANS_LPS_TO_ACT \ + {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ + PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84}, \ + {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, \ + {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, \ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, \ + {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, \ + {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(7), 0}, \ + {0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6)|BIT(7), 0}, \ + {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)}, \ + {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, \ + {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1) | BIT(0), BIT(1) | BIT(0)}, \ + {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, + +#define RTL8723B_TRANS_END \ + {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, 0, \ + PWR_CMD_END, 0, 0}, + +extern struct wlan_pwr_cfg rtl8723B_power_on_flow + [RTL8723B_TRANS_CARDEMU_TO_ACT_STEPS + + RTL8723B_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723B_radio_off_flow + [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8723B_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723B_card_disable_flow + [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS + + RTL8723B_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723B_card_enable_flow + [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS + + RTL8723B_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723B_suspend_flow + [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS + + RTL8723B_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723B_resume_flow + [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8723B_TRANS_CARDEMU_TO_SUS_STEPS + + RTL8723B_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723B_hwpdn_flow + [RTL8723B_TRANS_ACT_TO_CARDEMU_STEPS + + RTL8723B_TRANS_CARDEMU_TO_PDN_STEPS + + RTL8723B_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723B_enter_lps_flow + [RTL8723B_TRANS_ACT_TO_LPS_STEPS + + RTL8723B_TRANS_END_STEPS]; +extern struct wlan_pwr_cfg rtl8723B_leave_lps_flow + [RTL8723B_TRANS_LPS_TO_ACT_STEPS + + RTL8723B_TRANS_END_STEPS]; + +/* RTL8723 Power Configuration CMDs for PCIe interface */ +#define RTL8723_NIC_PWR_ON_FLOW rtl8723B_power_on_flow +#define RTL8723_NIC_RF_OFF_FLOW rtl8723B_radio_off_flow +#define RTL8723_NIC_DISABLE_FLOW rtl8723B_card_disable_flow +#define RTL8723_NIC_ENABLE_FLOW rtl8723B_card_enable_flow +#define RTL8723_NIC_SUSPEND_FLOW rtl8723B_suspend_flow +#define RTL8723_NIC_RESUME_FLOW rtl8723B_resume_flow +#define RTL8723_NIC_PDN_FLOW rtl8723B_hwpdn_flow +#define RTL8723_NIC_LPS_ENTER_FLOW rtl8723B_enter_lps_flow +#define RTL8723_NIC_LPS_LEAVE_FLOW rtl8723B_leave_lps_flow + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.c b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.c new file mode 100644 index 000000000000..e4a507a756fb --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.c @@ -0,0 +1,140 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "pwrseq.h" + +/* Description: + * This routine deal with the Power Configuration CMDs + * parsing for RTL8723/RTL8188E Series IC. + * Assumption: + * We should follow specific format which was released from HW SD. + * + * 2011.07.07, added by Roger. + */ +bool rtlbe_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version, + u8 fab_version, u8 interface_type, + struct wlan_pwr_cfg pwrcfgcmd[]) + +{ + struct wlan_pwr_cfg pwr_cfg_cmd = {0}; + bool b_polling_bit = false; + u32 ary_idx = 0; + u8 value = 0; + u32 offset = 0; + u32 polling_count = 0; + u32 max_polling_cnt = 5000; + + do { + pwr_cfg_cmd = pwrcfgcmd[ary_idx]; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "rtlbe_hal_pwrseqcmdparsing(): " + "offset(%#x),cut_msk(%#x), fab_msk(%#x)," + "interface_msk(%#x), base(%#x), " + "cmd(%#x), msk(%#x), value(%#x)\n", + GET_PWR_CFG_OFFSET(pwr_cfg_cmd), + GET_PWR_CFG_CUT_MASK(pwr_cfg_cmd), + GET_PWR_CFG_FAB_MASK(pwr_cfg_cmd), + GET_PWR_CFG_INTF_MASK(pwr_cfg_cmd), + GET_PWR_CFG_BASE(pwr_cfg_cmd), + GET_PWR_CFG_CMD(pwr_cfg_cmd), + GET_PWR_CFG_MASK(pwr_cfg_cmd), + GET_PWR_CFG_VALUE(pwr_cfg_cmd)); + + if ((GET_PWR_CFG_FAB_MASK(pwr_cfg_cmd)&fab_version) && + (GET_PWR_CFG_CUT_MASK(pwr_cfg_cmd)&cut_version) && + (GET_PWR_CFG_INTF_MASK(pwr_cfg_cmd)&interface_type)) { + switch (GET_PWR_CFG_CMD(pwr_cfg_cmd)) { + case PWR_CMD_READ: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "rtlbe_hal_pwrseqcmdparsing(): " + "PWR_CMD_READ\n"); + break; + case PWR_CMD_WRITE: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "rtlbe_hal_pwrseqcmdparsing(): " + "PWR_CMD_WRITE\n"); + offset = GET_PWR_CFG_OFFSET(pwr_cfg_cmd); + + /*Read the value from system register*/ + value = rtl_read_byte(rtlpriv, offset); + value &= (~(GET_PWR_CFG_MASK(pwr_cfg_cmd))); + value = value | (GET_PWR_CFG_VALUE(pwr_cfg_cmd) + & GET_PWR_CFG_MASK(pwr_cfg_cmd)); + + /*Write the value back to sytem register*/ + rtl_write_byte(rtlpriv, offset, value); + break; + case PWR_CMD_POLLING: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "rtlbe_hal_pwrseqcmdparsing(): " + "PWR_CMD_POLLING\n"); + b_polling_bit = false; + offset = GET_PWR_CFG_OFFSET(pwr_cfg_cmd); + + do { + value = rtl_read_byte(rtlpriv, offset); + + value &= GET_PWR_CFG_MASK(pwr_cfg_cmd); + if (value == + (GET_PWR_CFG_VALUE(pwr_cfg_cmd) & + GET_PWR_CFG_MASK(pwr_cfg_cmd))) + b_polling_bit = true; + else + udelay(10); + + if (polling_count++ > max_polling_cnt) + return false; + + } while (!b_polling_bit); + break; + case PWR_CMD_DELAY: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "rtlbe_hal_pwrseqcmdparsing(): " + "PWR_CMD_DELAY\n"); + if (GET_PWR_CFG_VALUE(pwr_cfg_cmd) == + PWRSEQ_DELAY_US) + udelay(GET_PWR_CFG_OFFSET(pwr_cfg_cmd)); + else + mdelay(GET_PWR_CFG_OFFSET(pwr_cfg_cmd)); + break; + case PWR_CMD_END: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "rtlbe_hal_pwrseqcmdparsing(): " + "PWR_CMD_END\n"); + return true; + break; + default: + RT_ASSERT(false, + "rtlbe_hal_pwrseqcmdparsing(): " + "Unknown CMD!!\n"); + break; + } + } + + ary_idx++; + } while (1); + + return true; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.h b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.h new file mode 100644 index 000000000000..ce14a3b5cb71 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.h @@ -0,0 +1,95 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8723BE_PWRSEQCMD_H__ +#define __RTL8723BE_PWRSEQCMD_H__ + +#include "../wifi.h" +/*---------------------------------------------*/ +/*The value of cmd: 4 bits */ +/*---------------------------------------------*/ +#define PWR_CMD_READ 0x00 +#define PWR_CMD_WRITE 0x01 +#define PWR_CMD_POLLING 0x02 +#define PWR_CMD_DELAY 0x03 +#define PWR_CMD_END 0x04 + +/* define the base address of each block */ +#define PWR_BASEADDR_MAC 0x00 +#define PWR_BASEADDR_USB 0x01 +#define PWR_BASEADDR_PCIE 0x02 +#define PWR_BASEADDR_SDIO 0x03 + +#define PWR_INTF_SDIO_MSK BIT(0) +#define PWR_INTF_USB_MSK BIT(1) +#define PWR_INTF_PCI_MSK BIT(2) +#define PWR_INTF_ALL_MSK (BIT(0) | BIT(1) | BIT(2) | BIT(3)) + +#define PWR_FAB_TSMC_MSK BIT(0) +#define PWR_FAB_UMC_MSK BIT(1) +#define PWR_FAB_ALL_MSK (BIT(0) | BIT(1) | BIT(2) | BIT(3)) + +#define PWR_CUT_TESTCHIP_MSK BIT(0) +#define PWR_CUT_A_MSK BIT(1) +#define PWR_CUT_B_MSK BIT(2) +#define PWR_CUT_C_MSK BIT(3) +#define PWR_CUT_D_MSK BIT(4) +#define PWR_CUT_E_MSK BIT(5) +#define PWR_CUT_F_MSK BIT(6) +#define PWR_CUT_G_MSK BIT(7) +#define PWR_CUT_ALL_MSK 0xFF + + +enum pwrseq_delay_unit { + PWRSEQ_DELAY_US, + PWRSEQ_DELAY_MS, +}; + +struct wlan_pwr_cfg { + u16 offset; + u8 cut_msk; + u8 fab_msk:4; + u8 interface_msk:4; + u8 base:4; + u8 cmd:4; + u8 msk; + u8 value; + +}; + +#define GET_PWR_CFG_OFFSET(__PWR_CMD) __PWR_CMD.offset +#define GET_PWR_CFG_CUT_MASK(__PWR_CMD) __PWR_CMD.cut_msk +#define GET_PWR_CFG_FAB_MASK(__PWR_CMD) __PWR_CMD.fab_msk +#define GET_PWR_CFG_INTF_MASK(__PWR_CMD) __PWR_CMD.interface_msk +#define GET_PWR_CFG_BASE(__PWR_CMD) __PWR_CMD.base +#define GET_PWR_CFG_CMD(__PWR_CMD) __PWR_CMD.cmd +#define GET_PWR_CFG_MASK(__PWR_CMD) __PWR_CMD.msk +#define GET_PWR_CFG_VALUE(__PWR_CMD) __PWR_CMD.value + +bool rtlbe_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version, + u8 fab_version, u8 interface_type, + struct wlan_pwr_cfg pwrcfgcmd[]); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/reg.h b/drivers/net/wireless/rtlwifi/rtl8723be/reg.h new file mode 100644 index 000000000000..65221e678230 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/reg.h @@ -0,0 +1,2293 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8723BE_REG_H__ +#define __RTL8723BE_REG_H__ + +#define TXPKT_BUF_SELECT 0x69 +#define RXPKT_BUF_SELECT 0xA5 +#define DISABLE_TRXPKT_BUF_ACCESS 0x0 + +#define REG_SYS_ISO_CTRL 0x0000 +#define REG_SYS_FUNC_EN 0x0002 +#define REG_APS_FSMCO 0x0004 +#define REG_SYS_CLKR 0x0008 +#define REG_9346CR 0x000A +#define REG_EE_VPD 0x000C +#define REG_AFE_MISC 0x0010 +#define REG_SPS0_CTRL 0x0011 +#define REG_SPS_OCP_CFG 0x0018 +#define REG_RSV_CTRL 0x001C +#define REG_RF_CTRL 0x001F +#define REG_LDOA15_CTRL 0x0020 +#define REG_LDOV12D_CTRL 0x0021 +#define REG_LDOHCI12_CTRL 0x0022 +#define REG_LPLDO_CTRL 0x0023 +#define REG_AFE_XTAL_CTRL 0x0024 +/* 1.5v for 8188EE test chip, 1.4v for MP chip */ +#define REG_AFE_LDO_CTRL 0x0027 +#define REG_AFE_PLL_CTRL 0x0028 +#define REG_MAC_PHY_CTRL 0x002c +#define REG_EFUSE_CTRL 0x0030 +#define REG_EFUSE_TEST 0x0034 +#define REG_PWR_DATA 0x0038 +#define REG_CAL_TIMER 0x003C +#define REG_ACLK_MON 0x003E +#define REG_GPIO_MUXCFG 0x0040 +#define REG_GPIO_IO_SEL 0x0042 +#define REG_MAC_PINMUX_CFG 0x0043 +#define REG_GPIO_PIN_CTRL 0x0044 +#define REG_GPIO_INTM 0x0048 +#define REG_LEDCFG0 0x004C +#define REG_LEDCFG1 0x004D +#define REG_LEDCFG2 0x004E +#define REG_LEDCFG3 0x004F +#define REG_FSIMR 0x0050 +#define REG_FSISR 0x0054 +#define REG_HSIMR 0x0058 +#define REG_HSISR 0x005c +#define REG_GPIO_PIN_CTRL_2 0x0060 +#define REG_GPIO_IO_SEL_2 0x0062 +#define REG_MULTI_FUNC_CTRL 0x0068 +#define REG_GPIO_OUTPUT 0x006c +#define REG_AFE_XTAL_CTRL_EXT 0x0078 +#define REG_XCK_OUT_CTRL 0x007c +#define REG_MCUFWDL 0x0080 +#define REG_WOL_EVENT 0x0081 +#define REG_MCUTSTCFG 0x0084 + + +#define REG_HIMR 0x00B0 +#define REG_HISR 0x00B4 +#define REG_HIMRE 0x00B8 +#define REG_HISRE 0x00BC + +#define REG_EFUSE_ACCESS 0x00CF + +#define REG_BIST_SCAN 0x00D0 +#define REG_BIST_RPT 0x00D4 +#define REG_BIST_ROM_RPT 0x00D8 +#define REG_USB_SIE_INTF 0x00E0 +#define REG_PCIE_MIO_INTF 0x00E4 +#define REG_PCIE_MIO_INTD 0x00E8 +#define REG_HPON_FSM 0x00EC +#define REG_SYS_CFG 0x00F0 +#define REG_GPIO_OUTSTS 0x00F4 +#define REG_SYS_CFG1 0x00F0 +#define REG_ROM_VERSION 0x00FD + +#define REG_CR 0x0100 +#define REG_PBP 0x0104 +#define REG_PKT_BUFF_ACCESS_CTRL 0x0106 +#define REG_TRXDMA_CTRL 0x010C +#define REG_TRXFF_BNDY 0x0114 +#define REG_TRXFF_STATUS 0x0118 +#define REG_RXFF_PTR 0x011C + +#define REG_CPWM 0x012F +#define REG_FWIMR 0x0130 +#define REG_FWISR 0x0134 +#define REG_PKTBUF_DBG_CTRL 0x0140 +#define REG_PKTBUF_DBG_DATA_L 0x0144 +#define REG_PKTBUF_DBG_DATA_H 0x0148 +#define REG_RXPKTBUF_CTRL (REG_PKTBUF_DBG_CTRL + 2) + +#define REG_TC0_CTRL 0x0150 +#define REG_TC1_CTRL 0x0154 +#define REG_TC2_CTRL 0x0158 +#define REG_TC3_CTRL 0x015C +#define REG_TC4_CTRL 0x0160 +#define REG_TCUNIT_BASE 0x0164 +#define REG_MBIST_START 0x0174 +#define REG_MBIST_DONE 0x0178 +#define REG_MBIST_FAIL 0x017C +#define REG_32K_CTRL 0x0194 +#define REG_C2HEVT_MSG_NORMAL 0x01A0 +#define REG_C2HEVT_CLEAR 0x01AF +#define REG_C2HEVT_MSG_TEST 0x01B8 +#define REG_MCUTST_1 0x01c0 +#define REG_FMETHR 0x01C8 +#define REG_HMETFR 0x01CC +#define REG_HMEBOX_0 0x01D0 +#define REG_HMEBOX_1 0x01D4 +#define REG_HMEBOX_2 0x01D8 +#define REG_HMEBOX_3 0x01DC + +#define REG_LLT_INIT 0x01E0 +#define REG_BB_ACCEESS_CTRL 0x01E8 +#define REG_BB_ACCESS_DATA 0x01EC + +#define REG_HMEBOX_EXT_0 0x01F0 +#define REG_HMEBOX_EXT_1 0x01F4 +#define REG_HMEBOX_EXT_2 0x01F8 +#define REG_HMEBOX_EXT_3 0x01FC + +#define REG_RQPN 0x0200 +#define REG_FIFOPAGE 0x0204 +#define REG_TDECTRL 0x0208 +#define REG_TXDMA_OFFSET_CHK 0x020C +#define REG_TXDMA_STATUS 0x0210 +#define REG_RQPN_NPQ 0x0214 + +#define REG_RXDMA_AGG_PG_TH 0x0280 +/* FW shall update this register before FW write RXPKT_RELEASE_POLL to 1 */ +#define REG_FW_UPD_RDPTR 0x0284 +/* Control the RX DMA.*/ +#define REG_RXDMA_CONTROL 0x0286 +/* The number of packets in RXPKTBUF. */ +#define REG_RXPKT_NUM 0x0287 + +#define REG_PCIE_CTRL_REG 0x0300 +#define REG_INT_MIG 0x0304 +#define REG_BCNQ_DESA 0x0308 +#define REG_HQ_DESA 0x0310 +#define REG_MGQ_DESA 0x0318 +#define REG_VOQ_DESA 0x0320 +#define REG_VIQ_DESA 0x0328 +#define REG_BEQ_DESA 0x0330 +#define REG_BKQ_DESA 0x0338 +#define REG_RX_DESA 0x0340 + +#define REG_DBI 0x0348 +#define REG_MDIO 0x0354 +#define REG_DBG_SEL 0x0360 +#define REG_PCIE_HRPWM 0x0361 +#define REG_PCIE_HCPWM 0x0363 +#define REG_UART_CTRL 0x0364 +#define REG_WATCH_DOG 0x0368 +#define REG_UART_TX_DESA 0x0370 +#define REG_UART_RX_DESA 0x0378 + + +#define REG_HDAQ_DESA_NODEF 0x0000 +#define REG_CMDQ_DESA_NODEF 0x0000 + +#define REG_VOQ_INFORMATION 0x0400 +#define REG_VIQ_INFORMATION 0x0404 +#define REG_BEQ_INFORMATION 0x0408 +#define REG_BKQ_INFORMATION 0x040C +#define REG_MGQ_INFORMATION 0x0410 +#define REG_HGQ_INFORMATION 0x0414 +#define REG_BCNQ_INFORMATION 0x0418 +#define REG_TXPKT_EMPTY 0x041A + + +#define REG_CPU_MGQ_INFORMATION 0x041C +#define REG_FWHW_TXQ_CTRL 0x0420 +#define REG_HWSEQ_CTRL 0x0423 +#define REG_TXPKTBUF_BCNQ_BDNY 0x0424 +#define REG_TXPKTBUF_MGQ_BDNY 0x0425 +#define REG_MULTI_BCNQ_EN 0x0426 +#define REG_MULTI_BCNQ_OFFSET 0x0427 +#define REG_SPEC_SIFS 0x0428 +#define REG_RL 0x042A +#define REG_DARFRC 0x0430 +#define REG_RARFRC 0x0438 +#define REG_RRSR 0x0440 +#define REG_ARFR0 0x0444 +#define REG_ARFR1 0x0448 +#define REG_ARFR2 0x044C +#define REG_ARFR3 0x0450 +#define REG_AMPDU_MAX_TIME 0x0456 +#define REG_AGGLEN_LMT 0x0458 +#define REG_AMPDU_MIN_SPACE 0x045C +#define REG_TXPKTBUF_WMAC_LBK_BF_HD 0x045D +#define REG_FAST_EDCA_CTRL 0x0460 +#define REG_RD_RESP_PKT_TH 0x0463 +#define REG_INIRTS_RATE_SEL 0x0480 +#define REG_INIDATA_RATE_SEL 0x0484 +#define REG_POWER_STATUS 0x04A4 +#define REG_POWER_STAGE1 0x04B4 +#define REG_POWER_STAGE2 0x04B8 +#define REG_PKT_LIFE_TIME 0x04C0 +#define REG_STBC_SETTING 0x04C4 +#define REG_PROT_MODE_CTRL 0x04C8 +#define REG_BAR_MODE_CTRL 0x04CC +#define REG_RA_TRY_RATE_AGG_LMT 0x04CF +#define REG_EARLY_MODE_CONTROL 0x04D0 +#define REG_NQOS_SEQ 0x04DC +#define REG_QOS_SEQ 0x04DE +#define REG_NEED_CPU_HANDLE 0x04E0 +#define REG_PKT_LOSE_RPT 0x04E1 +#define REG_PTCL_ERR_STATUS 0x04E2 +#define REG_TX_RPT_CTRL 0x04EC +#define REG_TX_RPT_TIME 0x04F0 +#define REG_DUMMY 0x04FC + +#define REG_EDCA_VO_PARAM 0x0500 +#define REG_EDCA_VI_PARAM 0x0504 +#define REG_EDCA_BE_PARAM 0x0508 +#define REG_EDCA_BK_PARAM 0x050C +#define REG_BCNTCFG 0x0510 +#define REG_PIFS 0x0512 +#define REG_RDG_PIFS 0x0513 +#define REG_SIFS_CTX 0x0514 +#define REG_SIFS_TRX 0x0516 +#define REG_AGGR_BREAK_TIME 0x051A +#define REG_SLOT 0x051B +#define REG_TX_PTCL_CTRL 0x0520 +#define REG_TXPAUSE 0x0522 +#define REG_DIS_TXREQ_CLR 0x0523 +#define REG_RD_CTRL 0x0524 +#define REG_TBTT_PROHIBIT 0x0540 +#define REG_RD_NAV_NXT 0x0544 +#define REG_NAV_PROT_LEN 0x0546 +#define REG_BCN_CTRL 0x0550 +#define REG_USTIME_TSF 0x0551 +#define REG_MBID_NUM 0x0552 +#define REG_DUAL_TSF_RST 0x0553 +#define REG_BCN_INTERVAL 0x0554 +#define REG_MBSSID_BCN_SPACE 0x0554 +#define REG_DRVERLYINT 0x0558 +#define REG_BCNDMATIM 0x0559 +#define REG_ATIMWND 0x055A +#define REG_BCN_MAX_ERR 0x055D +#define REG_RXTSF_OFFSET_CCK 0x055E +#define REG_RXTSF_OFFSET_OFDM 0x055F +#define REG_TSFTR 0x0560 +#define REG_INIT_TSFTR 0x0564 +#define REG_SECONDARY_CCA_CTRL 0x0577 +#define REG_PSTIMER 0x0580 +#define REG_TIMER0 0x0584 +#define REG_TIMER1 0x0588 +#define REG_ACMHWCTRL 0x05C0 +#define REG_ACMRSTCTRL 0x05C1 +#define REG_ACMAVG 0x05C2 +#define REG_VO_ADMTIME 0x05C4 +#define REG_VI_ADMTIME 0x05C6 +#define REG_BE_ADMTIME 0x05C8 +#define REG_EDCA_RANDOM_GEN 0x05CC +#define REG_SCH_TXCMD 0x05D0 + +#define REG_APSD_CTRL 0x0600 +#define REG_BWOPMODE 0x0603 +#define REG_TCR 0x0604 +#define REG_RCR 0x0608 +#define REG_RX_PKT_LIMIT 0x060C +#define REG_RX_DLK_TIME 0x060D +#define REG_RX_DRVINFO_SZ 0x060F + +#define REG_MACID 0x0610 +#define REG_BSSID 0x0618 +#define REG_MAR 0x0620 +#define REG_MBIDCAMCFG 0x0628 + +#define REG_USTIME_EDCA 0x0638 +#define REG_MAC_SPEC_SIFS 0x063A +#define REG_RESP_SIFS_CCK 0x063C +#define REG_RESP_SIFS_OFDM 0x063E +#define REG_ACKTO 0x0640 +#define REG_CTS2TO 0x0641 +#define REG_EIFS 0x0642 + +#define REG_NAV_CTRL 0x0650 +#define REG_BACAMCMD 0x0654 +#define REG_BACAMCONTENT 0x0658 +#define REG_LBDLY 0x0660 +#define REG_FWDLY 0x0661 +#define REG_RXERR_RPT 0x0664 +#define REG_TRXPTCL_CTL 0x0668 + +#define REG_CAMCMD 0x0670 +#define REG_CAMWRITE 0x0674 +#define REG_CAMREAD 0x0678 +#define REG_CAMDBG 0x067C +#define REG_SECCFG 0x0680 + +#define REG_WOW_CTRL 0x0690 +#define REG_PSSTATUS 0x0691 +#define REG_PS_RX_INFO 0x0692 +#define REG_UAPSD_TID 0x0693 +#define REG_LPNAV_CTRL 0x0694 +#define REG_WKFMCAM_NUM 0x0698 +#define REG_WKFMCAM_RWD 0x069C +#define REG_RXFLTMAP0 0x06A0 +#define REG_RXFLTMAP1 0x06A2 +#define REG_RXFLTMAP2 0x06A4 +#define REG_BCN_PSR_RPT 0x06A8 +#define REG_CALB32K_CTRL 0x06AC +#define REG_PKT_MON_CTRL 0x06B4 +#define REG_BT_COEX_TABLE 0x06C0 +#define REG_WMAC_RESP_TXINFO 0x06D8 + +#define REG_USB_INFO 0xFE17 +#define REG_USB_SPECIAL_OPTION 0xFE55 +#define REG_USB_DMA_AGG_TO 0xFE5B +#define REG_USB_AGG_TO 0xFE5C +#define REG_USB_AGG_TH 0xFE5D + +#define REG_TEST_USB_TXQS 0xFE48 +#define REG_TEST_SIE_VID 0xFE60 +#define REG_TEST_SIE_PID 0xFE62 +#define REG_TEST_SIE_OPTIONAL 0xFE64 +#define REG_TEST_SIE_CHIRP_K 0xFE65 +#define REG_TEST_SIE_PHY 0xFE66 +#define REG_TEST_SIE_MAC_ADDR 0xFE70 +#define REG_TEST_SIE_STRING 0xFE80 + +#define REG_NORMAL_SIE_VID 0xFE60 +#define REG_NORMAL_SIE_PID 0xFE62 +#define REG_NORMAL_SIE_OPTIONAL 0xFE64 +#define REG_NORMAL_SIE_EP 0xFE65 +#define REG_NORMAL_SIE_PHY 0xFE68 +#define REG_NORMAL_SIE_MAC_ADDR 0xFE70 +#define REG_NORMAL_SIE_STRING 0xFE80 + +#define CR9346 REG_9346CR +#define MSR (REG_CR + 2) +#define ISR REG_HISR +#define TSFR REG_TSFTR + +#define MACIDR0 REG_MACID +#define MACIDR4 (REG_MACID + 4) + +#define PBP REG_PBP + +#define IDR0 MACIDR0 +#define IDR4 MACIDR4 + +#define UNUSED_REGISTER 0x1BF +#define DCAM UNUSED_REGISTER +#define PSR UNUSED_REGISTER +#define BBADDR UNUSED_REGISTER +#define PHYDATAR UNUSED_REGISTER + +#define INVALID_BBRF_VALUE 0x12345678 + +#define MAX_MSS_DENSITY_2T 0x13 +#define MAX_MSS_DENSITY_1T 0x0A + +#define CMDEEPROM_EN BIT(5) +#define CMDEEPROM_SEL BIT(4) +#define CMD9346CR_9356SEL BIT(4) +#define AUTOLOAD_EEPROM (CMDEEPROM_EN | CMDEEPROM_SEL) +#define AUTOLOAD_EFUSE CMDEEPROM_EN + +#define GPIOSEL_GPIO 0 +#define GPIOSEL_ENBT BIT(5) + +#define GPIO_IN REG_GPIO_PIN_CTRL +#define GPIO_OUT (REG_GPIO_PIN_CTRL + 1) +#define GPIO_IO_SEL (REG_GPIO_PIN_CTRL + 2) +#define GPIO_MOD (REG_GPIO_PIN_CTRL + 3) + +/* 8723/8188E Host System Interrupt Mask Register (offset 0x58, 32 byte) */ +#define HSIMR_GPIO12_0_INT_EN BIT(0) +#define HSIMR_SPS_OCP_INT_EN BIT(5) +#define HSIMR_RON_INT_EN BIT(6) +#define HSIMR_PDN_INT_EN BIT(7) +#define HSIMR_GPIO9_INT_EN BIT(25) + +/* 8723/8188E Host System Interrupt Status Register (offset 0x5C, 32 byte) */ + +#define HSISR_GPIO12_0_INT BIT(0) +#define HSISR_SPS_OCP_INT BIT(5) +#define HSISR_RON_INT_EN BIT(6) +#define HSISR_PDNINT BIT(7) +#define HSISR_GPIO9_INT BIT(25) + +#define MSR_NOLINK 0x00 +#define MSR_ADHOC 0x01 +#define MSR_INFRA 0x02 +#define MSR_AP 0x03 + +#define RRSR_RSC_OFFSET 21 +#define RRSR_SHORT_OFFSET 23 +#define RRSR_RSC_BW_40M 0x600000 +#define RRSR_RSC_UPSUBCHNL 0x400000 +#define RRSR_RSC_LOWSUBCHNL 0x200000 +#define RRSR_SHORT 0x800000 +#define RRSR_1M BIT(0) +#define RRSR_2M BIT(1) +#define RRSR_5_5M BIT(2) +#define RRSR_11M BIT(3) +#define RRSR_6M BIT(4) +#define RRSR_9M BIT(5) +#define RRSR_12M BIT(6) +#define RRSR_18M BIT(7) +#define RRSR_24M BIT(8) +#define RRSR_36M BIT(9) +#define RRSR_48M BIT(10) +#define RRSR_54M BIT(11) +#define RRSR_MCS0 BIT(12) +#define RRSR_MCS1 BIT(13) +#define RRSR_MCS2 BIT(14) +#define RRSR_MCS3 BIT(15) +#define RRSR_MCS4 BIT(16) +#define RRSR_MCS5 BIT(17) +#define RRSR_MCS6 BIT(18) +#define RRSR_MCS7 BIT(19) +#define BRSR_ACKSHORTPMB BIT(23) + +#define RATR_1M 0x00000001 +#define RATR_2M 0x00000002 +#define RATR_55M 0x00000004 +#define RATR_11M 0x00000008 +#define RATR_6M 0x00000010 +#define RATR_9M 0x00000020 +#define RATR_12M 0x00000040 +#define RATR_18M 0x00000080 +#define RATR_24M 0x00000100 +#define RATR_36M 0x00000200 +#define RATR_48M 0x00000400 +#define RATR_54M 0x00000800 +#define RATR_MCS0 0x00001000 +#define RATR_MCS1 0x00002000 +#define RATR_MCS2 0x00004000 +#define RATR_MCS3 0x00008000 +#define RATR_MCS4 0x00010000 +#define RATR_MCS5 0x00020000 +#define RATR_MCS6 0x00040000 +#define RATR_MCS7 0x00080000 +#define RATR_MCS8 0x00100000 +#define RATR_MCS9 0x00200000 +#define RATR_MCS10 0x00400000 +#define RATR_MCS11 0x00800000 +#define RATR_MCS12 0x01000000 +#define RATR_MCS13 0x02000000 +#define RATR_MCS14 0x04000000 +#define RATR_MCS15 0x08000000 + +#define RATE_1M BIT(0) +#define RATE_2M BIT(1) +#define RATE_5_5M BIT(2) +#define RATE_11M BIT(3) +#define RATE_6M BIT(4) +#define RATE_9M BIT(5) +#define RATE_12M BIT(6) +#define RATE_18M BIT(7) +#define RATE_24M BIT(8) +#define RATE_36M BIT(9) +#define RATE_48M BIT(10) +#define RATE_54M BIT(11) +#define RATE_MCS0 BIT(12) +#define RATE_MCS1 BIT(13) +#define RATE_MCS2 BIT(14) +#define RATE_MCS3 BIT(15) +#define RATE_MCS4 BIT(16) +#define RATE_MCS5 BIT(17) +#define RATE_MCS6 BIT(18) +#define RATE_MCS7 BIT(19) +#define RATE_MCS8 BIT(20) +#define RATE_MCS9 BIT(21) +#define RATE_MCS10 BIT(22) +#define RATE_MCS11 BIT(23) +#define RATE_MCS12 BIT(24) +#define RATE_MCS13 BIT(25) +#define RATE_MCS14 BIT(26) +#define RATE_MCS15 BIT(27) + +#define RATE_ALL_CCK (RATR_1M | RATR_2M | RATR_55M | RATR_11M) +#define RATE_ALL_OFDM_AG (RATR_6M | RATR_9M | RATR_12M | RATR_18M |\ + RATR_24M | RATR_36M | RATR_48M | RATR_54M) +#define RATE_ALL_OFDM_1SS (RATR_MCS0 | RATR_MCS1 | RATR_MCS2 |\ + RATR_MCS3 | RATR_MCS4 | RATR_MCS5 |\ + RATR_MCS6 | RATR_MCS7) +#define RATE_ALL_OFDM_2SS (RATR_MCS8 | RATR_MCS9 | RATR_MCS10 |\ + RATR_MCS11 | RATR_MCS12 | RATR_MCS13 |\ + RATR_MCS14 | RATR_MCS15) + +#define BW_OPMODE_20MHZ BIT(2) +#define BW_OPMODE_5G BIT(1) +#define BW_OPMODE_11J BIT(0) + +#define CAM_VALID BIT(15) +#define CAM_NOTVALID 0x0000 +#define CAM_USEDK BIT(5) + +#define CAM_NONE 0x0 +#define CAM_WEP40 0x01 +#define CAM_TKIP 0x02 +#define CAM_AES 0x04 +#define CAM_WEP104 0x05 + +#define TOTAL_CAM_ENTRY 32 +#define HALF_CAM_ENTRY 16 + +#define CAM_WRITE BIT(16) +#define CAM_READ 0x00000000 +#define CAM_POLLINIG BIT(31) + +#define SCR_USEDK 0x01 +#define SCR_TXSEC_ENABLE 0x02 +#define SCR_RXSEC_ENABLE 0x04 + +#define WOW_PMEN BIT(0) +#define WOW_WOMEN BIT(1) +#define WOW_MAGIC BIT(2) +#define WOW_UWF BIT(3) + +/********************************************* +* 8723BE IMR/ISR bits +**********************************************/ +#define IMR_DISABLED 0x0 +/* IMR DW0(0x0060-0063) Bit 0-31 */ +#define IMR_TXCCK BIT(30) /* TXRPT interrupt when + * CCX bit of the packet is set + */ +#define IMR_PSTIMEOUT BIT(29) /* Power Save Time Out Interrupt */ +#define IMR_GTINT4 BIT(28) /* When GTIMER4 expires, + * this bit is set to 1 + */ +#define IMR_GTINT3 BIT(27) /* When GTIMER3 expires, + * this bit is set to 1 + */ +#define IMR_TBDER BIT(26) /* Transmit Beacon0 Error */ +#define IMR_TBDOK BIT(25) /* Transmit Beacon0 OK */ +#define IMR_TSF_BIT32_TOGGLE BIT(24) /* TSF Timer BIT32 toggle + * indication interrupt + */ +#define IMR_BCNDMAINT0 BIT(20) /* Beacon DMA Interrupt 0 */ +#define IMR_BCNDOK0 BIT(16) /* Beacon Queue DMA OK0 */ +#define IMR_HSISR_IND_ON_INT BIT(15) /* HSISR Indicator (HSIMR & HSISR is + * true, this bit is set to 1) + */ +#define IMR_BCNDMAINT_E BIT(14) /* Beacon DMA Interrupt + * Extension for Win7 + */ +#define IMR_ATIMEND BIT(12) /* CTWidnow End or ATIM Window End */ +#define IMR_HISR1_IND_INT BIT(11) /* HISR1 Indicator (HISR1 & HIMR1 is + * true, this bit is set to 1) + */ +#define IMR_C2HCMD BIT(10) /* CPU to Host Command INT Status, + * Write 1 clear + */ +#define IMR_CPWM2 BIT(9) /* CPU power Mode exchange INT Status, + * Write 1 clear + */ +#define IMR_CPWM BIT(8) /* CPU power Mode exchange INT Status, + * Write 1 clear + */ +#define IMR_HIGHDOK BIT(7) /* High Queue DMA OK */ +#define IMR_MGNTDOK BIT(6) /* Management Queue DMA OK */ +#define IMR_BKDOK BIT(5) /* AC_BK DMA OK */ +#define IMR_BEDOK BIT(4) /* AC_BE DMA OK */ +#define IMR_VIDOK BIT(3) /* AC_VI DMA OK */ +#define IMR_VODOK BIT(2) /* AC_VO DMA OK */ +#define IMR_RDU BIT(1) /* Rx Descriptor Unavailable */ +#define IMR_ROK BIT(0) /* Receive DMA OK */ + +/* IMR DW1(0x00B4-00B7) Bit 0-31 */ +#define IMR_BCNDMAINT7 BIT(27) /* Beacon DMA Interrupt 7 */ +#define IMR_BCNDMAINT6 BIT(26) /* Beacon DMA Interrupt 6 */ +#define IMR_BCNDMAINT5 BIT(25) /* Beacon DMA Interrupt 5 */ +#define IMR_BCNDMAINT4 BIT(24) /* Beacon DMA Interrupt 4 */ +#define IMR_BCNDMAINT3 BIT(23) /* Beacon DMA Interrupt 3 */ +#define IMR_BCNDMAINT2 BIT(22) /* Beacon DMA Interrupt 2 */ +#define IMR_BCNDMAINT1 BIT(21) /* Beacon DMA Interrupt 1 */ +#define IMR_BCNDOK7 BIT(20) /* Beacon Queue DMA OK Interrup 7 */ +#define IMR_BCNDOK6 BIT(19) /* Beacon Queue DMA OK Interrup 6 */ +#define IMR_BCNDOK5 BIT(18) /* Beacon Queue DMA OK Interrup 5 */ +#define IMR_BCNDOK4 BIT(17) /* Beacon Queue DMA OK Interrup 4 */ +#define IMR_BCNDOK3 BIT(16) /* Beacon Queue DMA OK Interrup 3 */ +#define IMR_BCNDOK2 BIT(15) /* Beacon Queue DMA OK Interrup 2 */ +#define IMR_BCNDOK1 BIT(14) /* Beacon Queue DMA OK Interrup 1 */ +#define IMR_ATIMEND_E BIT(13) /* ATIM Window End Extension for Win7 */ +#define IMR_TXERR BIT(11) /* Tx Error Flag Interrupt Status, + * write 1 clear. + */ +#define IMR_RXERR BIT(10) /* Rx Error Flag INT Status, + * Write 1 clear + */ +#define IMR_TXFOVW BIT(9) /* Transmit FIFO Overflow */ +#define IMR_RXFOVW BIT(8) /* Receive FIFO Overflow */ + +#define HWSET_MAX_SIZE 512 +#define EFUSE_MAX_SECTION 64 +#define EFUSE_REAL_CONTENT_LEN 256 +#define EFUSE_OOB_PROTECT_BYTES 18 /* PG data exclude header, + * dummy 7 bytes frome CP test + * and reserved 1byte. + */ + +#define EEPROM_DEFAULT_TSSI 0x0 +#define EEPROM_DEFAULT_TXPOWERDIFF 0x0 +#define EEPROM_DEFAULT_CRYSTALCAP 0x5 +#define EEPROM_DEFAULT_BOARDTYPE 0x02 +#define EEPROM_DEFAULT_TXPOWER 0x1010 +#define EEPROM_DEFAULT_HT2T_TXPWR 0x10 + +#define EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF 0x3 +#define EEPROM_DEFAULT_THERMALMETER 0x18 +#define EEPROM_DEFAULT_ANTTXPOWERDIFF 0x0 +#define EEPROM_DEFAULT_TXPWDIFF_CRYSTALCAP 0x5 +#define EEPROM_DEFAULT_TXPOWERLEVEL 0x22 +#define EEPROM_DEFAULT_HT40_2SDIFF 0x0 +#define EEPROM_DEFAULT_HT20_DIFF 2 +#define EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF 0x3 +#define EEPROM_DEFAULT_HT40_PWRMAXOFFSET 0 +#define EEPROM_DEFAULT_HT20_PWRMAXOFFSET 0 + +#define RF_OPTION1 0x79 +#define RF_OPTION2 0x7A +#define RF_OPTION3 0x7B +#define RF_OPTION4 0xC3 + +#define EEPROM_DEFAULT_PID 0x1234 +#define EEPROM_DEFAULT_VID 0x5678 +#define EEPROM_DEFAULT_CUSTOMERID 0xAB +#define EEPROM_DEFAULT_SUBCUSTOMERID 0xCD +#define EEPROM_DEFAULT_VERSION 0 + +#define EEPROM_CHANNEL_PLAN_FCC 0x0 +#define EEPROM_CHANNEL_PLAN_IC 0x1 +#define EEPROM_CHANNEL_PLAN_ETSI 0x2 +#define EEPROM_CHANNEL_PLAN_SPAIN 0x3 +#define EEPROM_CHANNEL_PLAN_FRANCE 0x4 +#define EEPROM_CHANNEL_PLAN_MKK 0x5 +#define EEPROM_CHANNEL_PLAN_MKK1 0x6 +#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7 +#define EEPROM_CHANNEL_PLAN_TELEC 0x8 +#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9 +#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA +#define EEPROM_CHANNEL_PLAN_NCC 0xB +#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 + +#define EEPROM_CID_DEFAULT 0x0 +#define EEPROM_CID_TOSHIBA 0x4 +#define EEPROM_CID_CCX 0x10 +#define EEPROM_CID_QMI 0x0D +#define EEPROM_CID_WHQL 0xFE + +#define RTL8723BE_EEPROM_ID 0x8129 + +#define EEPROM_HPON 0x02 +#define EEPROM_CLK 0x06 +#define EEPROM_TESTR 0x08 + + +#define EEPROM_TXPOWERCCK 0x10 +#define EEPROM_TXPOWERHT40_1S 0x16 +#define EEPROM_TXPOWERHT20DIFF 0x1B +#define EEPROM_TXPOWER_OFDMDIFF 0x1B + + + +#define EEPROM_TX_PWR_INX 0x10 + +#define EEPROM_CHANNELPLAN 0xB8 +#define EEPROM_XTAL_8723BE 0xB9 +#define EEPROM_THERMAL_METER_88E 0xBA +#define EEPROM_IQK_LCK_88E 0xBB + +#define EEPROM_RF_BOARD_OPTION_88E 0xC1 +#define EEPROM_RF_FEATURE_OPTION_88E 0xC2 +#define EEPROM_RF_BT_SETTING_88E 0xC3 +#define EEPROM_VERSION 0xC4 +#define EEPROM_CUSTOMER_ID 0xC5 +#define EEPROM_RF_ANTENNA_OPT_88E 0xC9 + +#define EEPROM_MAC_ADDR 0xD0 +#define EEPROM_VID 0xD6 +#define EEPROM_DID 0xD8 +#define EEPROM_SVID 0xDA +#define EEPROM_SMID 0xDC + +#define STOPBECON BIT(6) +#define STOPHIGHT BIT(5) +#define STOPMGT BIT(4) +#define STOPVO BIT(3) +#define STOPVI BIT(2) +#define STOPBE BIT(1) +#define STOPBK BIT(0) + +#define RCR_APPFCS BIT(31) +#define RCR_APP_MIC BIT(30) +#define RCR_APP_ICV BIT(29) +#define RCR_APP_PHYST_RXFF BIT(28) +#define RCR_APP_BA_SSN BIT(27) +#define RCR_ENMBID BIT(24) +#define RCR_LSIGEN BIT(23) +#define RCR_MFBEN BIT(22) +#define RCR_HTC_LOC_CTRL BIT(14) +#define RCR_AMF BIT(13) +#define RCR_ACF BIT(12) +#define RCR_ADF BIT(11) +#define RCR_AICV BIT(9) +#define RCR_ACRC32 BIT(8) +#define RCR_CBSSID_BCN BIT(7) +#define RCR_CBSSID_DATA BIT(6) +#define RCR_CBSSID RCR_CBSSID_DATA +#define RCR_APWRMGT BIT(5) +#define RCR_ADD3 BIT(4) +#define RCR_AB BIT(3) +#define RCR_AM BIT(2) +#define RCR_APM BIT(1) +#define RCR_AAP BIT(0) +#define RCR_MXDMA_OFFSET 8 +#define RCR_FIFO_OFFSET 13 + +#define RSV_CTRL 0x001C +#define RD_CTRL 0x0524 + +#define REG_USB_INFO 0xFE17 +#define REG_USB_SPECIAL_OPTION 0xFE55 +#define REG_USB_DMA_AGG_TO 0xFE5B +#define REG_USB_AGG_TO 0xFE5C +#define REG_USB_AGG_TH 0xFE5D + +#define REG_USB_VID 0xFE60 +#define REG_USB_PID 0xFE62 +#define REG_USB_OPTIONAL 0xFE64 +#define REG_USB_CHIRP_K 0xFE65 +#define REG_USB_PHY 0xFE66 +#define REG_USB_MAC_ADDR 0xFE70 +#define REG_USB_HRPWM 0xFE58 +#define REG_USB_HCPWM 0xFE57 + +#define SW18_FPWM BIT(3) + +#define ISO_MD2PP BIT(0) +#define ISO_UA2USB BIT(1) +#define ISO_UD2CORE BIT(2) +#define ISO_PA2PCIE BIT(3) +#define ISO_PD2CORE BIT(4) +#define ISO_IP2MAC BIT(5) +#define ISO_DIOP BIT(6) +#define ISO_DIOE BIT(7) +#define ISO_EB2CORE BIT(8) +#define ISO_DIOR BIT(9) + +#define PWC_EV25V BIT(14) +#define PWC_EV12V BIT(15) + +#define FEN_BBRSTB BIT(0) +#define FEN_BB_GLB_RSTN BIT(1) +#define FEN_USBA BIT(2) +#define FEN_UPLL BIT(3) +#define FEN_USBD BIT(4) +#define FEN_DIO_PCIE BIT(5) +#define FEN_PCIEA BIT(6) +#define FEN_PPLL BIT(7) +#define FEN_PCIED BIT(8) +#define FEN_DIOE BIT(9) +#define FEN_CPUEN BIT(10) +#define FEN_DCORE BIT(11) +#define FEN_ELDR BIT(12) +#define FEN_DIO_RF BIT(13) +#define FEN_HWPDN BIT(14) +#define FEN_MREGEN BIT(15) + +#define PFM_LDALL BIT(0) +#define PFM_ALDN BIT(1) +#define PFM_LDKP BIT(2) +#define PFM_WOWL BIT(3) +#define ENPDN BIT(4) +#define PDN_PL BIT(5) +#define APFM_ONMAC BIT(8) +#define APFM_OFF BIT(9) +#define APFM_RSM BIT(10) +#define AFSM_HSUS BIT(11) +#define AFSM_PCIE BIT(12) +#define APDM_MAC BIT(13) +#define APDM_HOST BIT(14) +#define APDM_HPDN BIT(15) +#define RDY_MACON BIT(16) +#define SUS_HOST BIT(17) +#define ROP_ALD BIT(20) +#define ROP_PWR BIT(21) +#define ROP_SPS BIT(22) +#define SOP_MRST BIT(25) +#define SOP_FUSE BIT(26) +#define SOP_ABG BIT(27) +#define SOP_AMB BIT(28) +#define SOP_RCK BIT(29) +#define SOP_A8M BIT(30) +#define XOP_BTCK BIT(31) + +#define ANAD16V_EN BIT(0) +#define ANA8M BIT(1) +#define MACSLP BIT(4) +#define LOADER_CLK_EN BIT(5) +#define _80M_SSC_DIS BIT(7) +#define _80M_SSC_EN_HO BIT(8) +#define PHY_SSC_RSTB BIT(9) +#define SEC_CLK_EN BIT(10) +#define MAC_CLK_EN BIT(11) +#define SYS_CLK_EN BIT(12) +#define RING_CLK_EN BIT(13) + +#define BOOT_FROM_EEPROM BIT(4) +#define EEPROM_EN BIT(5) + +#define AFE_BGEN BIT(0) +#define AFE_MBEN BIT(1) +#define MAC_ID_EN BIT(7) + +#define WLOCK_ALL BIT(0) +#define WLOCK_00 BIT(1) +#define WLOCK_04 BIT(2) +#define WLOCK_08 BIT(3) +#define WLOCK_40 BIT(4) +#define R_DIS_PRST_0 BIT(5) +#define R_DIS_PRST_1 BIT(6) +#define LOCK_ALL_EN BIT(7) + +#define RF_EN BIT(0) +#define RF_RSTB BIT(1) +#define RF_SDMRSTB BIT(2) + +#define LDA15_EN BIT(0) +#define LDA15_STBY BIT(1) +#define LDA15_OBUF BIT(2) +#define LDA15_REG_VOS BIT(3) +#define _LDA15_VOADJ(x) (((x) & 0x7) << 4) + +#define LDV12_EN BIT(0) +#define LDV12_SDBY BIT(1) +#define LPLDO_HSM BIT(2) +#define LPLDO_LSM_DIS BIT(3) +#define _LDV12_VADJ(x) (((x) & 0xF) << 4) + +#define XTAL_EN BIT(0) +#define XTAL_BSEL BIT(1) +#define _XTAL_BOSC(x) (((x) & 0x3) << 2) +#define _XTAL_CADJ(x) (((x) & 0xF) << 4) +#define XTAL_GATE_USB BIT(8) +#define _XTAL_USB_DRV(x) (((x) & 0x3) << 9) +#define XTAL_GATE_AFE BIT(11) +#define _XTAL_AFE_DRV(x) (((x) & 0x3) << 12) +#define XTAL_RF_GATE BIT(14) +#define _XTAL_RF_DRV(x) (((x) & 0x3) << 15) +#define XTAL_GATE_DIG BIT(17) +#define _XTAL_DIG_DRV(x) (((x) & 0x3) << 18) +#define XTAL_BT_GATE BIT(20) +#define _XTAL_BT_DRV(x) (((x) & 0x3) << 21) +#define _XTAL_GPIO(x) (((x) & 0x7) << 23) + +#define CKDLY_AFE BIT(26) +#define CKDLY_USB BIT(27) +#define CKDLY_DIG BIT(28) +#define CKDLY_BT BIT(29) + +#define APLL_EN BIT(0) +#define APLL_320_EN BIT(1) +#define APLL_FREF_SEL BIT(2) +#define APLL_EDGE_SEL BIT(3) +#define APLL_WDOGB BIT(4) +#define APLL_LPFEN BIT(5) + +#define APLL_REF_CLK_13MHZ 0x1 +#define APLL_REF_CLK_19_2MHZ 0x2 +#define APLL_REF_CLK_20MHZ 0x3 +#define APLL_REF_CLK_25MHZ 0x4 +#define APLL_REF_CLK_26MHZ 0x5 +#define APLL_REF_CLK_38_4MHZ 0x6 +#define APLL_REF_CLK_40MHZ 0x7 + +#define APLL_320EN BIT(14) +#define APLL_80EN BIT(15) +#define APLL_1MEN BIT(24) + +#define ALD_EN BIT(18) +#define EF_PD BIT(19) +#define EF_FLAG BIT(31) + +#define EF_TRPT BIT(7) +#define LDOE25_EN BIT(31) + +#define RSM_EN BIT(0) +#define TIMER_EN BIT(4) + +#define TRSW0EN BIT(2) +#define TRSW1EN BIT(3) +#define EROM_EN BIT(4) +#define ENBT BIT(5) +#define ENUART BIT(8) +#define UART_910 BIT(9) +#define ENPMAC BIT(10) +#define SIC_SWRST BIT(11) +#define ENSIC BIT(12) +#define SIC_23 BIT(13) +#define ENHDP BIT(14) +#define SIC_LBK BIT(15) + +#define LED0PL BIT(4) +#define LED1PL BIT(12) +#define LED0DIS BIT(7) + +#define MCUFWDL_EN BIT(0) +#define MCUFWDL_RDY BIT(1) +#define FWDL_CHKSUM_RPT BIT(2) +#define MACINI_RDY BIT(3) +#define BBINI_RDY BIT(4) +#define RFINI_RDY BIT(5) +#define WINTINI_RDY BIT(6) +#define CPRST BIT(23) + +#define XCLK_VLD BIT(0) +#define ACLK_VLD BIT(1) +#define UCLK_VLD BIT(2) +#define PCLK_VLD BIT(3) +#define PCIRSTB BIT(4) +#define V15_VLD BIT(5) +#define TRP_B15V_EN BIT(7) +#define SIC_IDLE BIT(8) +#define BD_MAC2 BIT(9) +#define BD_MAC1 BIT(10) +#define IC_MACPHY_MODE BIT(11) +#define VENDOR_ID BIT(19) +#define PAD_HWPD_IDN BIT(22) +#define TRP_VAUX_EN BIT(23) +#define TRP_BT_EN BIT(24) +#define BD_PKG_SEL BIT(25) +#define BD_HCI_SEL BIT(26) +#define TYPE_ID BIT(27) + +#define CHIP_VER_RTL_MASK 0xF000 +#define CHIP_VER_RTL_SHIFT 12 + +#define REG_LBMODE (REG_CR + 3) + +#define HCI_TXDMA_EN BIT(0) +#define HCI_RXDMA_EN BIT(1) +#define TXDMA_EN BIT(2) +#define RXDMA_EN BIT(3) +#define PROTOCOL_EN BIT(4) +#define SCHEDULE_EN BIT(5) +#define MACTXEN BIT(6) +#define MACRXEN BIT(7) +#define ENSWBCN BIT(8) +#define ENSEC BIT(9) + +#define _NETTYPE(x) (((x) & 0x3) << 16) +#define MASK_NETTYPE 0x30000 +#define NT_NO_LINK 0x0 +#define NT_LINK_AD_HOC 0x1 +#define NT_LINK_AP 0x2 +#define NT_AS_AP 0x3 + +#define _LBMODE(x) (((x) & 0xF) << 24) +#define MASK_LBMODE 0xF000000 +#define LOOPBACK_NORMAL 0x0 +#define LOOPBACK_IMMEDIATELY 0xB +#define LOOPBACK_MAC_DELAY 0x3 +#define LOOPBACK_PHY 0x1 +#define LOOPBACK_DMA 0x7 + +#define GET_RX_PAGE_SIZE(value) ((value) & 0xF) +#define GET_TX_PAGE_SIZE(value) (((value) & 0xF0) >> 4) +#define _PSRX_MASK 0xF +#define _PSTX_MASK 0xF0 +#define _PSRX(x) (x) +#define _PSTX(x) ((x) << 4) + +#define PBP_64 0x0 +#define PBP_128 0x1 +#define PBP_256 0x2 +#define PBP_512 0x3 +#define PBP_1024 0x4 + +#define RXDMA_ARBBW_EN BIT(0) +#define RXSHFT_EN BIT(1) +#define RXDMA_AGG_EN BIT(2) +#define QS_VO_QUEUE BIT(8) +#define QS_VI_QUEUE BIT(9) +#define QS_BE_QUEUE BIT(10) +#define QS_BK_QUEUE BIT(11) +#define QS_MANAGER_QUEUE BIT(12) +#define QS_HIGH_QUEUE BIT(13) + +#define HQSEL_VOQ BIT(0) +#define HQSEL_VIQ BIT(1) +#define HQSEL_BEQ BIT(2) +#define HQSEL_BKQ BIT(3) +#define HQSEL_MGTQ BIT(4) +#define HQSEL_HIQ BIT(5) + +#define _TXDMA_HIQ_MAP(x) (((x)&0x3) << 14) +#define _TXDMA_MGQ_MAP(x) (((x)&0x3) << 12) +#define _TXDMA_BKQ_MAP(x) (((x)&0x3) << 10) +#define _TXDMA_BEQ_MAP(x) (((x)&0x3) << 8) +#define _TXDMA_VIQ_MAP(x) (((x)&0x3) << 6) +#define _TXDMA_VOQ_MAP(x) (((x)&0x3) << 4) + +#define QUEUE_LOW 1 +#define QUEUE_NORMAL 2 +#define QUEUE_HIGH 3 + +#define _LLT_NO_ACTIVE 0x0 +#define _LLT_WRITE_ACCESS 0x1 +#define _LLT_READ_ACCESS 0x2 + +#define _LLT_INIT_DATA(x) ((x) & 0xFF) +#define _LLT_INIT_ADDR(x) (((x) & 0xFF) << 8) +#define _LLT_OP(x) (((x) & 0x3) << 30) +#define _LLT_OP_VALUE(x) (((x) >> 30) & 0x3) + +#define BB_WRITE_READ_MASK (BIT(31) | BIT(30)) +#define BB_WRITE_EN BIT(30) +#define BB_READ_EN BIT(31) + +#define _HPQ(x) ((x) & 0xFF) +#define _LPQ(x) (((x) & 0xFF) << 8) +#define _PUBQ(x) (((x) & 0xFF) << 16) +#define _NPQ(x) ((x) & 0xFF) + +#define HPQ_PUBLIC_DIS BIT(24) +#define LPQ_PUBLIC_DIS BIT(25) +#define LD_RQPN BIT(31) + +#define BCN_VALID BIT(16) +#define BCN_HEAD(x) (((x) & 0xFF) << 8) +#define BCN_HEAD_MASK 0xFF00 + +#define BLK_DESC_NUM_SHIFT 4 +#define BLK_DESC_NUM_MASK 0xF + +#define DROP_DATA_EN BIT(9) + +#define EN_AMPDU_RTY_NEW BIT(7) + +#define _INIRTSMCS_SEL(x) ((x) & 0x3F) + +#define _SPEC_SIFS_CCK(x) ((x) & 0xFF) +#define _SPEC_SIFS_OFDM(x) (((x) & 0xFF) << 8) + +#define RATE_REG_BITMAP_ALL 0xFFFFF + +#define _RRSC_BITMAP(x) ((x) & 0xFFFFF) + +#define _RRSR_RSC(x) (((x) & 0x3) << 21) +#define RRSR_RSC_RESERVED 0x0 +#define RRSR_RSC_UPPER_SUBCHANNEL 0x1 +#define RRSR_RSC_LOWER_SUBCHANNEL 0x2 +#define RRSR_RSC_DUPLICATE_MODE 0x3 + +#define USE_SHORT_G1 BIT(20) + +#define _AGGLMT_MCS0(x) ((x) & 0xF) +#define _AGGLMT_MCS1(x) (((x) & 0xF) << 4) +#define _AGGLMT_MCS2(x) (((x) & 0xF) << 8) +#define _AGGLMT_MCS3(x) (((x) & 0xF) << 12) +#define _AGGLMT_MCS4(x) (((x) & 0xF) << 16) +#define _AGGLMT_MCS5(x) (((x) & 0xF) << 20) +#define _AGGLMT_MCS6(x) (((x) & 0xF) << 24) +#define _AGGLMT_MCS7(x) (((x) & 0xF) << 28) + +#define RETRY_LIMIT_SHORT_SHIFT 8 +#define RETRY_LIMIT_LONG_SHIFT 0 + +#define _DARF_RC1(x) ((x) & 0x1F) +#define _DARF_RC2(x) (((x) & 0x1F) << 8) +#define _DARF_RC3(x) (((x) & 0x1F) << 16) +#define _DARF_RC4(x) (((x) & 0x1F) << 24) +#define _DARF_RC5(x) ((x) & 0x1F) +#define _DARF_RC6(x) (((x) & 0x1F) << 8) +#define _DARF_RC7(x) (((x) & 0x1F) << 16) +#define _DARF_RC8(x) (((x) & 0x1F) << 24) + +#define _RARF_RC1(x) ((x) & 0x1F) +#define _RARF_RC2(x) (((x) & 0x1F) << 8) +#define _RARF_RC3(x) (((x) & 0x1F) << 16) +#define _RARF_RC4(x) (((x) & 0x1F) << 24) +#define _RARF_RC5(x) ((x) & 0x1F) +#define _RARF_RC6(x) (((x) & 0x1F) << 8) +#define _RARF_RC7(x) (((x) & 0x1F) << 16) +#define _RARF_RC8(x) (((x) & 0x1F) << 24) + +#define AC_PARAM_TXOP_LIMIT_OFFSET 16 +#define AC_PARAM_ECW_MAX_OFFSET 12 +#define AC_PARAM_ECW_MIN_OFFSET 8 +#define AC_PARAM_AIFS_OFFSET 0 + +#define _AIFS(x) (x) +#define _ECW_MAX_MIN(x) ((x) << 8) +#define _TXOP_LIMIT(x) ((x) << 16) + +#define _BCNIFS(x) ((x) & 0xFF) +#define _BCNECW(x) ((((x) & 0xF)) << 8) + +#define _LRL(x) ((x) & 0x3F) +#define _SRL(x) (((x) & 0x3F) << 8) + +#define _SIFS_CCK_CTX(x) ((x) & 0xFF) +#define _SIFS_CCK_TRX(x) (((x) & 0xFF) << 8) + +#define _SIFS_OFDM_CTX(x) ((x) & 0xFF) +#define _SIFS_OFDM_TRX(x) (((x) & 0xFF) << 8) + +#define _TBTT_PROHIBIT_HOLD(x) (((x) & 0xFF) << 8) + +#define DIS_EDCA_CNT_DWN BIT(11) + +#define EN_MBSSID BIT(1) +#define EN_TXBCN_RPT BIT(2) +#define EN_BCN_FUNCTION BIT(3) + +#define TSFTR_RST BIT(0) +#define TSFTR1_RST BIT(1) + +#define STOP_BCNQ BIT(6) + +#define DIS_TSF_UDT0_NORMAL_CHIP BIT(4) +#define DIS_TSF_UDT0_TEST_CHIP BIT(5) + +#define ACMHW_HWEN BIT(0) +#define ACMHW_BEQEN BIT(1) +#define ACMHW_VIQEN BIT(2) +#define ACMHW_VOQEN BIT(3) +#define ACMHW_BEQSTATUS BIT(4) +#define ACMHW_VIQSTATUS BIT(5) +#define ACMHW_VOQSTATUS BIT(6) + +#define APSDOFF BIT(6) +#define APSDOFF_STATUS BIT(7) + +#define BW_20MHZ BIT(2) + +#define RATE_BITMAP_ALL 0xFFFFF + +#define RATE_RRSR_CCK_ONLY_1M 0xFFFF1 + +#define TSFRST BIT(0) +#define DIS_GCLK BIT(1) +#define PAD_SEL BIT(2) +#define PWR_ST BIT(6) +#define PWRBIT_OW_EN BIT(7) +#define ACRC BIT(8) +#define CFENDFORM BIT(9) +#define ICV BIT(10) + +#define AAP BIT(0) +#define APM BIT(1) +#define AM BIT(2) +#define AB BIT(3) +#define ADD3 BIT(4) +#define APWRMGT BIT(5) +#define CBSSID BIT(6) +#define CBSSID_DATA BIT(6) +#define CBSSID_BCN BIT(7) +#define ACRC32 BIT(8) +#define AICV BIT(9) +#define ADF BIT(11) +#define ACF BIT(12) +#define AMF BIT(13) +#define HTC_LOC_CTRL BIT(14) +#define UC_DATA_EN BIT(16) +#define BM_DATA_EN BIT(17) +#define MFBEN BIT(22) +#define LSIGEN BIT(23) +#define ENMBID BIT(24) +#define APP_BASSN BIT(27) +#define APP_PHYSTS BIT(28) +#define APP_ICV BIT(29) +#define APP_MIC BIT(30) +#define APP_FCS BIT(31) + +#define _MIN_SPACE(x) ((x) & 0x7) +#define _SHORT_GI_PADDING(x) (((x) & 0x1F) << 3) + +#define RXERR_TYPE_OFDM_PPDU 0 +#define RXERR_TYPE_OFDM_FALSE_ALARM 1 +#define RXERR_TYPE_OFDM_MPDU_OK 2 +#define RXERR_TYPE_OFDM_MPDU_FAIL 3 +#define RXERR_TYPE_CCK_PPDU 4 +#define RXERR_TYPE_CCK_FALSE_ALARM 5 +#define RXERR_TYPE_CCK_MPDU_OK 6 +#define RXERR_TYPE_CCK_MPDU_FAIL 7 +#define RXERR_TYPE_HT_PPDU 8 +#define RXERR_TYPE_HT_FALSE_ALARM 9 +#define RXERR_TYPE_HT_MPDU_TOTAL 10 +#define RXERR_TYPE_HT_MPDU_OK 11 +#define RXERR_TYPE_HT_MPDU_FAIL 12 +#define RXERR_TYPE_RX_FULL_DROP 15 + +#define RXERR_COUNTER_MASK 0xFFFFF +#define RXERR_RPT_RST BIT(27) +#define _RXERR_RPT_SEL(type) ((type) << 28) + +#define SCR_TXUSEDK BIT(0) +#define SCR_RXUSEDK BIT(1) +#define SCR_TXENCENABLE BIT(2) +#define SCR_RXDECENABLE BIT(3) +#define SCR_SKBYA2 BIT(4) +#define SCR_NOSKMC BIT(5) +#define SCR_TXBCUSEDK BIT(6) +#define SCR_RXBCUSEDK BIT(7) + +#define XCLK_VLD BIT(0) +#define ACLK_VLD BIT(1) +#define UCLK_VLD BIT(2) +#define PCLK_VLD BIT(3) +#define PCIRSTB BIT(4) +#define V15_VLD BIT(5) +#define TRP_B15V_EN BIT(7) +#define SIC_IDLE BIT(8) +#define BD_MAC2 BIT(9) +#define BD_MAC1 BIT(10) +#define IC_MACPHY_MODE BIT(11) +#define BT_FUNC BIT(16) +#define VENDOR_ID BIT(19) +#define PAD_HWPD_IDN BIT(22) +#define TRP_VAUX_EN BIT(23) +#define TRP_BT_EN BIT(24) +#define BD_PKG_SEL BIT(25) +#define BD_HCI_SEL BIT(26) +#define TYPE_ID BIT(27) + +#define USB_IS_HIGH_SPEED 0 +#define USB_IS_FULL_SPEED 1 +#define USB_SPEED_MASK BIT(5) + +#define USB_NORMAL_SIE_EP_MASK 0xF +#define USB_NORMAL_SIE_EP_SHIFT 4 + +#define USB_TEST_EP_MASK 0x30 +#define USB_TEST_EP_SHIFT 4 + +#define USB_AGG_EN BIT(3) + +#define MAC_ADDR_LEN 6 +#define LAST_ENTRY_OF_TX_PKT_BUFFER 175/*255 88e*/ + +#define POLLING_LLT_THRESHOLD 20 +#define POLLING_READY_TIMEOUT_COUNT 3000 + +#define MAX_MSS_DENSITY_2T 0x13 +#define MAX_MSS_DENSITY_1T 0x0A + +#define EPROM_CMD_OPERATING_MODE_MASK ((1<<7)|(1<<6)) +#define EPROM_CMD_CONFIG 0x3 +#define EPROM_CMD_LOAD 1 + +#define HWSET_MAX_SIZE_92S HWSET_MAX_SIZE + +#define HAL_8192C_HW_GPIO_WPS_BIT BIT(2) + +#define RPMAC_RESET 0x100 +#define RPMAC_TXSTART 0x104 +#define RPMAC_TXLEGACYSIG 0x108 +#define RPMAC_TXHTSIG1 0x10c +#define RPMAC_TXHTSIG2 0x110 +#define RPMAC_PHYDEBUG 0x114 +#define RPMAC_TXPACKETNUM 0x118 +#define RPMAC_TXIDLE 0x11c +#define RPMAC_TXMACHEADER0 0x120 +#define RPMAC_TXMACHEADER1 0x124 +#define RPMAC_TXMACHEADER2 0x128 +#define RPMAC_TXMACHEADER3 0x12c +#define RPMAC_TXMACHEADER4 0x130 +#define RPMAC_TXMACHEADER5 0x134 +#define RPMAC_TXDADATYPE 0x138 +#define RPMAC_TXRANDOMSEED 0x13c +#define RPMAC_CCKPLCPPREAMBLE 0x140 +#define RPMAC_CCKPLCPHEADER 0x144 +#define RPMAC_CCKCRC16 0x148 +#define RPMAC_OFDMRXCRC32OK 0x170 +#define RPMAC_OFDMRXCRC32ER 0x174 +#define RPMAC_OFDMRXPARITYER 0x178 +#define RPMAC_OFDMRXCRC8ER 0x17c +#define RPMAC_CCKCRXRC16ER 0x180 +#define RPMAC_CCKCRXRC32ER 0x184 +#define RPMAC_CCKCRXRC32OK 0x188 +#define RPMAC_TXSTATUS 0x18c + +#define RFPGA0_RFMOD 0x800 + +#define RFPGA0_TXINFO 0x804 +#define RFPGA0_PSDFUNCTION 0x808 + +#define RFPGA0_TXGAINSTAGE 0x80c + +#define RFPGA0_RFTIMING1 0x810 +#define RFPGA0_RFTIMING2 0x814 + +#define RFPGA0_XA_HSSIPARAMETER1 0x820 +#define RFPGA0_XA_HSSIPARAMETER2 0x824 +#define RFPGA0_XB_HSSIPARAMETER1 0x828 +#define RFPGA0_XB_HSSIPARAMETER2 0x82c + +#define RFPGA0_XA_LSSIPARAMETER 0x840 +#define RFPGA0_XB_LSSIPARAMETER 0x844 + +#define RFPGA0_RFWAKEUPPARAMETER 0x850 +#define RFPGA0_RFSLEEPUPPARAMETER 0x854 + +#define RFPGA0_XAB_SWITCHCONTROL 0x858 +#define RFPGA0_XCD_SWITCHCONTROL 0x85c + +#define RFPGA0_XA_RFINTERFACEOE 0x860 +#define RFPGA0_XB_RFINTERFACEOE 0x864 + +#define RFPGA0_XAB_RFINTERFACESW 0x870 +#define RFPGA0_XCD_RFINTERFACESW 0x874 + +#define RFPGA0_XAB_RFPARAMETER 0x878 +#define RFPGA0_XCD_RFPARAMETER 0x87c + +#define RFPGA0_ANALOGPARAMETER1 0x880 +#define RFPGA0_ANALOGPARAMETER2 0x884 +#define RFPGA0_ANALOGPARAMETER3 0x888 +#define RFPGA0_ANALOGPARAMETER4 0x88c + +#define RFPGA0_XA_LSSIREADBACK 0x8a0 +#define RFPGA0_XB_LSSIREADBACK 0x8a4 +#define RFPGA0_XC_LSSIREADBACK 0x8a8 +#define RFPGA0_XD_LSSIREADBACK 0x8ac + +#define RFPGA0_PSDREPORT 0x8b4 +#define TRANSCEIVEA_HSPI_READBACK 0x8b8 +#define TRANSCEIVEB_HSPI_READBACK 0x8bc +#define REG_SC_CNT 0x8c4 +#define RFPGA0_XAB_RFINTERFACERB 0x8e0 +#define RFPGA0_XCD_RFINTERFACERB 0x8e4 + +#define RFPGA1_RFMOD 0x900 + +#define RFPGA1_TXBLOCK 0x904 +#define RFPGA1_DEBUGSELECT 0x908 +#define RFPGA1_TXINFO 0x90c + +#define RCCK0_SYSTEM 0xa00 + +#define RCCK0_AFESETTING 0xa04 +#define RCCK0_CCA 0xa08 + +#define RCCK0_RXAGC1 0xa0c +#define RCCK0_RXAGC2 0xa10 + +#define RCCK0_RXHP 0xa14 + +#define RCCK0_DSPPARAMETER1 0xa18 +#define RCCK0_DSPPARAMETER2 0xa1c + +#define RCCK0_TXFILTER1 0xa20 +#define RCCK0_TXFILTER2 0xa24 +#define RCCK0_DEBUGPORT 0xa28 +#define RCCK0_FALSEALARMREPORT 0xa2c +#define RCCK0_TRSSIREPORT 0xa50 +#define RCCK0_RXREPORT 0xa54 +#define RCCK0_FACOUNTERLOWER 0xa5c +#define RCCK0_FACOUNTERUPPER 0xa58 +#define RCCK0_CCA_CNT 0xa60 + + +/* PageB(0xB00) */ +#define RPDP_ANTA 0xb00 +#define RPDP_ANTA_4 0xb04 +#define RPDP_ANTA_8 0xb08 +#define RPDP_ANTA_C 0xb0c +#define RPDP_ANTA_10 0xb10 +#define RPDP_ANTA_14 0xb14 +#define RPDP_ANTA_18 0xb18 +#define RPDP_ANTA_1C 0xb1c +#define RPDP_ANTA_20 0xb20 +#define RPDP_ANTA_24 0xb24 + +#define RCONFIG_PMPD_ANTA 0xb28 +#define CONFIG_RAM64X16 0xb2c + +#define RBNDA 0xb30 +#define RHSSIPAR 0xb34 + +#define RCONFIG_ANTA 0xb68 +#define RCONFIG_ANTB 0xb6c + +#define RPDP_ANTB 0xb70 +#define RPDP_ANTB_4 0xb74 +#define RPDP_ANTB_8 0xb78 +#define RPDP_ANTB_C 0xb7c +#define RPDP_ANTB_10 0xb80 +#define RPDP_ANTB_14 0xb84 +#define RPDP_ANTB_18 0xb88 +#define RPDP_ANTB_1C 0xb8c +#define RPDP_ANTB_20 0xb90 +#define RPDP_ANTB_24 0xb94 + +#define RCONFIG_PMPD_ANTB 0xb98 + +#define RBNDB 0xba0 + +#define RAPK 0xbd8 +#define RPM_RX0_ANTA 0xbdc +#define RPM_RX1_ANTA 0xbe0 +#define RPM_RX2_ANTA 0xbe4 +#define RPM_RX3_ANTA 0xbe8 +#define RPM_RX0_ANTB 0xbec +#define RPM_RX1_ANTB 0xbf0 +#define RPM_RX2_ANTB 0xbf4 +#define RPM_RX3_ANTB 0xbf8 + +/*Page C*/ +#define ROFDM0_LSTF 0xc00 + +#define ROFDM0_TRXPATHENABLE 0xc04 +#define ROFDM0_TRMUXPAR 0xc08 +#define ROFDM0_TRSWISOLATION 0xc0c + +#define ROFDM0_XARXAFE 0xc10 +#define ROFDM0_XARXIQIMBALANCE 0xc14 +#define ROFDM0_XBRXAFE 0xc18 +#define ROFDM0_XBRXIQIMBALANCE 0xc1c +#define ROFDM0_XCRXAFE 0xc20 +#define ROFDM0_XCRXIQIMBANLANCE 0xc24 +#define ROFDM0_XDRXAFE 0xc28 +#define ROFDM0_XDRXIQIMBALANCE 0xc2c + +#define ROFDM0_RXDETECTOR1 0xc30 +#define ROFDM0_RXDETECTOR2 0xc34 +#define ROFDM0_RXDETECTOR3 0xc38 +#define ROFDM0_RXDETECTOR4 0xc3c + +#define ROFDM0_RXDSP 0xc40 +#define ROFDM0_CFOANDDAGC 0xc44 +#define ROFDM0_CCADROPTHRESHOLD 0xc48 +#define ROFDM0_ECCATHRESHOLD 0xc4c + +#define ROFDM0_XAAGCCORE1 0xc50 +#define ROFDM0_XAAGCCORE2 0xc54 +#define ROFDM0_XBAGCCORE1 0xc58 +#define ROFDM0_XBAGCCORE2 0xc5c +#define ROFDM0_XCAGCCORE1 0xc60 +#define ROFDM0_XCAGCCORE2 0xc64 +#define ROFDM0_XDAGCCORE1 0xc68 +#define ROFDM0_XDAGCCORE2 0xc6c + +#define ROFDM0_AGCPARAMETER1 0xc70 +#define ROFDM0_AGCPARAMETER2 0xc74 +#define ROFDM0_AGCRSSITABLE 0xc78 +#define ROFDM0_HTSTFAGC 0xc7c + +#define ROFDM0_XATXIQIMBALANCE 0xc80 +#define ROFDM0_XATXAFE 0xc84 +#define ROFDM0_XBTXIQIMBALANCE 0xc88 +#define ROFDM0_XBTXAFE 0xc8c +#define ROFDM0_XCTXIQIMBALANCE 0xc90 +#define ROFDM0_XCTXAFE 0xc94 +#define ROFDM0_XDTXIQIMBALANCE 0xc98 +#define ROFDM0_XDTXAFE 0xc9c + +#define ROFDM0_RXIQEXTANTA 0xca0 +#define ROFDM0_TXCOEFF1 0xca4 +#define ROFDM0_TXCOEFF2 0xca8 +#define ROFDM0_TXCOEFF3 0xcac +#define ROFDM0_TXCOEFF4 0xcb0 +#define ROFDM0_TXCOEFF5 0xcb4 +#define ROFDM0_TXCOEFF6 0xcb8 + +#define ROFDM0_RXHPPARAMETER 0xce0 +#define ROFDM0_TXPSEUDONOISEWGT 0xce4 +#define ROFDM0_FRAMESYNC 0xcf0 +#define ROFDM0_DFSREPORT 0xcf4 + + +#define ROFDM1_LSTF 0xd00 +#define ROFDM1_TRXPATHENABLE 0xd04 + +#define ROFDM1_CF0 0xd08 +#define ROFDM1_CSI1 0xd10 +#define ROFDM1_SBD 0xd14 +#define ROFDM1_CSI2 0xd18 +#define ROFDM1_CFOTRACKING 0xd2c +#define ROFDM1_TRXMESAURE1 0xd34 +#define ROFDM1_INTFDET 0xd3c +#define ROFDM1_PSEUDONOISESTATEAB 0xd50 +#define ROFDM1_PSEUDONOISESTATECD 0xd54 +#define ROFDM1_RXPSEUDONOISEWGT 0xd58 + +#define ROFDM_PHYCOUNTER1 0xda0 +#define ROFDM_PHYCOUNTER2 0xda4 +#define ROFDM_PHYCOUNTER3 0xda8 + +#define ROFDM_SHORTCFOAB 0xdac +#define ROFDM_SHORTCFOCD 0xdb0 +#define ROFDM_LONGCFOAB 0xdb4 +#define ROFDM_LONGCFOCD 0xdb8 +#define ROFDM_TAILCF0AB 0xdbc +#define ROFDM_TAILCF0CD 0xdc0 +#define ROFDM_PWMEASURE1 0xdc4 +#define ROFDM_PWMEASURE2 0xdc8 +#define ROFDM_BWREPORT 0xdcc +#define ROFDM_AGCREPORT 0xdd0 +#define ROFDM_RXSNR 0xdd4 +#define ROFDM_RXEVMCSI 0xdd8 +#define ROFDM_SIGREPORT 0xddc + +#define RTXAGC_A_RATE18_06 0xe00 +#define RTXAGC_A_RATE54_24 0xe04 +#define RTXAGC_A_CCK1_MCS32 0xe08 +#define RTXAGC_A_MCS03_MCS00 0xe10 +#define RTXAGC_A_MCS07_MCS04 0xe14 +#define RTXAGC_A_MCS11_MCS08 0xe18 +#define RTXAGC_A_MCS15_MCS12 0xe1c + +#define RTXAGC_B_RATE18_06 0x830 +#define RTXAGC_B_RATE54_24 0x834 +#define RTXAGC_B_CCK1_55_MCS32 0x838 +#define RTXAGC_B_MCS03_MCS00 0x83c +#define RTXAGC_B_MCS07_MCS04 0x848 +#define RTXAGC_B_MCS11_MCS08 0x84c +#define RTXAGC_B_MCS15_MCS12 0x868 +#define RTXAGC_B_CCK11_A_CCK2_11 0x86c + +#define RFPGA0_IQK 0xe28 +#define RTX_IQK_TONE_A 0xe30 +#define RRX_IQK_TONE_A 0xe34 +#define RTX_IQK_PI_A 0xe38 +#define RRX_IQK_PI_A 0xe3c + +#define RTX_IQK 0xe40 +#define RRX_IQK 0xe44 +#define RIQK_AGC_PTS 0xe48 +#define RIQK_AGC_RSP 0xe4c +#define RTX_IQK_TONE_B 0xe50 +#define RRX_IQK_TONE_B 0xe54 +#define RTX_IQK_PI_B 0xe58 +#define RRX_IQK_PI_B 0xe5c +#define RIQK_AGC_CONT 0xe60 + +#define RBLUE_TOOTH 0xe6c +#define RRX_WAIT_CCA 0xe70 +#define RTX_CCK_RFON 0xe74 +#define RTX_CCK_BBON 0xe78 +#define RTX_OFDM_RFON 0xe7c +#define RTX_OFDM_BBON 0xe80 +#define RTX_TO_RX 0xe84 +#define RTX_TO_TX 0xe88 +#define RRX_CCK 0xe8c + +#define RTX_POWER_BEFORE_IQK_A 0xe94 +#define RTX_POWER_AFTER_IQK_A 0xe9c + +#define RRX_POWER_BEFORE_IQK_A 0xea0 +#define RRX_POWER_BEFORE_IQK_A_2 0xea4 +#define RRX_POWER_AFTER_IQK_A 0xea8 +#define RRX_POWER_AFTER_IQK_A_2 0xeac + +#define RTX_POWER_BEFORE_IQK_B 0xeb4 +#define RTX_POWER_AFTER_IQK_B 0xebc + +#define RRX_POWER_BEFORE_IQK_B 0xec0 +#define RRX_POWER_BEFORE_IQK_B_2 0xec4 +#define RRX_POWER_AFTER_IQK_B 0xec8 +#define RRX_POWER_AFTER_IQK_B_2 0xecc + +#define RRX_OFDM 0xed0 +#define RRX_WAIT_RIFS 0xed4 +#define RRX_TO_RX 0xed8 +#define RSTANDBY 0xedc +#define RSLEEP 0xee0 +#define RPMPD_ANAEN 0xeec + +#define RZEBRA1_HSSIENABLE 0x0 +#define RZEBRA1_TRXENABLE1 0x1 +#define RZEBRA1_TRXENABLE2 0x2 +#define RZEBRA1_AGC 0x4 +#define RZEBRA1_CHARGEPUMP 0x5 +#define RZEBRA1_CHANNEL 0x7 + +#define RZEBRA1_TXGAIN 0x8 +#define RZEBRA1_TXLPF 0x9 +#define RZEBRA1_RXLPF 0xb +#define RZEBRA1_RXHPFCORNER 0xc + +#define RGLOBALCTRL 0 +#define RRTL8256_TXLPF 19 +#define RRTL8256_RXLPF 11 +#define RRTL8258_TXLPF 0x11 +#define RRTL8258_RXLPF 0x13 +#define RRTL8258_RSSILPF 0xa + +#define RF_AC 0x00 + +#define RF_IQADJ_G1 0x01 +#define RF_IQADJ_G2 0x02 +#define RF_POW_TRSW 0x05 + +#define RF_GAIN_RX 0x06 +#define RF_GAIN_TX 0x07 + +#define RF_TXM_IDAC 0x08 +#define RF_BS_IQGEN 0x0F + +#define RF_MODE1 0x10 +#define RF_MODE2 0x11 + +#define RF_RX_AGC_HP 0x12 +#define RF_TX_AGC 0x13 +#define RF_BIAS 0x14 +#define RF_IPA 0x15 +#define RF_POW_ABILITY 0x17 +#define RF_MODE_AG 0x18 +#define RRFCHANNEL 0x18 +#define RF_CHNLBW 0x18 +#define RF_TOP 0x19 + +#define RF_RX_G1 0x1A +#define RF_RX_G2 0x1B + +#define RF_RX_BB2 0x1C +#define RF_RX_BB1 0x1D + +#define RF_RCK1 0x1E +#define RF_RCK2 0x1F + +#define RF_TX_G1 0x20 +#define RF_TX_G2 0x21 +#define RF_TX_G3 0x22 + +#define RF_TX_BB1 0x23 +#define RF_T_METER 0x42 + +#define RF_SYN_G1 0x25 +#define RF_SYN_G2 0x26 +#define RF_SYN_G3 0x27 +#define RF_SYN_G4 0x28 +#define RF_SYN_G5 0x29 +#define RF_SYN_G6 0x2A +#define RF_SYN_G7 0x2B +#define RF_SYN_G8 0x2C + +#define RF_RCK_OS 0x30 +#define RF_TXPA_G1 0x31 +#define RF_TXPA_G2 0x32 +#define RF_TXPA_G3 0x33 + +#define RF_TX_BIAS_A 0x35 +#define RF_TX_BIAS_D 0x36 +#define RF_LOBF_9 0x38 +#define RF_RXRF_A3 0x3C +#define RF_TRSW 0x3F + +#define RF_TXRF_A2 0x41 +#define RF_TXPA_G4 0x46 +#define RF_TXPA_A4 0x4B + +#define RF_WE_LUT 0xEF + +#define BBBRESETB 0x100 +#define BGLOBALRESETB 0x200 +#define BOFDMTXSTART 0x4 +#define BCCKTXSTART 0x8 +#define BCRC32DEBUG 0x100 +#define BPMACLOOPBACK 0x10 +#define BTXLSIG 0xffffff +#define BOFDMTXRATE 0xf +#define BOFDMTXRESERVED 0x10 +#define BOFDMTXLENGTH 0x1ffe0 +#define BOFDMTXPARITY 0x20000 +#define BTXHTSIG1 0xffffff +#define BTXHTMCSRATE 0x7f +#define BTXHTBW 0x80 +#define BTXHTLENGTH 0xffff00 +#define BTXHTSIG2 0xffffff +#define BTXHTSMOOTHING 0x1 +#define BTXHTSOUNDING 0x2 +#define BTXHTRESERVED 0x4 +#define BTXHTAGGREATION 0x8 +#define BTXHTSTBC 0x30 +#define BTXHTADVANCECODING 0x40 +#define BTXHTSHORTGI 0x80 +#define BTXHTNUMBERHT_LTF 0x300 +#define BTXHTCRC8 0x3fc00 +#define BCOUNTERRESET 0x10000 +#define BNUMOFOFDMTX 0xffff +#define BNUMOFCCKTX 0xffff0000 +#define BTXIDLEINTERVAL 0xffff +#define BOFDMSERVICE 0xffff0000 +#define BTXMACHEADER 0xffffffff +#define BTXDATAINIT 0xff +#define BTXHTMODE 0x100 +#define BTXDATATYPE 0x30000 +#define BTXRANDOMSEED 0xffffffff +#define BCCKTXPREAMBLE 0x1 +#define BCCKTXSFD 0xffff0000 +#define BCCKTXSIG 0xff +#define BCCKTXSERVICE 0xff00 +#define BCCKLENGTHEXT 0x8000 +#define BCCKTXLENGHT 0xffff0000 +#define BCCKTXCRC16 0xffff +#define BCCKTXSTATUS 0x1 +#define BOFDMTXSTATUS 0x2 +#define IS_BB_REG_OFFSET_92S(_offset) \ + ((_offset >= 0x800) && (_offset <= 0xfff)) + +#define BRFMOD 0x1 +#define BJAPANMODE 0x2 +#define BCCKTXSC 0x30 +#define BCCKEN 0x1000000 +#define BOFDMEN 0x2000000 + +#define BOFDMRXADCPHASE 0x10000 +#define BOFDMTXDACPHASE 0x40000 +#define BXATXAGC 0x3f + +#define BXBTXAGC 0xf00 +#define BXCTXAGC 0xf000 +#define BXDTXAGC 0xf0000 + +#define BPASTART 0xf0000000 +#define BTRSTART 0x00f00000 +#define BRFSTART 0x0000f000 +#define BBBSTART 0x000000f0 +#define BBBCCKSTART 0x0000000f +#define BPAEND 0xf +#define BTREND 0x0f000000 +#define BRFEND 0x000f0000 +#define BCCAMASK 0x000000f0 +#define BR2RCCAMASK 0x00000f00 +#define BHSSI_R2TDELAY 0xf8000000 +#define BHSSI_T2RDELAY 0xf80000 +#define BCONTXHSSI 0x400 +#define BIGFROMCCK 0x200 +#define BAGCADDRESS 0x3f +#define BRXHPTX 0x7000 +#define BRXHP2RX 0x38000 +#define BRXHPCCKINI 0xc0000 +#define BAGCTXCODE 0xc00000 +#define BAGCRXCODE 0x300000 + +#define B3WIREDATALENGTH 0x800 +#define B3WIREADDREAALENGTH 0x400 + +#define B3WIRERFPOWERDOWN 0x1 +#define B5GPAPEPOLARITY 0x40000000 +#define B2GPAPEPOLARITY 0x80000000 +#define BRFSW_TXDEFAULTANT 0x3 +#define BRFSW_TXOPTIONANT 0x30 +#define BRFSW_RXDEFAULTANT 0x300 +#define BRFSW_RXOPTIONANT 0x3000 +#define BRFSI_3WIREDATA 0x1 +#define BRFSI_3WIRECLOCK 0x2 +#define BRFSI_3WIRELOAD 0x4 +#define BRFSI_3WIRERW 0x8 +#define BRFSI_3WIRE 0xf + +#define BRFSI_RFENV 0x10 + +#define BRFSI_TRSW 0x20 +#define BRFSI_TRSWB 0x40 +#define BRFSI_ANTSW 0x100 +#define BRFSI_ANTSWB 0x200 +#define BRFSI_PAPE 0x400 +#define BRFSI_PAPE5G 0x800 +#define BBANDSELECT 0x1 +#define BHTSIG2_GI 0x80 +#define BHTSIG2_SMOOTHING 0x01 +#define BHTSIG2_SOUNDING 0x02 +#define BHTSIG2_AGGREATON 0x08 +#define BHTSIG2_STBC 0x30 +#define BHTSIG2_ADVCODING 0x40 +#define BHTSIG2_NUMOFHTLTF 0x300 +#define BHTSIG2_CRC8 0x3fc +#define BHTSIG1_MCS 0x7f +#define BHTSIG1_BANDWIDTH 0x80 +#define BHTSIG1_HTLENGTH 0xffff +#define BLSIG_RATE 0xf +#define BLSIG_RESERVED 0x10 +#define BLSIG_LENGTH 0x1fffe +#define BLSIG_PARITY 0x20 +#define BCCKRXPHASE 0x4 + +#define BLSSIREADADDRESS 0x7f800000 +#define BLSSIREADEDGE 0x80000000 + +#define BLSSIREADBACKDATA 0xfffff + +#define BLSSIREADOKFLAG 0x1000 +#define BCCKSAMPLERATE 0x8 +#define BREGULATOR0STANDBY 0x1 +#define BREGULATORPLLSTANDBY 0x2 +#define BREGULATOR1STANDBY 0x4 +#define BPLLPOWERUP 0x8 +#define BDPLLPOWERUP 0x10 +#define BDA10POWERUP 0x20 +#define BAD7POWERUP 0x200 +#define BDA6POWERUP 0x2000 +#define BXTALPOWERUP 0x4000 +#define B40MDCLKPOWERUP 0x8000 +#define BDA6DEBUGMODE 0x20000 +#define BDA6SWING 0x380000 + +#define BADCLKPHASE 0x4000000 +#define B80MCLKDELAY 0x18000000 +#define BAFEWATCHDOGENABLE 0x20000000 + +#define BXTALCAP01 0xc0000000 +#define BXTALCAP23 0x3 +#define BXTALCAP92X 0x0f000000 +#define BXTALCAP 0x0f000000 + +#define BINTDIFCLKENABLE 0x400 +#define BEXTSIGCLKENABLE 0x800 +#define BBANDGAP_MBIAS_POWERUP 0x10000 +#define BAD11SH_GAIN 0xc0000 +#define BAD11NPUT_RANGE 0x700000 +#define BAD110P_CURRENT 0x3800000 +#define BLPATH_LOOPBACK 0x4000000 +#define BQPATH_LOOPBACK 0x8000000 +#define BAFE_LOOPBACK 0x10000000 +#define BDA10_SWING 0x7e0 +#define BDA10_REVERSE 0x800 +#define BDA_CLK_SOURCE 0x1000 +#define BDA7INPUT_RANGE 0x6000 +#define BDA7_GAIN 0x38000 +#define BDA7OUTPUT_CM_MODE 0x40000 +#define BDA7INPUT_CM_MODE 0x380000 +#define BDA7CURRENT 0xc00000 +#define BREGULATOR_ADJUST 0x7000000 +#define BAD11POWERUP_ATTX 0x1 +#define BDA10PS_ATTX 0x10 +#define BAD11POWERUP_ATRX 0x100 +#define BDA10PS_ATRX 0x1000 +#define BCCKRX_AGC_FORMAT 0x200 +#define BPSDFFT_SAMPLE_POINT 0xc000 +#define BPSD_AVERAGE_NUM 0x3000 +#define BIQPATH_CONTROL 0xc00 +#define BPSD_FREQ 0x3ff +#define BPSD_ANTENNA_PATH 0x30 +#define BPSD_IQ_SWITCH 0x40 +#define BPSD_RX_TRIGGER 0x400000 +#define BPSD_TX_TRIGGER 0x80000000 +#define BPSD_SINE_TONE_SCALE 0x7f000000 +#define BPSD_REPORT 0xffff + +#define BOFDM_TXSC 0x30000000 +#define BCCK_TXON 0x1 +#define BOFDM_TXON 0x2 +#define BDEBUG_PAGE 0xfff +#define BDEBUG_ITEM 0xff +#define BANTL 0x10 +#define BANT_NONHT 0x100 +#define BANT_HT1 0x1000 +#define BANT_HT2 0x10000 +#define BANT_HT1S1 0x100000 +#define BANT_NONHTS1 0x1000000 + +#define BCCK_BBMODE 0x3 +#define BCCK_TXPOWERSAVING 0x80 +#define BCCK_RXPOWERSAVING 0x40 + +#define BCCK_SIDEBAND 0x10 + +#define BCCK_SCRAMBLE 0x8 +#define BCCK_ANTDIVERSITY 0x8000 +#define BCCK_CARRIER_RECOVERY 0x4000 +#define BCCK_TXRATE 0x3000 +#define BCCK_DCCANCEL 0x0800 +#define BCCK_ISICANCEL 0x0400 +#define BCCK_MATCH_FILTER 0x0200 +#define BCCK_EQUALIZER 0x0100 +#define BCCK_PREAMBLE_DETECT 0x800000 +#define BCCK_FAST_FALSECCA 0x400000 +#define BCCK_CH_ESTSTART 0x300000 +#define BCCK_CCA_COUNT 0x080000 +#define BCCK_CS_LIM 0x070000 +#define BCCK_BIST_MODE 0x80000000 +#define BCCK_CCAMASK 0x40000000 +#define BCCK_TX_DAC_PHASE 0x4 +#define BCCK_RX_ADC_PHASE 0x20000000 +#define BCCKR_CP_MODE 0x0100 +#define BCCK_TXDC_OFFSET 0xf0 +#define BCCK_RXDC_OFFSET 0xf +#define BCCK_CCA_MODE 0xc000 +#define BCCK_FALSECS_LIM 0x3f00 +#define BCCK_CS_RATIO 0xc00000 +#define BCCK_CORGBIT_SEL 0x300000 +#define BCCK_PD_LIM 0x0f0000 +#define BCCK_NEWCCA 0x80000000 +#define BCCK_RXHP_OF_IG 0x8000 +#define BCCK_RXIG 0x7f00 +#define BCCK_LNA_POLARITY 0x800000 +#define BCCK_RX1ST_BAIN 0x7f0000 +#define BCCK_RF_EXTEND 0x20000000 +#define BCCK_RXAGC_SATLEVEL 0x1f000000 +#define BCCK_RXAGC_SATCOUNT 0xe0 +#define BCCKRXRFSETTLE 0x1f +#define BCCK_FIXED_RXAGC 0x8000 +#define BCCK_ANTENNA_POLARITY 0x2000 +#define BCCK_TXFILTER_TYPE 0x0c00 +#define BCCK_RXAGC_REPORTTYPE 0x0300 +#define BCCK_RXDAGC_EN 0x80000000 +#define BCCK_RXDAGC_PERIOD 0x20000000 +#define BCCK_RXDAGC_SATLEVEL 0x1f000000 +#define BCCK_TIMING_RECOVERY 0x800000 +#define BCCK_TXC0 0x3f0000 +#define BCCK_TXC1 0x3f000000 +#define BCCK_TXC2 0x3f +#define BCCK_TXC3 0x3f00 +#define BCCK_TXC4 0x3f0000 +#define BCCK_TXC5 0x3f000000 +#define BCCK_TXC6 0x3f +#define BCCK_TXC7 0x3f00 +#define BCCK_DEBUGPORT 0xff0000 +#define BCCK_DAC_DEBUG 0x0f000000 +#define BCCK_FALSEALARM_ENABLE 0x8000 +#define BCCK_FALSEALARM_READ 0x4000 +#define BCCK_TRSSI 0x7f +#define BCCK_RXAGC_REPORT 0xfe +#define BCCK_RXREPORT_ANTSEL 0x80000000 +#define BCCK_RXREPORT_MFOFF 0x40000000 +#define BCCK_RXREPORT_SQLOSS 0x20000000 +#define BCCK_RXREPORT_PKTLOSS 0x10000000 +#define BCCK_RXREPORT_LOCKEDBIT 0x08000000 +#define BCCK_RXREPORT_RATEERROR 0x04000000 +#define BCCK_RXREPORT_RXRATE 0x03000000 +#define BCCK_RXFA_COUNTER_LOWER 0xff +#define BCCK_RXFA_COUNTER_UPPER 0xff000000 +#define BCCK_RXHPAGC_START 0xe000 +#define BCCK_RXHPAGC_FINAL 0x1c00 +#define BCCK_RXFALSEALARM_ENABLE 0x8000 +#define BCCK_FACOUNTER_FREEZE 0x4000 +#define BCCK_TXPATH_SEL 0x10000000 +#define BCCK_DEFAULT_RXPATH 0xc000000 +#define BCCK_OPTION_RXPATH 0x3000000 + +#define BNUM_OFSTF 0x3 +#define BSHIFT_L 0xc0 +#define BGI_TH 0xc +#define BRXPATH_A 0x1 +#define BRXPATH_B 0x2 +#define BRXPATH_C 0x4 +#define BRXPATH_D 0x8 +#define BTXPATH_A 0x1 +#define BTXPATH_B 0x2 +#define BTXPATH_C 0x4 +#define BTXPATH_D 0x8 +#define BTRSSI_FREQ 0x200 +#define BADC_BACKOFF 0x3000 +#define BDFIR_BACKOFF 0xc000 +#define BTRSSI_LATCH_PHASE 0x10000 +#define BRX_LDC_OFFSET 0xff +#define BRX_QDC_OFFSET 0xff00 +#define BRX_DFIR_MODE 0x1800000 +#define BRX_DCNF_TYPE 0xe000000 +#define BRXIQIMB_A 0x3ff +#define BRXIQIMB_B 0xfc00 +#define BRXIQIMB_C 0x3f0000 +#define BRXIQIMB_D 0xffc00000 +#define BDC_DC_NOTCH 0x60000 +#define BRXNB_NOTCH 0x1f000000 +#define BPD_TH 0xf +#define BPD_TH_OPT2 0xc000 +#define BPWED_TH 0x700 +#define BIFMF_WIN_L 0x800 +#define BPD_OPTION 0x1000 +#define BMF_WIN_L 0xe000 +#define BBW_SEARCH_L 0x30000 +#define BWIN_ENH_L 0xc0000 +#define BBW_TH 0x700000 +#define BED_TH2 0x3800000 +#define BBW_OPTION 0x4000000 +#define BRADIO_TH 0x18000000 +#define BWINDOW_L 0xe0000000 +#define BSBD_OPTION 0x1 +#define BFRAME_TH 0x1c +#define BFS_OPTION 0x60 +#define BDC_SLOPE_CHECK 0x80 +#define BFGUARD_COUNTER_DC_L 0xe00 +#define BFRAME_WEIGHT_SHORT 0x7000 +#define BSUB_TUNE 0xe00000 +#define BFRAME_DC_LENGTH 0xe000000 +#define BSBD_START_OFFSET 0x30000000 +#define BFRAME_TH_2 0x7 +#define BFRAME_GI2_TH 0x38 +#define BGI2_SYNC_EN 0x40 +#define BSARCH_SHORT_EARLY 0x300 +#define BSARCH_SHORT_LATE 0xc00 +#define BSARCH_GI2_LATE 0x70000 +#define BCFOANTSUM 0x1 +#define BCFOACC 0x2 +#define BCFOSTARTOFFSET 0xc +#define BCFOLOOPBACK 0x70 +#define BCFOSUMWEIGHT 0x80 +#define BDAGCENABLE 0x10000 +#define BTXIQIMB_A 0x3ff +#define BTXIQIMB_b 0xfc00 +#define BTXIQIMB_C 0x3f0000 +#define BTXIQIMB_D 0xffc00000 +#define BTXIDCOFFSET 0xff +#define BTXIQDCOFFSET 0xff00 +#define BTXDFIRMODE 0x10000 +#define BTXPESUDO_NOISEON 0x4000000 +#define BTXPESUDO_NOISE_A 0xff +#define BTXPESUDO_NOISE_B 0xff00 +#define BTXPESUDO_NOISE_C 0xff0000 +#define BTXPESUDO_NOISE_D 0xff000000 +#define BCCA_DROPOPTION 0x20000 +#define BCCA_DROPTHRES 0xfff00000 +#define BEDCCA_H 0xf +#define BEDCCA_L 0xf0 +#define BLAMBDA_ED 0x300 +#define BRX_INITIALGAIN 0x7f +#define BRX_ANTDIV_EN 0x80 +#define BRX_AGC_ADDRESS_FOR_LNA 0x7f00 +#define BRX_HIGHPOWER_FLOW 0x8000 +#define BRX_AGC_FREEZE_THRES 0xc0000 +#define BRX_FREEZESTEP_AGC1 0x300000 +#define BRX_FREEZESTEP_AGC2 0xc00000 +#define BRX_FREEZESTEP_AGC3 0x3000000 +#define BRX_FREEZESTEP_AGC0 0xc000000 +#define BRXRSSI_CMP_EN 0x10000000 +#define BRXQUICK_AGCEN 0x20000000 +#define BRXAGC_FREEZE_THRES_MODE 0x40000000 +#define BRX_OVERFLOW_CHECKTYPE 0x80000000 +#define BRX_AGCSHIFT 0x7f +#define BTRSW_TRI_ONLY 0x80 +#define BPOWER_THRES 0x300 +#define BRXAGC_EN 0x1 +#define BRXAGC_TOGETHER_EN 0x2 +#define BRXAGC_MIN 0x4 +#define BRXHP_INI 0x7 +#define BRXHP_TRLNA 0x70 +#define BRXHP_RSSI 0x700 +#define BRXHP_BBP1 0x7000 +#define BRXHP_BBP2 0x70000 +#define BRXHP_BBP3 0x700000 +#define BRSSI_H 0x7f0000 +#define BRSSI_GEN 0x7f000000 +#define BRXSETTLE_TRSW 0x7 +#define BRXSETTLE_LNA 0x38 +#define BRXSETTLE_RSSI 0x1c0 +#define BRXSETTLE_BBP 0xe00 +#define BRXSETTLE_RXHP 0x7000 +#define BRXSETTLE_ANTSW_RSSI 0x38000 +#define BRXSETTLE_ANTSW 0xc0000 +#define BRXPROCESS_TIME_DAGC 0x300000 +#define BRXSETTLE_HSSI 0x400000 +#define BRXPROCESS_TIME_BBPPW 0x800000 +#define BRXANTENNA_POWER_SHIFT 0x3000000 +#define BRSSI_TABLE_SELECT 0xc000000 +#define BRXHP_FINAL 0x7000000 +#define BRXHPSETTLE_BBP 0x7 +#define BRXHTSETTLE_HSSI 0x8 +#define BRXHTSETTLE_RXHP 0x70 +#define BRXHTSETTLE_BBPPW 0x80 +#define BRXHTSETTLE_IDLE 0x300 +#define BRXHTSETTLE_RESERVED 0x1c00 +#define BRXHT_RXHP_EN 0x8000 +#define BRXAGC_FREEZE_THRES 0x30000 +#define BRXAGC_TOGETHEREN 0x40000 +#define BRXHTAGC_MIN 0x80000 +#define BRXHTAGC_EN 0x100000 +#define BRXHTDAGC_EN 0x200000 +#define BRXHT_RXHP_BBP 0x1c00000 +#define BRXHT_RXHP_FINAL 0xe0000000 +#define BRXPW_RADIO_TH 0x3 +#define BRXPW_RADIO_EN 0x4 +#define BRXMF_HOLD 0x3800 +#define BRXPD_DELAY_TH1 0x38 +#define BRXPD_DELAY_TH2 0x1c0 +#define BRXPD_DC_COUNT_MAX 0x600 +#define BRXPD_DELAY_TH 0x8000 +#define BRXPROCESS_DELAY 0xf0000 +#define BRXSEARCHRANGE_GI2_EARLY 0x700000 +#define BRXFRAME_FUARD_COUNTER_L 0x3800000 +#define BRXSGI_GUARD_L 0xc000000 +#define BRXSGI_SEARCH_L 0x30000000 +#define BRXSGI_TH 0xc0000000 +#define BDFSCNT0 0xff +#define BDFSCNT1 0xff00 +#define BDFSFLAG 0xf0000 +#define BMF_WEIGHT_SUM 0x300000 +#define BMINIDX_TH 0x7f000000 +#define BDAFORMAT 0x40000 +#define BTXCH_EMU_ENABLE 0x01000000 +#define BTRSW_ISOLATION_A 0x7f +#define BTRSW_ISOLATION_B 0x7f00 +#define BTRSW_ISOLATION_C 0x7f0000 +#define BTRSW_ISOLATION_D 0x7f000000 +#define BEXT_LNA_GAIN 0x7c00 + +#define BSTBC_EN 0x4 +#define BANTENNA_MAPPING 0x10 +#define BNSS 0x20 +#define BCFO_ANTSUM_ID 0x200 +#define BPHY_COUNTER_RESET 0x8000000 +#define BCFO_REPORT_GET 0x4000000 +#define BOFDM_CONTINUE_TX 0x10000000 +#define BOFDM_SINGLE_CARRIER 0x20000000 +#define BOFDM_SINGLE_TONE 0x40000000 +#define BHT_DETECT 0x100 +#define BCFOEN 0x10000 +#define BCFOVALUE 0xfff00000 +#define BSIGTONE_RE 0x3f +#define BSIGTONE_IM 0x7f00 +#define BCOUNTER_CCA 0xffff +#define BCOUNTER_PARITYFAIL 0xffff0000 +#define BCOUNTER_RATEILLEGAL 0xffff +#define BCOUNTER_CRC8FAIL 0xffff0000 +#define BCOUNTER_MCSNOSUPPORT 0xffff +#define BCOUNTER_FASTSYNC 0xffff +#define BSHORTCFO 0xfff +#define BSHORTCFOT_LENGTH 12 +#define BSHORTCFOF_LENGTH 11 +#define BLONGCFO 0x7ff +#define BLONGCFOT_LENGTH 11 +#define BLONGCFOF_LENGTH 11 +#define BTAILCFO 0x1fff +#define BTAILCFOT_LENGTH 13 +#define BTAILCFOF_LENGTH 12 +#define BNOISE_EN_PWDB 0xffff +#define BCC_POWER_DB 0xffff0000 +#define BMOISE_PWDB 0xffff +#define BPOWERMEAST_LENGTH 10 +#define BPOWERMEASF_LENGTH 3 +#define BRX_HT_BW 0x1 +#define BRXSC 0x6 +#define BRX_HT 0x8 +#define BNB_INTF_DET_ON 0x1 +#define BINTF_WIN_LEN_CFG 0x30 +#define BNB_INTF_TH_CFG 0x1c0 +#define BRFGAIN 0x3f +#define BTABLESEL 0x40 +#define BTRSW 0x80 +#define BRXSNR_A 0xff +#define BRXSNR_B 0xff00 +#define BRXSNR_C 0xff0000 +#define BRXSNR_D 0xff000000 +#define BSNR_EVMT_LENGTH 8 +#define BSNR_EVMF_LENGTH 1 +#define BCSI1ST 0xff +#define BCSI2ND 0xff00 +#define BRXEVM1ST 0xff0000 +#define BRXEVM2ND 0xff000000 +#define BSIGEVM 0xff +#define BPWDB 0xff00 +#define BSGIEN 0x10000 + +#define BSFACTOR_QMA1 0xf +#define BSFACTOR_QMA2 0xf0 +#define BSFACTOR_QMA3 0xf00 +#define BSFACTOR_QMA4 0xf000 +#define BSFACTOR_QMA5 0xf0000 +#define BSFACTOR_QMA6 0xf0000 +#define BSFACTOR_QMA7 0xf00000 +#define BSFACTOR_QMA8 0xf000000 +#define BSFACTOR_QMA9 0xf0000000 +#define BCSI_SCHEME 0x100000 + +#define BNOISE_LVL_TOP_SET 0x3 +#define BCHSMOOTH 0x4 +#define BCHSMOOTH_CFG1 0x38 +#define BCHSMOOTH_CFG2 0x1c0 +#define BCHSMOOTH_CFG3 0xe00 +#define BCHSMOOTH_CFG4 0x7000 +#define BMRCMODE 0x800000 +#define BTHEVMCFG 0x7000000 + +#define BLOOP_FIT_TYPE 0x1 +#define BUPD_CFO 0x40 +#define BUPD_CFO_OFFDATA 0x80 +#define BADV_UPD_CFO 0x100 +#define BADV_TIME_CTRL 0x800 +#define BUPD_CLKO 0x1000 +#define BFC 0x6000 +#define BTRACKING_MODE 0x8000 +#define BPHCMP_ENABLE 0x10000 +#define BUPD_CLKO_LTF 0x20000 +#define BCOM_CH_CFO 0x40000 +#define BCSI_ESTI_MODE 0x80000 +#define BADV_UPD_EQZ 0x100000 +#define BUCHCFG 0x7000000 +#define BUPDEQZ 0x8000000 + +#define BRX_PESUDO_NOISE_ON 0x20000000 +#define BRX_PESUDO_NOISE_A 0xff +#define BRX_PESUDO_NOISE_B 0xff00 +#define BRX_PESUDO_NOISE_C 0xff0000 +#define BRX_PESUDO_NOISE_D 0xff000000 +#define BRX_PESUDO_NOISESTATE_A 0xffff +#define BRX_PESUDO_NOISESTATE_B 0xffff0000 +#define BRX_PESUDO_NOISESTATE_C 0xffff +#define BRX_PESUDO_NOISESTATE_D 0xffff0000 + +#define BZEBRA1_HSSIENABLE 0x8 +#define BZEBRA1_TRXCONTROL 0xc00 +#define BZEBRA1_TRXGAINSETTING 0x07f +#define BZEBRA1_RXCOUNTER 0xc00 +#define BZEBRA1_TXCHANGEPUMP 0x38 +#define BZEBRA1_RXCHANGEPUMP 0x7 +#define BZEBRA1_CHANNEL_NUM 0xf80 +#define BZEBRA1_TXLPFBW 0x400 +#define BZEBRA1_RXLPFBW 0x600 + +#define BRTL8256REG_MODE_CTRL1 0x100 +#define BRTL8256REG_MODE_CTRL0 0x40 +#define BRTL8256REG_TXLPFBW 0x18 +#define BRTL8256REG_RXLPFBW 0x600 + +#define BRTL8258_TXLPFBW 0xc +#define BRTL8258_RXLPFBW 0xc00 +#define BRTL8258_RSSILPFBW 0xc0 + +#define BBYTE0 0x1 +#define BBYTE1 0x2 +#define BBYTE2 0x4 +#define BBYTE3 0x8 +#define BWORD0 0x3 +#define BWORD1 0xc +#define BWORD 0xf + +#define MASKBYTE0 0xff +#define MASKBYTE1 0xff00 +#define MASKBYTE2 0xff0000 +#define MASKBYTE3 0xff000000 +#define MASKHWORD 0xffff0000 +#define MASKLWORD 0x0000ffff +#define MASKDWORD 0xffffffff +#define MASK12BITS 0xfff +#define MASKH4BITS 0xf0000000 +#define MASKOFDM_D 0xffc00000 +#define MASKCCK 0x3f3f3f3f + +#define MASK4BITS 0x0f +#define MASK20BITS 0xfffff +#define RFREG_OFFSET_MASK 0xfffff + +#define BENABLE 0x1 +#define BDISABLE 0x0 + +#define LEFT_ANTENNA 0x0 +#define RIGHT_ANTENNA 0x1 + +#define TCHECK_TXSTATUS 500 +#define TUPDATE_RXCOUNTER 100 + +#define REG_UN_used_register 0x01bf + +/* WOL bit information */ +#define HAL92C_WOL_PTK_UPDATE_EVENT BIT(0) +#define HAL92C_WOL_GTK_UPDATE_EVENT BIT(1) +#define HAL92C_WOL_DISASSOC_EVENT BIT(2) +#define HAL92C_WOL_DEAUTH_EVENT BIT(3) +#define HAL92C_WOL_FW_DISCONNECT_EVENT BIT(4) + +#define WOL_REASON_PTK_UPDATE BIT(0) +#define WOL_REASON_GTK_UPDATE BIT(1) +#define WOL_REASON_DISASSOC BIT(2) +#define WOL_REASON_DEAUTH BIT(3) +#define WOL_REASON_FW_DISCONNECT BIT(4) + +/* 2 EFUSE_TEST (For RTL8723 partially) */ +#define EFUSE_SEL(x) (((x) & 0x3) << 8) +#define EFUSE_SEL_MASK 0x300 +#define EFUSE_WIFI_SEL_0 0x0 + +#define WL_HWPDN_EN BIT(0) /* Enable GPIO[9] as WiFi HW PDn source*/ +#define WL_HWPDN_SL BIT(1) /* WiFi HW PDn polarity control*/ + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/rf.c b/drivers/net/wireless/rtlwifi/rtl8723be/rf.c new file mode 100644 index 000000000000..486294930a7b --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/rf.c @@ -0,0 +1,504 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" + +static bool _rtl8723be_phy_rf6052_config_parafile(struct ieee80211_hw *hw); + +void rtl8723be_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + switch (bandwidth) { + case HT_CHANNEL_WIDTH_20: + rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] & + 0xfffff3ff) | BIT(10) | BIT(11)); + rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, + rtlphy->rfreg_chnlval[0]); + break; + case HT_CHANNEL_WIDTH_20_40: + rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] & + 0xfffff3ff) | BIT(10)); + rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, + rtlphy->rfreg_chnlval[0]); + break; + default: + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + "unknown bandwidth: %#X\n", bandwidth); + break; + } +} + +void rtl8723be_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u32 tx_agc[2] = {0, 0}, tmpval; + bool turbo_scanoff = false; + u8 idx1, idx2; + u8 *ptr; + u8 direction; + u32 pwrtrac_value; + + if (rtlefuse->eeprom_regulatory != 0) + turbo_scanoff = true; + + if (mac->act_scanning) { + tx_agc[RF90_PATH_A] = 0x3f3f3f3f; + tx_agc[RF90_PATH_B] = 0x3f3f3f3f; + + if (turbo_scanoff) { + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + tx_agc[idx1] = ppowerlevel[idx1] | + (ppowerlevel[idx1] << 8) | + (ppowerlevel[idx1] << 16) | + (ppowerlevel[idx1] << 24); + } + } + } else { + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + tx_agc[idx1] = ppowerlevel[idx1] | + (ppowerlevel[idx1] << 8) | + (ppowerlevel[idx1] << 16) | + (ppowerlevel[idx1] << 24); + } + if (rtlefuse->eeprom_regulatory == 0) { + tmpval = + (rtlphy->mcs_offset[0][6]) + + (rtlphy->mcs_offset[0][7] << 8); + tx_agc[RF90_PATH_A] += tmpval; + + tmpval = (rtlphy->mcs_offset[0][14]) + + (rtlphy->mcs_offset[0][15] << + 24); + tx_agc[RF90_PATH_B] += tmpval; + } + } + for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { + ptr = (u8 *)(&(tx_agc[idx1])); + for (idx2 = 0; idx2 < 4; idx2++) { + if (*ptr > RF6052_MAX_TX_PWR) + *ptr = RF6052_MAX_TX_PWR; + ptr++; + } + } + rtl8723be_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value); + if (direction == 1) { + tx_agc[0] += pwrtrac_value; + tx_agc[1] += pwrtrac_value; + } else if (direction == 2) { + tx_agc[0] -= pwrtrac_value; + tx_agc[1] -= pwrtrac_value; + } + tmpval = tx_agc[RF90_PATH_A] & 0xff; + rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", tmpval, + RTXAGC_A_CCK1_MCS32); + + tmpval = tx_agc[RF90_PATH_A] >> 8; + + rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval, + RTXAGC_B_CCK11_A_CCK2_11); + + tmpval = tx_agc[RF90_PATH_B] >> 24; + rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval, + RTXAGC_B_CCK11_A_CCK2_11); + + tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff; + rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n", tmpval, + RTXAGC_B_CCK1_55_MCS32); +} + +static void rtl8723be_phy_get_power_base(struct ieee80211_hw *hw, + u8 *ppowerlevel_ofdm, + u8 *ppowerlevel_bw20, + u8 *ppowerlevel_bw40, + u8 channel, u32 *ofdmbase, + u32 *mcsbase) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 powerbase0, powerbase1; + u8 i, powerlevel[2]; + + for (i = 0; i < 2; i++) { + powerbase0 = ppowerlevel_ofdm[i]; + + powerbase0 = (powerbase0 << 24) | (powerbase0 << 16) | + (powerbase0 << 8) | powerbase0; + *(ofdmbase + i) = powerbase0; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + " [OFDM power base index rf(%c) = 0x%x]\n", + ((i == 0) ? 'A' : 'B'), *(ofdmbase + i)); + } + + for (i = 0; i < 2; i++) { + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) + powerlevel[i] = ppowerlevel_bw20[i]; + else + powerlevel[i] = ppowerlevel_bw40[i]; + powerbase1 = powerlevel[i]; + powerbase1 = (powerbase1 << 24) | (powerbase1 << 16) | + (powerbase1 << 8) | powerbase1; + + *(mcsbase + i) = powerbase1; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + " [MCS power base index rf(%c) = 0x%x]\n", + ((i == 0) ? 'A' : 'B'), *(mcsbase + i)); + } +} + +static void txpwr_by_regulatory(struct ieee80211_hw *hw, u8 channel, u8 index, + u32 *powerbase0, u32 *powerbase1, + u32 *p_outwriteval) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 i, chnlgroup = 0, pwr_diff_limit[4]; + u8 pwr_diff = 0, customer_pwr_diff; + u32 writeval, customer_limit, rf; + + for (rf = 0; rf < 2; rf++) { + switch (rtlefuse->eeprom_regulatory) { + case 0: + chnlgroup = 0; + + writeval = + rtlphy->mcs_offset[chnlgroup][index + (rf ? 8 : 0)] + + ((index < 2) ? powerbase0[rf] : powerbase1[rf]); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "RTK better performance, " + "writeval(%c) = 0x%x\n", + ((rf == 0) ? 'A' : 'B'), writeval); + break; + case 1: + if (rtlphy->pwrgroup_cnt == 1) { + chnlgroup = 0; + } else { + if (channel < 3) + chnlgroup = 0; + else if (channel < 6) + chnlgroup = 1; + else if (channel < 9) + chnlgroup = 2; + else if (channel < 12) + chnlgroup = 3; + else if (channel < 14) + chnlgroup = 4; + else if (channel == 14) + chnlgroup = 5; + } + writeval = rtlphy->mcs_offset[chnlgroup] + [index + (rf ? 8 : 0)] + ((index < 2) ? + powerbase0[rf] : + powerbase1[rf]); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Realtek regulatory, 20MHz, " + "writeval(%c) = 0x%x\n", + ((rf == 0) ? 'A' : 'B'), writeval); + + break; + case 2: + writeval = + ((index < 2) ? powerbase0[rf] : powerbase1[rf]); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Better regulatory, " + "writeval(%c) = 0x%x\n", + ((rf == 0) ? 'A' : 'B'), writeval); + break; + case 3: + chnlgroup = 0; + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "customer's limit, 40MHz " + "rf(%c) = 0x%x\n", + ((rf == 0) ? 'A' : 'B'), + rtlefuse->pwrgroup_ht40[rf] + [channel-1]); + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "customer's limit, 20MHz " + "rf(%c) = 0x%x\n", + ((rf == 0) ? 'A' : 'B'), + rtlefuse->pwrgroup_ht20[rf] + [channel-1]); + } + + if (index < 2) + pwr_diff = + rtlefuse->txpwr_legacyhtdiff[rf][channel-1]; + else if (rtlphy->current_chan_bw == + HT_CHANNEL_WIDTH_20) + pwr_diff = + rtlefuse->txpwr_ht20diff[rf][channel-1]; + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) + customer_pwr_diff = + rtlefuse->pwrgroup_ht40[rf][channel-1]; + else + customer_pwr_diff = + rtlefuse->pwrgroup_ht20[rf][channel-1]; + + if (pwr_diff > customer_pwr_diff) + pwr_diff = 0; + else + pwr_diff = customer_pwr_diff - pwr_diff; + + for (i = 0; i < 4; i++) { + pwr_diff_limit[i] = + (u8)((rtlphy->mcs_offset + [chnlgroup][index + (rf ? 8 : 0)] & + (0x7f << (i * 8))) >> (i * 8)); + + if (pwr_diff_limit[i] > pwr_diff) + pwr_diff_limit[i] = pwr_diff; + } + + customer_limit = (pwr_diff_limit[3] << 24) | + (pwr_diff_limit[2] << 16) | + (pwr_diff_limit[1] << 8) | + (pwr_diff_limit[0]); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Customer's limit rf(%c) = 0x%x\n", + ((rf == 0) ? 'A' : 'B'), customer_limit); + + writeval = customer_limit + ((index < 2) ? + powerbase0[rf] : + powerbase1[rf]); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Customer, writeval rf(%c)= 0x%x\n", + ((rf == 0) ? 'A' : 'B'), writeval); + break; + default: + chnlgroup = 0; + writeval = + rtlphy->mcs_offset[chnlgroup] + [index + (rf ? 8 : 0)] + + ((index < 2) ? powerbase0[rf] : powerbase1[rf]); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "RTK better performance, writeval " + "rf(%c) = 0x%x\n", + ((rf == 0) ? 'A' : 'B'), writeval); + break; + } + + if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1) + writeval = writeval - 0x06060606; + else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TXHIGHPWRLEVEL_BT2) + writeval = writeval - 0x0c0c0c0c; + *(p_outwriteval + rf) = writeval; + } +} + +static void _rtl8723be_write_ofdm_power_reg(struct ieee80211_hw *hw, + u8 index, u32 *value) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 regoffset_a[6] = { + RTXAGC_A_RATE18_06, RTXAGC_A_RATE54_24, + RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04, + RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12 + }; + u16 regoffset_b[6] = { + RTXAGC_B_RATE18_06, RTXAGC_B_RATE54_24, + RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04, + RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12 + }; + u8 i, rf, pwr_val[4]; + u32 writeval; + u16 regoffset; + + for (rf = 0; rf < 2; rf++) { + writeval = value[rf]; + for (i = 0; i < 4; i++) { + pwr_val[i] = (u8) ((writeval & (0x7f << + (i * 8))) >> (i * 8)); + + if (pwr_val[i] > RF6052_MAX_TX_PWR) + pwr_val[i] = RF6052_MAX_TX_PWR; + } + writeval = (pwr_val[3] << 24) | (pwr_val[2] << 16) | + (pwr_val[1] << 8) | pwr_val[0]; + + if (rf == 0) + regoffset = regoffset_a[index]; + else + regoffset = regoffset_b[index]; + rtl_set_bbreg(hw, regoffset, MASKDWORD, writeval); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "Set 0x%x = %08x\n", regoffset, writeval); + } +} + +void rtl8723be_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel_ofdm, + u8 *ppowerlevel_bw20, + u8 *ppowerlevel_bw40, u8 channel) +{ + u32 writeval[2], powerbase0[2], powerbase1[2]; + u8 index; + u8 direction; + u32 pwrtrac_value; + + rtl8723be_phy_get_power_base(hw, ppowerlevel_ofdm, ppowerlevel_bw20, + ppowerlevel_bw40, channel, + &powerbase0[0], &powerbase1[0]); + + rtl8723be_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value); + + for (index = 0; index < 6; index++) { + txpwr_by_regulatory(hw, channel, index, &powerbase0[0], + &powerbase1[0], &writeval[0]); + if (direction == 1) { + writeval[0] += pwrtrac_value; + writeval[1] += pwrtrac_value; + } else if (direction == 2) { + writeval[0] -= pwrtrac_value; + writeval[1] -= pwrtrac_value; + } + _rtl8723be_write_ofdm_power_reg(hw, index, &writeval[0]); + } +} + +bool rtl8723be_phy_rf6052_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + if (rtlphy->rf_type == RF_1T1R) + rtlphy->num_total_rfpath = 1; + else + rtlphy->num_total_rfpath = 2; + + return _rtl8723be_phy_rf6052_config_parafile(hw); +} + +static bool _rtl8723be_phy_rf6052_config_parafile(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct bb_reg_def *pphyreg; + u32 u4_regvalue = 0; + u8 rfpath; + bool rtstatus = true; + + for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { + pphyreg = &rtlphy->phyreg_def[rfpath]; + + switch (rfpath) { + case RF90_PATH_A: + case RF90_PATH_C: + u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs, + BRFSI_RFENV); + break; + case RF90_PATH_B: + case RF90_PATH_D: + u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs, + BRFSI_RFENV << 16); + break; + } + + rtl_set_bbreg(hw, pphyreg->rfintfe, BRFSI_RFENV << 16, 0x1); + udelay(1); + + rtl_set_bbreg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1); + udelay(1); + + rtl_set_bbreg(hw, pphyreg->rfhssi_para2, + B3WIREADDREAALENGTH, 0x0); + udelay(1); + + rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREDATALENGTH, 0x0); + udelay(1); + + switch (rfpath) { + case RF90_PATH_A: + rtstatus = rtl8723be_phy_config_rf_with_headerfile(hw, + (enum radio_path)rfpath); + break; + case RF90_PATH_B: + rtstatus = rtl8723be_phy_config_rf_with_headerfile(hw, + (enum radio_path)rfpath); + break; + case RF90_PATH_C: + break; + case RF90_PATH_D: + break; + } + + switch (rfpath) { + case RF90_PATH_A: + case RF90_PATH_C: + rtl_set_bbreg(hw, pphyreg->rfintfs, + BRFSI_RFENV, u4_regvalue); + break; + case RF90_PATH_B: + case RF90_PATH_D: + rtl_set_bbreg(hw, pphyreg->rfintfs, + BRFSI_RFENV << 16, u4_regvalue); + break; + } + + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "Radio[%d] Fail!!", rfpath); + return false; + } + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "\n"); + return rtstatus; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/rf.h b/drivers/net/wireless/rtlwifi/rtl8723be/rf.h new file mode 100644 index 000000000000..a6fea106ced4 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/rf.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8723BE_RF_H__ +#define __RTL8723BE_RF_H__ + +#define RF6052_MAX_TX_PWR 0x3F +#define RF6052_MAX_REG 0x3F + +void rtl8723be_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, + u8 bandwidth); +void rtl8723be_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel); +void rtl8723be_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel_ofdm, + u8 *ppowerlevel_bw20, + u8 *ppowerlevel_bw40, + u8 channel); +bool rtl8723be_phy_rf6052_config(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c new file mode 100644 index 000000000000..7834ae577b52 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c @@ -0,0 +1,385 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../core.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "../rtl8723com/phy_common.h" +#include "dm.h" +#include "hw.h" +#include "fw.h" +#include "../rtl8723com/fw_common.h" +#include "sw.h" +#include "trx.h" +#include "led.h" +#include "table.h" +#include "../btcoexist/rtl_btc.h" + +#include +#include + +static void rtl8723be_init_aspm_vars(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + /*close ASPM for AMD defaultly */ + rtlpci->const_amdpci_aspm = 0; + + /* ASPM PS mode. + * 0 - Disable ASPM, + * 1 - Enable ASPM without Clock Req, + * 2 - Enable ASPM with Clock Req, + * 3 - Alwyas Enable ASPM with Clock Req, + * 4 - Always Enable ASPM without Clock Req. + * set defult to RTL8192CE:3 RTL8192E:2 + */ + rtlpci->const_pci_aspm = 3; + + /*Setting for PCI-E device */ + rtlpci->const_devicepci_aspm_setting = 0x03; + + /*Setting for PCI-E bridge */ + rtlpci->const_hostpci_aspm_setting = 0x02; + + /* In Hw/Sw Radio Off situation. + * 0 - Default, + * 1 - From ASPM setting without low Mac Pwr, + * 2 - From ASPM setting with low Mac Pwr, + * 3 - Bus D3 + * set default to RTL8192CE:0 RTL8192SE:2 + */ + rtlpci->const_hwsw_rfoff_d3 = 0; + + /* This setting works for those device with + * backdoor ASPM setting such as EPHY setting. + * 0 - Not support ASPM, + * 1 - Support ASPM, + * 2 - According to chipset. + */ + rtlpci->const_support_pciaspm = 1; +} + +int rtl8723be_init_sw_vars(struct ieee80211_hw *hw) +{ + int err = 0; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + rtl8723be_bt_reg_init(hw); + rtlpci->msi_support = true; + rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer(); + + rtlpriv->dm.dm_initialgain_enable = 1; + rtlpriv->dm.dm_flag = 0; + rtlpriv->dm.disable_framebursting = 0; + rtlpriv->dm.thermalvalue = 0; + rtlpci->transmit_config = CFENDFORM | BIT(15) | BIT(24) | BIT(25); + + mac->ht_enable = true; + + /* compatible 5G band 88ce just 2.4G band & smsp */ + rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G; + rtlpriv->rtlhal.bandset = BAND_ON_2_4G; + rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY; + + rtlpci->receive_config = (RCR_APPFCS | + RCR_APP_MIC | + RCR_APP_ICV | + RCR_APP_PHYST_RXFF | + RCR_HTC_LOC_CTRL | + RCR_AMF | + RCR_ACF | + RCR_ADF | + RCR_AICV | + RCR_AB | + RCR_AM | + RCR_APM | + 0); + + rtlpci->irq_mask[0] = (u32) (IMR_PSTIMEOUT | + IMR_HSISR_IND_ON_INT | + IMR_C2HCMD | + IMR_HIGHDOK | + IMR_MGNTDOK | + IMR_BKDOK | + IMR_BEDOK | + IMR_VIDOK | + IMR_VODOK | + IMR_RDU | + IMR_ROK | + 0); + + rtlpci->irq_mask[1] = (u32)(IMR_RXFOVW | 0); + + /* for debug level */ + rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug; + /* for LPS & IPS */ + rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; + rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; + rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + rtlpriv->psc.reg_fwctrl_lps = 3; + rtlpriv->psc.reg_max_lps_awakeintvl = 5; + /* for ASPM, you can close aspm through + * set const_support_pciaspm = 0 + */ + rtl8723be_init_aspm_vars(hw); + + if (rtlpriv->psc.reg_fwctrl_lps == 1) + rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 2) + rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 3) + rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE; + + /* for firmware buf */ + rtlpriv->rtlhal.pfirmware = vzalloc(0x8000); + if (!rtlpriv->rtlhal.pfirmware) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Can't alloc buffer for fw.\n"); + return 1; + } + + rtlpriv->max_fw_size = 0x8000; + pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name); + err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name, + rtlpriv->io.dev, GFP_KERNEL, hw, + rtl_fw_cb); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Failed to request firmware!\n"); + return 1; + } + return 0; +} + +void rtl8723be_deinit_sw_vars(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_halt_notify(); + if (rtlpriv->rtlhal.pfirmware) { + vfree(rtlpriv->rtlhal.pfirmware); + rtlpriv->rtlhal.pfirmware = NULL; + } +} + +/* get bt coexist status */ +bool rtl8723be_get_btc_status(void) +{ + return true; +} + +static bool is_fw_header(struct rtl92c_firmware_header *hdr) +{ + return (hdr->signature & 0xfff0) == 0x5300; +} + +static struct rtl_hal_ops rtl8723be_hal_ops = { + .init_sw_vars = rtl8723be_init_sw_vars, + .deinit_sw_vars = rtl8723be_deinit_sw_vars, + .read_eeprom_info = rtl8723be_read_eeprom_info, + .interrupt_recognized = rtl8723be_interrupt_recognized, + .hw_init = rtl8723be_hw_init, + .hw_disable = rtl8723be_card_disable, + .hw_suspend = rtl8723be_suspend, + .hw_resume = rtl8723be_resume, + .enable_interrupt = rtl8723be_enable_interrupt, + .disable_interrupt = rtl8723be_disable_interrupt, + .set_network_type = rtl8723be_set_network_type, + .set_chk_bssid = rtl8723be_set_check_bssid, + .set_qos = rtl8723be_set_qos, + .set_bcn_reg = rtl8723be_set_beacon_related_registers, + .set_bcn_intv = rtl8723be_set_beacon_interval, + .update_interrupt_mask = rtl8723be_update_interrupt_mask, + .get_hw_reg = rtl8723be_get_hw_reg, + .set_hw_reg = rtl8723be_set_hw_reg, + .update_rate_tbl = rtl8723be_update_hal_rate_tbl, + .fill_tx_desc = rtl8723be_tx_fill_desc, + .fill_tx_cmddesc = rtl8723be_tx_fill_cmddesc, + .query_rx_desc = rtl8723be_rx_query_desc, + .set_channel_access = rtl8723be_update_channel_access_setting, + .radio_onoff_checking = rtl8723be_gpio_radio_on_off_checking, + .set_bw_mode = rtl8723be_phy_set_bw_mode, + .switch_channel = rtl8723be_phy_sw_chnl, + .dm_watchdog = rtl8723be_dm_watchdog, + .scan_operation_backup = rtl8723be_phy_scan_operation_backup, + .set_rf_power_state = rtl8723be_phy_set_rf_power_state, + .led_control = rtl8723be_led_control, + .set_desc = rtl8723be_set_desc, + .get_desc = rtl8723be_get_desc, + .is_tx_desc_closed = rtl8723be_is_tx_desc_closed, + .tx_polling = rtl8723be_tx_polling, + .enable_hw_sec = rtl8723be_enable_hw_security_config, + .set_key = rtl8723be_set_key, + .init_sw_leds = rtl8723be_init_sw_leds, + .allow_all_destaddr = rtl8723be_allow_all_destaddr, + .get_bbreg = rtl8723_phy_query_bb_reg, + .set_bbreg = rtl8723_phy_set_bb_reg, + .get_rfreg = rtl8723be_phy_query_rf_reg, + .set_rfreg = rtl8723be_phy_set_rf_reg, + .fill_h2c_cmd = rtl8723be_fill_h2c_cmd, + .get_btc_status = rtl8723be_get_btc_status, + .is_fw_header = is_fw_header, +}; + +static struct rtl_mod_params rtl8723be_mod_params = { + .sw_crypto = false, + .inactiveps = true, + .swctrl_lps = false, + .fwctrl_lps = true, + .debug = DBG_EMERG, +}; + +static struct rtl_hal_cfg rtl8723be_hal_cfg = { + .bar_id = 2, + .write_readback = true, + .name = "rtl8723be_pci", + .fw_name = "rtlwifi/rtl8723befw.bin", + .ops = &rtl8723be_hal_ops, + .mod_params = &rtl8723be_mod_params, + .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL, + .maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN, + .maps[SYS_CLK] = REG_SYS_CLKR, + .maps[MAC_RCR_AM] = AM, + .maps[MAC_RCR_AB] = AB, + .maps[MAC_RCR_ACRC32] = ACRC32, + .maps[MAC_RCR_ACF] = ACF, + .maps[MAC_RCR_AAP] = AAP, + + .maps[EFUSE_ACCESS] = REG_EFUSE_ACCESS, + + .maps[EFUSE_TEST] = REG_EFUSE_TEST, + .maps[EFUSE_CTRL] = REG_EFUSE_CTRL, + .maps[EFUSE_CLK] = 0, + .maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL, + .maps[EFUSE_PWC_EV12V] = PWC_EV12V, + .maps[EFUSE_FEN_ELDR] = FEN_ELDR, + .maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN, + .maps[EFUSE_ANA8M] = ANA8M, + .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE, + .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION, + .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN, + .maps[EFUSE_OOB_PROTECT_BYTES_LEN] = EFUSE_OOB_PROTECT_BYTES, + + .maps[RWCAM] = REG_CAMCMD, + .maps[WCAMI] = REG_CAMWRITE, + .maps[RCAMO] = REG_CAMREAD, + .maps[CAMDBG] = REG_CAMDBG, + .maps[SECR] = REG_SECCFG, + .maps[SEC_CAM_NONE] = CAM_NONE, + .maps[SEC_CAM_WEP40] = CAM_WEP40, + .maps[SEC_CAM_TKIP] = CAM_TKIP, + .maps[SEC_CAM_AES] = CAM_AES, + .maps[SEC_CAM_WEP104] = CAM_WEP104, + + .maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6, + .maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5, + .maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4, + .maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3, + .maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2, + .maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1, + .maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7, + .maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6, + .maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5, + .maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4, + .maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3, + .maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2, + .maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1, + + .maps[RTL_IMR_TXFOVW] = IMR_TXFOVW, + .maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT, + .maps[RTL_IMR_BCNINT] = IMR_BCNDMAINT0, + .maps[RTL_IMR_RXFOVW] = IMR_RXFOVW, + .maps[RTL_IMR_RDU] = IMR_RDU, + .maps[RTL_IMR_ATIMEND] = IMR_ATIMEND, + .maps[RTL_IMR_BDOK] = IMR_BCNDOK0, + .maps[RTL_IMR_MGNTDOK] = IMR_MGNTDOK, + .maps[RTL_IMR_TBDER] = IMR_TBDER, + .maps[RTL_IMR_HIGHDOK] = IMR_HIGHDOK, + .maps[RTL_IMR_TBDOK] = IMR_TBDOK, + .maps[RTL_IMR_BKDOK] = IMR_BKDOK, + .maps[RTL_IMR_BEDOK] = IMR_BEDOK, + .maps[RTL_IMR_VIDOK] = IMR_VIDOK, + .maps[RTL_IMR_VODOK] = IMR_VODOK, + .maps[RTL_IMR_ROK] = IMR_ROK, + .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNDMAINT0 | IMR_TBDOK | IMR_TBDER), + + .maps[RTL_RC_CCK_RATE1M] = DESC92C_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC92C_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC92C_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC92C_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC92C_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC92C_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC92C_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC92C_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC92C_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC92C_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC92C_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC92C_RATE54M, + + .maps[RTL_RC_HT_RATEMCS7] = DESC92C_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15, +}; + +static DEFINE_PCI_DEVICE_TABLE(rtl8723be_pci_id) = { + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xb723, rtl8723be_hal_cfg)}, + {}, +}; + +MODULE_DEVICE_TABLE(pci, rtl8723be_pci_id); + +MODULE_AUTHOR("PageHe "); +MODULE_AUTHOR("Realtek WlanFAE "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 8723BE 802.11n PCI wireless"); +MODULE_FIRMWARE("rtlwifi/rtl8723befw.bin"); + +module_param_named(swenc, rtl8723be_mod_params.sw_crypto, bool, 0444); +module_param_named(debug, rtl8723be_mod_params.debug, int, 0444); +module_param_named(ips, rtl8723be_mod_params.inactiveps, bool, 0444); +module_param_named(swlps, rtl8723be_mod_params.swctrl_lps, bool, 0444); +module_param_named(fwlps, rtl8723be_mod_params.fwctrl_lps, bool, 0444); +MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n"); +MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n"); +MODULE_PARM_DESC(fwlps, "using linked fw control power save (default 1 is open)\n"); +MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); + +static const SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); + +static struct pci_driver rtl8723be_driver = { + .name = KBUILD_MODNAME, + .id_table = rtl8723be_pci_id, + .probe = rtl_pci_probe, + .remove = rtl_pci_disconnect, + + .driver.pm = &rtlwifi_pm_ops, +}; + +module_pci_driver(rtl8723be_driver); diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.h b/drivers/net/wireless/rtlwifi/rtl8723be/sw.h new file mode 100644 index 000000000000..a7b25e769950 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/sw.h @@ -0,0 +1,35 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8723BE_SW_H__ +#define __RTL8723BE_SW_H__ + +int rtl8723be_init_sw_vars(struct ieee80211_hw *hw); +void rtl8723be_deinit_sw_vars(struct ieee80211_hw *hw); +void rtl8723be_init_var_map(struct ieee80211_hw *hw); +bool rtl8723be_get_btc_status(void); + + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/table.c b/drivers/net/wireless/rtlwifi/rtl8723be/table.c new file mode 100644 index 000000000000..4b283cde042e --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/table.c @@ -0,0 +1,572 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Created on 2010/ 5/18, 1:41 + * + * Larry Finger + * + *****************************************************************************/ + +#include "table.h" +u32 RTL8723BEPHY_REG_1TARRAY[] = { + 0x800, 0x80040000, + 0x804, 0x00000003, + 0x808, 0x0000FC00, + 0x80C, 0x0000000A, + 0x810, 0x10001331, + 0x814, 0x020C3D10, + 0x818, 0x02200385, + 0x81C, 0x00000000, + 0x820, 0x01000100, + 0x824, 0x00390204, + 0x828, 0x00000000, + 0x82C, 0x00000000, + 0x830, 0x00000000, + 0x834, 0x00000000, + 0x838, 0x00000000, + 0x83C, 0x00000000, + 0x840, 0x00010000, + 0x844, 0x00000000, + 0x848, 0x00000000, + 0x84C, 0x00000000, + 0x850, 0x00000000, + 0x854, 0x00000000, + 0x858, 0x569A11A9, + 0x85C, 0x01000014, + 0x860, 0x66F60110, + 0x864, 0x061F0649, + 0x868, 0x00000000, + 0x86C, 0x27272700, + 0x870, 0x07000760, + 0x874, 0x25004000, + 0x878, 0x00000808, + 0x87C, 0x00000000, + 0x880, 0xB0000C1C, + 0x884, 0x00000001, + 0x888, 0x00000000, + 0x88C, 0xCCC000C0, + 0x890, 0x00000800, + 0x894, 0xFFFFFFFE, + 0x898, 0x40302010, + 0x89C, 0x00706050, + 0x900, 0x00000000, + 0x904, 0x00000023, + 0x908, 0x00000000, + 0x90C, 0x81121111, + 0x910, 0x00000002, + 0x914, 0x00000201, + 0x948, 0x00000000, + 0xA00, 0x00D047C8, + 0xA04, 0x80FF000C, + 0xA08, 0x8C838300, + 0xA0C, 0x2E7F120F, + 0xA10, 0x9500BB78, + 0xA14, 0x1114D028, + 0xA18, 0x00881117, + 0xA1C, 0x89140F00, + 0xA20, 0x1A1B0000, + 0xA24, 0x090E1317, + 0xA28, 0x00000204, + 0xA2C, 0x00D30000, + 0xA70, 0x101FBF00, + 0xA74, 0x00000007, + 0xA78, 0x00000900, + 0xA7C, 0x225B0606, + 0xA80, 0x21806490, + 0xB2C, 0x00000000, + 0xC00, 0x48071D40, + 0xC04, 0x03A05611, + 0xC08, 0x000000E4, + 0xC0C, 0x6C6C6C6C, + 0xC10, 0x08800000, + 0xC14, 0x40000100, + 0xC18, 0x08800000, + 0xC1C, 0x40000100, + 0xC20, 0x00000000, + 0xC24, 0x00000000, + 0xC28, 0x00000000, + 0xC2C, 0x00000000, + 0xC30, 0x69E9AC44, + 0xC34, 0x469652AF, + 0xC38, 0x49795994, + 0xC3C, 0x0A97971C, + 0xC40, 0x1F7C403F, + 0xC44, 0x000100B7, + 0xC48, 0xEC020107, + 0xC4C, 0x007F037F, + 0xC50, 0x69553420, + 0xC54, 0x43BC0094, + 0xC58, 0x00023169, + 0xC5C, 0x00250492, + 0xC60, 0x00000000, + 0xC64, 0x7112848B, + 0xC68, 0x47C00BFF, + 0xC6C, 0x00000036, + 0xC70, 0x2C7F000D, + 0xC74, 0x020610DB, + 0xC78, 0x0000001F, + 0xC7C, 0x00B91612, + 0xC80, 0x390000E4, + 0xC84, 0x20F60000, + 0xC88, 0x40000100, + 0xC8C, 0x20200000, + 0xC90, 0x00020E1A, + 0xC94, 0x00000000, + 0xC98, 0x00020E1A, + 0xC9C, 0x00007F7F, + 0xCA0, 0x00000000, + 0xCA4, 0x000300A0, + 0xCA8, 0x00000000, + 0xCAC, 0x00000000, + 0xCB0, 0x00000000, + 0xCB4, 0x00000000, + 0xCB8, 0x00000000, + 0xCBC, 0x28000000, + 0xCC0, 0x00000000, + 0xCC4, 0x00000000, + 0xCC8, 0x00000000, + 0xCCC, 0x00000000, + 0xCD0, 0x00000000, + 0xCD4, 0x00000000, + 0xCD8, 0x64B22427, + 0xCDC, 0x00766932, + 0xCE0, 0x00222222, + 0xCE4, 0x00000000, + 0xCE8, 0x37644302, + 0xCEC, 0x2F97D40C, + 0xD00, 0x00000740, + 0xD04, 0x40020401, + 0xD08, 0x0000907F, + 0xD0C, 0x20010201, + 0xD10, 0xA0633333, + 0xD14, 0x3333BC53, + 0xD18, 0x7A8F5B6F, + 0xD2C, 0xCC979975, + 0xD30, 0x00000000, + 0xD34, 0x80608000, + 0xD38, 0x00000000, + 0xD3C, 0x00127353, + 0xD40, 0x00000000, + 0xD44, 0x00000000, + 0xD48, 0x00000000, + 0xD4C, 0x00000000, + 0xD50, 0x6437140A, + 0xD54, 0x00000000, + 0xD58, 0x00000282, + 0xD5C, 0x30032064, + 0xD60, 0x4653DE68, + 0xD64, 0x04518A3C, + 0xD68, 0x00002101, + 0xD6C, 0x2A201C16, + 0xD70, 0x1812362E, + 0xD74, 0x322C2220, + 0xD78, 0x000E3C24, + 0xE00, 0x2D2D2D2D, + 0xE04, 0x2D2D2D2D, + 0xE08, 0x0390272D, + 0xE10, 0x2D2D2D2D, + 0xE14, 0x2D2D2D2D, + 0xE18, 0x2D2D2D2D, + 0xE1C, 0x2D2D2D2D, + 0xE28, 0x00000000, + 0xE30, 0x1000DC1F, + 0xE34, 0x10008C1F, + 0xE38, 0x02140102, + 0xE3C, 0x681604C2, + 0xE40, 0x01007C00, + 0xE44, 0x01004800, + 0xE48, 0xFB000000, + 0xE4C, 0x000028D1, + 0xE50, 0x1000DC1F, + 0xE54, 0x10008C1F, + 0xE58, 0x02140102, + 0xE5C, 0x28160D05, + 0xE60, 0x00000008, + 0xE68, 0x001B2556, + 0xE6C, 0x00C00096, + 0xE70, 0x00C00096, + 0xE74, 0x01000056, + 0xE78, 0x01000014, + 0xE7C, 0x01000056, + 0xE80, 0x01000014, + 0xE84, 0x00C00096, + 0xE88, 0x01000056, + 0xE8C, 0x00C00096, + 0xED0, 0x00C00096, + 0xED4, 0x00C00096, + 0xED8, 0x00C00096, + 0xEDC, 0x000000D6, + 0xEE0, 0x000000D6, + 0xEEC, 0x01C00016, + 0xF14, 0x00000003, + 0xF4C, 0x00000000, + 0xF00, 0x00000300, + 0x820, 0x01000100, + 0x800, 0x83040000, +}; + +u32 RTL8723BEPHY_REG_ARRAY_PG[] = { + 0, 0, 0, 0x00000e08, 0x0000ff00, 0x00004000, + 0, 0, 0, 0x0000086c, 0xffffff00, 0x34363800, + 0, 0, 0, 0x00000e00, 0xffffffff, 0x42444646, + 0, 0, 0, 0x00000e04, 0xffffffff, 0x30343840, + 0, 0, 0, 0x00000e10, 0xffffffff, 0x38404244, + 0, 0, 0, 0x00000e14, 0xffffffff, 0x26303436 +}; + +u32 RTL8723BE_RADIOA_1TARRAY[] = { + 0x000, 0x00010000, + 0x0B0, 0x000DFFE0, + 0x0FE, 0x00000000, + 0x0FE, 0x00000000, + 0x0FE, 0x00000000, + 0x0B1, 0x00000018, + 0x0FE, 0x00000000, + 0x0FE, 0x00000000, + 0x0FE, 0x00000000, + 0x0B2, 0x00084C00, + 0x0B5, 0x0000D2CC, + 0x0B6, 0x000925AA, + 0x0B7, 0x00000010, + 0x0B8, 0x0000907F, + 0x05C, 0x00000002, + 0x07C, 0x00000002, + 0x07E, 0x00000005, + 0x08B, 0x0006FC00, + 0x0B0, 0x000FF9F0, + 0x01C, 0x000739D2, + 0x01E, 0x00000000, + 0x0DF, 0x00000780, + 0x050, 0x00067435, + 0x051, 0x0006B04E, + 0x052, 0x000007D2, + 0x053, 0x00000000, + 0x054, 0x00050400, + 0x055, 0x0004026E, + 0x0DD, 0x0000004C, + 0x070, 0x00067435, + 0x071, 0x0006B04E, + 0x072, 0x000007D2, + 0x073, 0x00000000, + 0x074, 0x00050400, + 0x075, 0x0004026E, + 0x0EF, 0x00000100, + 0x034, 0x0000ADD7, + 0x035, 0x00005C00, + 0x034, 0x00009DD4, + 0x035, 0x00005000, + 0x034, 0x00008DD1, + 0x035, 0x00004400, + 0x034, 0x00007DCE, + 0x035, 0x00003800, + 0x034, 0x00006CD1, + 0x035, 0x00004400, + 0x034, 0x00005CCE, + 0x035, 0x00003800, + 0x034, 0x000048CE, + 0x035, 0x00004400, + 0x034, 0x000034CE, + 0x035, 0x00003800, + 0x034, 0x00002451, + 0x035, 0x00004400, + 0x034, 0x0000144E, + 0x035, 0x00003800, + 0x034, 0x00000051, + 0x035, 0x00004400, + 0x0EF, 0x00000000, + 0x0EF, 0x00000100, + 0x0ED, 0x00000010, + 0x044, 0x0000ADD7, + 0x044, 0x00009DD4, + 0x044, 0x00008DD1, + 0x044, 0x00007DCE, + 0x044, 0x00006CC1, + 0x044, 0x00005CCE, + 0x044, 0x000044D1, + 0x044, 0x000034CE, + 0x044, 0x00002451, + 0x044, 0x0000144E, + 0x044, 0x00000051, + 0x0EF, 0x00000000, + 0x0ED, 0x00000000, + 0x0EF, 0x00002000, + 0x03B, 0x000380EF, + 0x03B, 0x000302FE, + 0x03B, 0x00028CE6, + 0x03B, 0x000200BC, + 0x03B, 0x000188A5, + 0x03B, 0x00010FBC, + 0x03B, 0x00008F71, + 0x03B, 0x00000900, + 0x0EF, 0x00000000, + 0x0ED, 0x00000001, + 0x040, 0x000380EF, + 0x040, 0x000302FE, + 0x040, 0x00028CE6, + 0x040, 0x000200BC, + 0x040, 0x000188A5, + 0x040, 0x00010FBC, + 0x040, 0x00008F71, + 0x040, 0x00000900, + 0x0ED, 0x00000000, + 0x082, 0x00080000, + 0x083, 0x00008000, + 0x084, 0x00048D80, + 0x085, 0x00068000, + 0x0A2, 0x00080000, + 0x0A3, 0x00008000, + 0x0A4, 0x00048D80, + 0x0A5, 0x00068000, + 0x000, 0x00033D80, +}; + +u32 RTL8723BEMAC_1T_ARRAY[] = { + 0x02F, 0x00000030, + 0x035, 0x00000000, + 0x428, 0x0000000A, + 0x429, 0x00000010, + 0x430, 0x00000000, + 0x431, 0x00000000, + 0x432, 0x00000000, + 0x433, 0x00000001, + 0x434, 0x00000004, + 0x435, 0x00000005, + 0x436, 0x00000007, + 0x437, 0x00000008, + 0x43C, 0x00000004, + 0x43D, 0x00000005, + 0x43E, 0x00000007, + 0x43F, 0x00000008, + 0x440, 0x0000005D, + 0x441, 0x00000001, + 0x442, 0x00000000, + 0x444, 0x00000010, + 0x445, 0x00000000, + 0x446, 0x00000000, + 0x447, 0x00000000, + 0x448, 0x00000000, + 0x449, 0x000000F0, + 0x44A, 0x0000000F, + 0x44B, 0x0000003E, + 0x44C, 0x00000010, + 0x44D, 0x00000000, + 0x44E, 0x00000000, + 0x44F, 0x00000000, + 0x450, 0x00000000, + 0x451, 0x000000F0, + 0x452, 0x0000000F, + 0x453, 0x00000000, + 0x456, 0x0000005E, + 0x460, 0x00000066, + 0x461, 0x00000066, + 0x4C8, 0x000000FF, + 0x4C9, 0x00000008, + 0x4CC, 0x000000FF, + 0x4CD, 0x000000FF, + 0x4CE, 0x00000001, + 0x500, 0x00000026, + 0x501, 0x000000A2, + 0x502, 0x0000002F, + 0x503, 0x00000000, + 0x504, 0x00000028, + 0x505, 0x000000A3, + 0x506, 0x0000005E, + 0x507, 0x00000000, + 0x508, 0x0000002B, + 0x509, 0x000000A4, + 0x50A, 0x0000005E, + 0x50B, 0x00000000, + 0x50C, 0x0000004F, + 0x50D, 0x000000A4, + 0x50E, 0x00000000, + 0x50F, 0x00000000, + 0x512, 0x0000001C, + 0x514, 0x0000000A, + 0x516, 0x0000000A, + 0x525, 0x0000004F, + 0x550, 0x00000010, + 0x551, 0x00000010, + 0x559, 0x00000002, + 0x55C, 0x00000050, + 0x55D, 0x000000FF, + 0x605, 0x00000030, + 0x608, 0x0000000E, + 0x609, 0x0000002A, + 0x620, 0x000000FF, + 0x621, 0x000000FF, + 0x622, 0x000000FF, + 0x623, 0x000000FF, + 0x624, 0x000000FF, + 0x625, 0x000000FF, + 0x626, 0x000000FF, + 0x627, 0x000000FF, + 0x638, 0x00000050, + 0x63C, 0x0000000A, + 0x63D, 0x0000000A, + 0x63E, 0x0000000E, + 0x63F, 0x0000000E, + 0x640, 0x00000040, + 0x642, 0x00000040, + 0x643, 0x00000000, + 0x652, 0x000000C8, + 0x66E, 0x00000005, + 0x700, 0x00000021, + 0x701, 0x00000043, + 0x702, 0x00000065, + 0x703, 0x00000087, + 0x708, 0x00000021, + 0x709, 0x00000043, + 0x70A, 0x00000065, + 0x70B, 0x00000087, +}; + +u32 RTL8723BEAGCTAB_1TARRAY[] = { + 0xC78, 0xFD000001, + 0xC78, 0xFC010001, + 0xC78, 0xFB020001, + 0xC78, 0xFA030001, + 0xC78, 0xF9040001, + 0xC78, 0xF8050001, + 0xC78, 0xF7060001, + 0xC78, 0xF6070001, + 0xC78, 0xF5080001, + 0xC78, 0xF4090001, + 0xC78, 0xF30A0001, + 0xC78, 0xF20B0001, + 0xC78, 0xF10C0001, + 0xC78, 0xF00D0001, + 0xC78, 0xEF0E0001, + 0xC78, 0xEE0F0001, + 0xC78, 0xED100001, + 0xC78, 0xEC110001, + 0xC78, 0xEB120001, + 0xC78, 0xEA130001, + 0xC78, 0xE9140001, + 0xC78, 0xE8150001, + 0xC78, 0xE7160001, + 0xC78, 0xAA170001, + 0xC78, 0xA9180001, + 0xC78, 0xA8190001, + 0xC78, 0xA71A0001, + 0xC78, 0xA61B0001, + 0xC78, 0xA51C0001, + 0xC78, 0xA41D0001, + 0xC78, 0xA31E0001, + 0xC78, 0x671F0001, + 0xC78, 0x66200001, + 0xC78, 0x65210001, + 0xC78, 0x64220001, + 0xC78, 0x63230001, + 0xC78, 0x62240001, + 0xC78, 0x61250001, + 0xC78, 0x47260001, + 0xC78, 0x46270001, + 0xC78, 0x45280001, + 0xC78, 0x44290001, + 0xC78, 0x432A0001, + 0xC78, 0x422B0001, + 0xC78, 0x292C0001, + 0xC78, 0x282D0001, + 0xC78, 0x272E0001, + 0xC78, 0x262F0001, + 0xC78, 0x25300001, + 0xC78, 0x24310001, + 0xC78, 0x09320001, + 0xC78, 0x08330001, + 0xC78, 0x07340001, + 0xC78, 0x06350001, + 0xC78, 0x05360001, + 0xC78, 0x04370001, + 0xC78, 0x03380001, + 0xC78, 0x02390001, + 0xC78, 0x013A0001, + 0xC78, 0x003B0001, + 0xC78, 0x003C0001, + 0xC78, 0x003D0001, + 0xC78, 0x003E0001, + 0xC78, 0x003F0001, + 0xC78, 0xFC400001, + 0xC78, 0xFB410001, + 0xC78, 0xFA420001, + 0xC78, 0xF9430001, + 0xC78, 0xF8440001, + 0xC78, 0xF7450001, + 0xC78, 0xF6460001, + 0xC78, 0xF5470001, + 0xC78, 0xF4480001, + 0xC78, 0xF3490001, + 0xC78, 0xF24A0001, + 0xC78, 0xF14B0001, + 0xC78, 0xF04C0001, + 0xC78, 0xEF4D0001, + 0xC78, 0xEE4E0001, + 0xC78, 0xED4F0001, + 0xC78, 0xEC500001, + 0xC78, 0xEB510001, + 0xC78, 0xEA520001, + 0xC78, 0xE9530001, + 0xC78, 0xE8540001, + 0xC78, 0xE7550001, + 0xC78, 0xE6560001, + 0xC78, 0xE5570001, + 0xC78, 0xAA580001, + 0xC78, 0xA9590001, + 0xC78, 0xA85A0001, + 0xC78, 0xA75B0001, + 0xC78, 0xA65C0001, + 0xC78, 0xA55D0001, + 0xC78, 0xA45E0001, + 0xC78, 0x675F0001, + 0xC78, 0x66600001, + 0xC78, 0x65610001, + 0xC78, 0x64620001, + 0xC78, 0x63630001, + 0xC78, 0x62640001, + 0xC78, 0x61650001, + 0xC78, 0x47660001, + 0xC78, 0x46670001, + 0xC78, 0x45680001, + 0xC78, 0x44690001, + 0xC78, 0x436A0001, + 0xC78, 0x426B0001, + 0xC78, 0x296C0001, + 0xC78, 0x286D0001, + 0xC78, 0x276E0001, + 0xC78, 0x266F0001, + 0xC78, 0x25700001, + 0xC78, 0x24710001, + 0xC78, 0x09720001, + 0xC78, 0x08730001, + 0xC78, 0x07740001, + 0xC78, 0x06750001, + 0xC78, 0x05760001, + 0xC78, 0x04770001, + 0xC78, 0x03780001, + 0xC78, 0x02790001, + 0xC78, 0x017A0001, + 0xC78, 0x007B0001, + 0xC78, 0x007C0001, + 0xC78, 0x007D0001, + 0xC78, 0x007E0001, + 0xC78, 0x007F0001, + 0xC50, 0x69553422, + 0xC50, 0x69553420, +}; diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/table.h b/drivers/net/wireless/rtlwifi/rtl8723be/table.h new file mode 100644 index 000000000000..932760a84827 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/table.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Created on 2010/ 5/18, 1:41 + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8723BE_TABLE__H_ +#define __RTL8723BE_TABLE__H_ + +#include +#define RTL8723BEPHY_REG_1TARRAYLEN 388 +extern u32 RTL8723BEPHY_REG_1TARRAY[]; +#define RTL8723BEPHY_REG_ARRAY_PGLEN 36 +extern u32 RTL8723BEPHY_REG_ARRAY_PG[]; +#define RTL8723BE_RADIOA_1TARRAYLEN 206 +extern u32 RTL8723BE_RADIOA_1TARRAY[]; +#define RTL8723BEMAC_1T_ARRAYLEN 194 +extern u32 RTL8723BEMAC_1T_ARRAY[]; +#define RTL8723BEAGCTAB_1TARRAYLEN 260 +extern u32 RTL8723BEAGCTAB_1TARRAY[]; + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/trx.c b/drivers/net/wireless/rtlwifi/rtl8723be/trx.c new file mode 100644 index 000000000000..7779531919fb --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/trx.c @@ -0,0 +1,959 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "../stats.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "trx.h" +#include "led.h" +#include "dm.h" +#include "phy.h" + +static u8 _rtl8723be_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) +{ + __le16 fc = rtl_get_fc(skb); + + if (unlikely(ieee80211_is_beacon(fc))) + return QSLT_BEACON; + if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) + return QSLT_MGNT; + + return skb->priority; +} + +/* mac80211's rate_idx is like this: + * + * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ + * + * B/G rate: + * (rx_status->flag & RX_FLAG_HT) = 0, + * DESC92C_RATE1M-->DESC92C_RATE54M ==> idx is 0-->11, + * + * N rate: + * (rx_status->flag & RX_FLAG_HT) = 1, + * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 + * + * 5G band:rx_status->band == IEEE80211_BAND_5GHZ + * A rate: + * (rx_status->flag & RX_FLAG_HT) = 0, + * DESC92C_RATE6M-->DESC92C_RATE54M ==> idx is 0-->7, + * + * N rate: + * (rx_status->flag & RX_FLAG_HT) = 1, + * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 + */ +static int _rtl8723be_rate_mapping(struct ieee80211_hw *hw, + bool isht, u8 desc_rate) +{ + int rate_idx; + + if (!isht) { + if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) { + switch (desc_rate) { + case DESC92C_RATE1M: + rate_idx = 0; + break; + case DESC92C_RATE2M: + rate_idx = 1; + break; + case DESC92C_RATE5_5M: + rate_idx = 2; + break; + case DESC92C_RATE11M: + rate_idx = 3; + break; + case DESC92C_RATE6M: + rate_idx = 4; + break; + case DESC92C_RATE9M: + rate_idx = 5; + break; + case DESC92C_RATE12M: + rate_idx = 6; + break; + case DESC92C_RATE18M: + rate_idx = 7; + break; + case DESC92C_RATE24M: + rate_idx = 8; + break; + case DESC92C_RATE36M: + rate_idx = 9; + break; + case DESC92C_RATE48M: + rate_idx = 10; + break; + case DESC92C_RATE54M: + rate_idx = 11; + break; + default: + rate_idx = 0; + break; + } + } else { + switch (desc_rate) { + case DESC92C_RATE6M: + rate_idx = 0; + break; + case DESC92C_RATE9M: + rate_idx = 1; + break; + case DESC92C_RATE12M: + rate_idx = 2; + break; + case DESC92C_RATE18M: + rate_idx = 3; + break; + case DESC92C_RATE24M: + rate_idx = 4; + break; + case DESC92C_RATE36M: + rate_idx = 5; + break; + case DESC92C_RATE48M: + rate_idx = 6; + break; + case DESC92C_RATE54M: + rate_idx = 7; + break; + default: + rate_idx = 0; + break; + } + } + } else { + switch (desc_rate) { + case DESC92C_RATEMCS0: + rate_idx = 0; + break; + case DESC92C_RATEMCS1: + rate_idx = 1; + break; + case DESC92C_RATEMCS2: + rate_idx = 2; + break; + case DESC92C_RATEMCS3: + rate_idx = 3; + break; + case DESC92C_RATEMCS4: + rate_idx = 4; + break; + case DESC92C_RATEMCS5: + rate_idx = 5; + break; + case DESC92C_RATEMCS6: + rate_idx = 6; + break; + case DESC92C_RATEMCS7: + rate_idx = 7; + break; + case DESC92C_RATEMCS8: + rate_idx = 8; + break; + case DESC92C_RATEMCS9: + rate_idx = 9; + break; + case DESC92C_RATEMCS10: + rate_idx = 10; + break; + case DESC92C_RATEMCS11: + rate_idx = 11; + break; + case DESC92C_RATEMCS12: + rate_idx = 12; + break; + case DESC92C_RATEMCS13: + rate_idx = 13; + break; + case DESC92C_RATEMCS14: + rate_idx = 14; + break; + case DESC92C_RATEMCS15: + rate_idx = 15; + break; + default: + rate_idx = 0; + break; + } + } + return rate_idx; +} + +static void _rtl8723be_query_rxphystatus(struct ieee80211_hw *hw, + struct rtl_stats *pstatus, u8 *pdesc, + struct rx_fwinfo_8723be *p_drvinfo, + bool packet_match_bssid, + bool packet_toself, + bool packet_beacon) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv); + struct phy_sts_cck_8723e_t *cck_buf; + struct phy_status_rpt *p_phystrpt = (struct phy_status_rpt *)p_drvinfo; + struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw)); + char rx_pwr_all = 0, rx_pwr[4]; + u8 rf_rx_num = 0, evm, pwdb_all; + u8 i, max_spatial_stream; + u32 rssi, total_rssi = 0; + bool is_cck = pstatus->is_cck; + u8 lan_idx, vga_idx; + + /* Record it for next packet processing */ + pstatus->packet_matchbssid = packet_match_bssid; + pstatus->packet_toself = packet_toself; + pstatus->packet_beacon = packet_beacon; + pstatus->rx_mimo_sig_qual[0] = -1; + pstatus->rx_mimo_sig_qual[1] = -1; + + if (is_cck) { + u8 cck_highpwr; + u8 cck_agc_rpt; + /* CCK Driver info Structure is not the same as OFDM packet. */ + cck_buf = (struct phy_sts_cck_8723e_t *)p_drvinfo; + cck_agc_rpt = cck_buf->cck_agc_rpt; + + /* (1)Hardware does not provide RSSI for CCK + * (2)PWDB, Average PWDB cacluated by + * hardware (for rate adaptive) + */ + if (ppsc->rfpwr_state == ERFON) + cck_highpwr = (u8) rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER2, + BIT(9)); + else + cck_highpwr = false; + + lan_idx = ((cck_agc_rpt & 0xE0) >> 5); + vga_idx = (cck_agc_rpt & 0x1f); + switch (lan_idx) { + case 7: + if (vga_idx <= 27)/*VGA_idx = 27~2*/ + rx_pwr_all = -100 + 2 * (27 - vga_idx); + else + rx_pwr_all = -100; + break; + case 6:/*VGA_idx = 2~0*/ + rx_pwr_all = -48 + 2 * (2 - vga_idx); + break; + case 5:/*VGA_idx = 7~5*/ + rx_pwr_all = -42 + 2 * (7 - vga_idx); + break; + case 4:/*VGA_idx = 7~4*/ + rx_pwr_all = -36 + 2 * (7 - vga_idx); + break; + case 3:/*VGA_idx = 7~0*/ + rx_pwr_all = -24 + 2 * (7 - vga_idx); + break; + case 2: + if (cck_highpwr)/*VGA_idx = 5~0*/ + rx_pwr_all = -12 + 2 * (5 - vga_idx); + else + rx_pwr_all = -6 + 2 * (5 - vga_idx); + break; + case 1: + rx_pwr_all = 8 - 2 * vga_idx; + break; + case 0: + rx_pwr_all = 14 - 2 * vga_idx; + break; + default: + break; + } + rx_pwr_all += 6; + pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all); + /* CCK gain is smaller than OFDM/MCS gain, */ + /* so we add gain diff by experiences, + * the val is 6 + */ + pwdb_all += 6; + if (pwdb_all > 100) + pwdb_all = 100; + /* modify the offset to make the same gain index with OFDM. */ + if (pwdb_all > 34 && pwdb_all <= 42) + pwdb_all -= 2; + else if (pwdb_all > 26 && pwdb_all <= 34) + pwdb_all -= 6; + else if (pwdb_all > 14 && pwdb_all <= 26) + pwdb_all -= 8; + else if (pwdb_all > 4 && pwdb_all <= 14) + pwdb_all -= 4; + if (!cck_highpwr) { + if (pwdb_all >= 80) + pwdb_all = ((pwdb_all - 80) << 1) + + ((pwdb_all - 80) >> 1) + 80; + else if ((pwdb_all <= 78) && (pwdb_all >= 20)) + pwdb_all += 3; + if (pwdb_all > 100) + pwdb_all = 100; + } + + pstatus->rx_pwdb_all = pwdb_all; + pstatus->recvsignalpower = rx_pwr_all; + + /* (3) Get Signal Quality (EVM) */ + if (packet_match_bssid) { + u8 sq; + + if (pstatus->rx_pwdb_all > 40) { + sq = 100; + } else { + sq = cck_buf->sq_rpt; + if (sq > 64) + sq = 0; + else if (sq < 20) + sq = 100; + else + sq = ((64 - sq) * 100) / 44; + } + + pstatus->signalquality = sq; + pstatus->rx_mimo_sig_qual[0] = sq; + pstatus->rx_mimo_sig_qual[1] = -1; + } + } else { + rtlpriv->dm.rfpath_rxenable[0] = true; + rtlpriv->dm.rfpath_rxenable[1] = true; + + /* (1)Get RSSI for HT rate */ + for (i = RF90_PATH_A; i < RF6052_MAX_PATH; i++) { + /* we will judge RF RX path now. */ + if (rtlpriv->dm.rfpath_rxenable[i]) + rf_rx_num++; + + rx_pwr[i] = ((p_drvinfo->gain_trsw[i] & 0x3f)*2) - 110; + + /* Translate DBM to percentage. */ + rssi = rtl_query_rxpwrpercentage(rx_pwr[i]); + total_rssi += rssi; + + /* Get Rx snr value in DB */ + rtlpriv->stats.rx_snr_db[i] = + (long)(p_drvinfo->rxsnr[i] / 2); + + /* Record Signal Strength for next packet */ + if (packet_match_bssid) + pstatus->rx_mimo_signalstrength[i] = (u8) rssi; + } + + /* (2)PWDB, Avg cacluated by hardware (for rate adaptive) */ + rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110; + + pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all); + pstatus->rx_pwdb_all = pwdb_all; + pstatus->rxpower = rx_pwr_all; + pstatus->recvsignalpower = rx_pwr_all; + + /* (3)EVM of HT rate */ + if (pstatus->is_ht && pstatus->rate >= DESC92C_RATEMCS8 && + pstatus->rate <= DESC92C_RATEMCS15) + max_spatial_stream = 2; + else + max_spatial_stream = 1; + + for (i = 0; i < max_spatial_stream; i++) { + evm = rtl_evm_db_to_percentage(p_drvinfo->rxevm[i]); + + if (packet_match_bssid) { + /* Fill value in RFD, Get the first + * spatial stream only + */ + if (i == 0) + pstatus->signalquality = + (u8) (evm & 0xff); + pstatus->rx_mimo_sig_qual[i] = + (u8) (evm & 0xff); + } + } + if (packet_match_bssid) { + for (i = RF90_PATH_A; i <= RF90_PATH_B; i++) + rtl_priv(hw)->dm.cfo_tail[i] = + (char)p_phystrpt->path_cfotail[i]; + + rtl_priv(hw)->dm.packet_count++; + if (rtl_priv(hw)->dm.packet_count == 0xffffffff) + rtl_priv(hw)->dm.packet_count = 0; + } + } + + /* UI BSS List signal strength(in percentage), + * make it good looking, from 0~100. + */ + if (is_cck) + pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw, + pwdb_all)); + else if (rf_rx_num != 0) + pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw, + total_rssi /= rf_rx_num)); + /*HW antenna diversity*/ + rtldm->fat_table.antsel_rx_keep_0 = p_phystrpt->ant_sel; + rtldm->fat_table.antsel_rx_keep_1 = p_phystrpt->ant_sel_b; + rtldm->fat_table.antsel_rx_keep_2 = p_phystrpt->antsel_rx_keep_2; +} + +static void _rtl8723be_translate_rx_signal_stuff(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct rtl_stats *pstatus, + u8 *pdesc, + struct rx_fwinfo_8723be *p_drvinfo) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct ieee80211_hdr *hdr; + u8 *tmp_buf; + u8 *praddr; + u8 *psaddr; + u16 fc, type; + bool packet_matchbssid, packet_toself, packet_beacon; + + tmp_buf = skb->data + pstatus->rx_drvinfo_size + pstatus->rx_bufshift; + + hdr = (struct ieee80211_hdr *)tmp_buf; + fc = le16_to_cpu(hdr->frame_control); + type = WLAN_FC_GET_TYPE(hdr->frame_control); + praddr = hdr->addr1; + psaddr = ieee80211_get_SA(hdr); + memcpy(pstatus->psaddr, psaddr, ETH_ALEN); + + packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && + (!ether_addr_equal(mac->bssid, (fc & IEEE80211_FCTL_TODS) ? + hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS) ? + hdr->addr2 : hdr->addr3)) && + (!pstatus->hwerror) && + (!pstatus->crc) && (!pstatus->icv)); + + packet_toself = packet_matchbssid && + (!ether_addr_equal(praddr, rtlefuse->dev_addr)); + + /* YP: packet_beacon is not initialized, + * this assignment is neccesary, + * otherwise it counld be true in this case + * the situation is much worse in Kernel 3.10 + */ + if (ieee80211_is_beacon(hdr->frame_control)) + packet_beacon = true; + else + packet_beacon = false; + + if (packet_beacon && packet_matchbssid) + rtl_priv(hw)->dm.dbginfo.num_qry_beacon_pkt++; + + _rtl8723be_query_rxphystatus(hw, pstatus, pdesc, p_drvinfo, + packet_matchbssid, + packet_toself, + packet_beacon); + + rtl_process_phyinfo(hw, tmp_buf, pstatus); +} + +static void _rtl8723be_insert_emcontent(struct rtl_tcb_desc *ptcb_desc, + u8 *virtualaddress) +{ + u32 dwtmp = 0; + memset(virtualaddress, 0, 8); + + SET_EARLYMODE_PKTNUM(virtualaddress, ptcb_desc->empkt_num); + if (ptcb_desc->empkt_num == 1) { + dwtmp = ptcb_desc->empkt_len[0]; + } else { + dwtmp = ptcb_desc->empkt_len[0]; + dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; + dwtmp += ptcb_desc->empkt_len[1]; + } + SET_EARLYMODE_LEN0(virtualaddress, dwtmp); + + if (ptcb_desc->empkt_num <= 3) { + dwtmp = ptcb_desc->empkt_len[2]; + } else { + dwtmp = ptcb_desc->empkt_len[2]; + dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; + dwtmp += ptcb_desc->empkt_len[3]; + } + SET_EARLYMODE_LEN1(virtualaddress, dwtmp); + if (ptcb_desc->empkt_num <= 5) { + dwtmp = ptcb_desc->empkt_len[4]; + } else { + dwtmp = ptcb_desc->empkt_len[4]; + dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; + dwtmp += ptcb_desc->empkt_len[5]; + } + SET_EARLYMODE_LEN2_1(virtualaddress, dwtmp & 0xF); + SET_EARLYMODE_LEN2_2(virtualaddress, dwtmp >> 4); + if (ptcb_desc->empkt_num <= 7) { + dwtmp = ptcb_desc->empkt_len[6]; + } else { + dwtmp = ptcb_desc->empkt_len[6]; + dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; + dwtmp += ptcb_desc->empkt_len[7]; + } + SET_EARLYMODE_LEN3(virtualaddress, dwtmp); + if (ptcb_desc->empkt_num <= 9) { + dwtmp = ptcb_desc->empkt_len[8]; + } else { + dwtmp = ptcb_desc->empkt_len[8]; + dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; + dwtmp += ptcb_desc->empkt_len[9]; + } + SET_EARLYMODE_LEN4(virtualaddress, dwtmp); +} + +bool rtl8723be_rx_query_desc(struct ieee80211_hw *hw, + struct rtl_stats *status, + struct ieee80211_rx_status *rx_status, + u8 *pdesc, struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rx_fwinfo_8723be *p_drvinfo; + struct ieee80211_hdr *hdr; + + u32 phystatus = GET_RX_DESC_PHYST(pdesc); + status->packet_report_type = (u8)GET_RX_STATUS_DESC_RPT_SEL(pdesc); + if (status->packet_report_type == TX_REPORT2) + status->length = (u16) GET_RX_RPT2_DESC_PKT_LEN(pdesc); + else + status->length = (u16) GET_RX_DESC_PKT_LEN(pdesc); + status->rx_drvinfo_size = (u8) GET_RX_DESC_DRV_INFO_SIZE(pdesc) * + RX_DRV_INFO_SIZE_UNIT; + status->rx_bufshift = (u8) (GET_RX_DESC_SHIFT(pdesc) & 0x03); + status->icv = (u16) GET_RX_DESC_ICV(pdesc); + status->crc = (u16) GET_RX_DESC_CRC32(pdesc); + status->hwerror = (status->crc | status->icv); + status->decrypted = !GET_RX_DESC_SWDEC(pdesc); + status->rate = (u8) GET_RX_DESC_RXMCS(pdesc); + status->shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc); + status->isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1); + status->isfirst_ampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1); + if (status->packet_report_type == NORMAL_RX) + status->timestamp_low = GET_RX_DESC_TSFL(pdesc); + status->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc); + status->is_ht = (bool)GET_RX_DESC_RXHT(pdesc); + + status->is_cck = RTL8723E_RX_HAL_IS_CCK_RATE(status->rate); + + status->macid = GET_RX_DESC_MACID(pdesc); + if (GET_RX_STATUS_DESC_MAGIC_MATCH(pdesc)) + status->wake_match = BIT(2); + else if (GET_RX_STATUS_DESC_MAGIC_MATCH(pdesc)) + status->wake_match = BIT(1); + else if (GET_RX_STATUS_DESC_UNICAST_MATCH(pdesc)) + status->wake_match = BIT(0); + else + status->wake_match = 0; + if (status->wake_match) + RT_TRACE(rtlpriv, COMP_RXDESC, DBG_LOUD, + "GGGGGGGGGGGGGet Wakeup Packet!! WakeMatch=%d\n", + status->wake_match); + rx_status->freq = hw->conf.chandef.chan->center_freq; + rx_status->band = hw->conf.chandef.chan->band; + + + hdr = (struct ieee80211_hdr *)(skb->data + status->rx_drvinfo_size + + status->rx_bufshift); + + if (status->crc) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + + if (status->rx_is40Mhzpacket) + rx_status->flag |= RX_FLAG_40MHZ; + + if (status->is_ht) + rx_status->flag |= RX_FLAG_HT; + + rx_status->flag |= RX_FLAG_MACTIME_START; + + /* hw will set status->decrypted true, if it finds the + * frame is open data frame or mgmt frame. + * So hw will not decryption robust managment frame + * for IEEE80211w but still set status->decrypted + * true, so here we should set it back to undecrypted + * for IEEE80211w frame, and mac80211 sw will help + * to decrypt it + */ + if (status->decrypted) { + if (!hdr) { + WARN_ON_ONCE(true); + pr_err("decrypted is true but hdr NULL in skb %p\n", + rtl_get_hdr(skb)); + return false; + } + + if ((_ieee80211_is_robust_mgmt_frame(hdr)) && + (ieee80211_has_protected(hdr->frame_control))) + rx_status->flag &= ~RX_FLAG_DECRYPTED; + else + rx_status->flag |= RX_FLAG_DECRYPTED; + } + + /* rate_idx: index of data rate into band's + * supported rates or MCS index if HT rates + * are use (RX_FLAG_HT) + * Notice: this is diff with windows define + */ + rx_status->rate_idx = _rtl8723be_rate_mapping(hw, status->is_ht, + status->rate); + + rx_status->mactime = status->timestamp_low; + if (phystatus) { + p_drvinfo = (struct rx_fwinfo_8723be *)(skb->data + + status->rx_bufshift); + + _rtl8723be_translate_rx_signal_stuff(hw, skb, status, + pdesc, p_drvinfo); + } + + /*rx_status->qual = status->signal; */ + rx_status->signal = status->recvsignalpower + 10; + if (status->packet_report_type == TX_REPORT2) { + status->macid_valid_entry[0] = + GET_RX_RPT2_DESC_MACID_VALID_1(pdesc); + status->macid_valid_entry[1] = + GET_RX_RPT2_DESC_MACID_VALID_2(pdesc); + } + return true; +} + +void rtl8723be_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, + struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, struct sk_buff *skb, + u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u8 *pdesc = (u8 *)pdesc_tx; + u16 seq_number; + __le16 fc = hdr->frame_control; + unsigned int buf_len = 0; + unsigned int skb_len = skb->len; + u8 fw_qsel = _rtl8723be_map_hwqueue_to_fwqueue(skb, hw_queue); + bool firstseg = ((hdr->seq_ctrl & + cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0); + bool lastseg = ((hdr->frame_control & + cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0); + dma_addr_t mapping; + u8 bw_40 = 0; + u8 short_gi = 0; + + if (mac->opmode == NL80211_IFTYPE_STATION) { + bw_40 = mac->bw_40; + } else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (sta) + bw_40 = sta->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40; + } + seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc); + /* reserve 8 byte for AMPDU early mode */ + if (rtlhal->earlymode_enable) { + skb_push(skb, EM_HDR_LEN); + memset(skb->data, 0, EM_HDR_LEN); + } + buf_len = skb->len; + mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "DMA mapping error"); + return; + } + CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_8723be)); + if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) { + firstseg = true; + lastseg = true; + } + if (firstseg) { + if (rtlhal->earlymode_enable) { + SET_TX_DESC_PKT_OFFSET(pdesc, 1); + SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN + + EM_HDR_LEN); + if (ptcb_desc->empkt_num) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, + "Insert 8 byte.pTcb->EMPktNum:%d\n", + ptcb_desc->empkt_num); + _rtl8723be_insert_emcontent(ptcb_desc, + (u8 *)(skb->data)); + } + } else { + SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); + } + + /* ptcb_desc->use_driver_rate = true; */ + SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); + if (ptcb_desc->hw_rate > DESC92C_RATEMCS0) + short_gi = (ptcb_desc->use_shortgi) ? 1 : 0; + else + short_gi = (ptcb_desc->use_shortpreamble) ? 1 : 0; + + SET_TX_DESC_DATA_SHORTGI(pdesc, short_gi); + + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + SET_TX_DESC_AGG_ENABLE(pdesc, 1); + SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14); + } + SET_TX_DESC_SEQ(pdesc, seq_number); + SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcb_desc->rts_enable && + !ptcb_desc->cts_enable) ? + 1 : 0)); + SET_TX_DESC_HW_RTS_ENABLE(pdesc, 0); + SET_TX_DESC_CTS2SELF(pdesc, ((ptcb_desc->cts_enable) ? + 1 : 0)); + + SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate); + + SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc); + SET_TX_DESC_RTS_SHORT(pdesc, + ((ptcb_desc->rts_rate <= DESC92C_RATE54M) ? + (ptcb_desc->rts_use_shortpreamble ? 1 : 0) : + (ptcb_desc->rts_use_shortgi ? 1 : 0))); + + if (ptcb_desc->btx_enable_sw_calc_duration) + SET_TX_DESC_NAV_USE_HDR(pdesc, 1); + + if (bw_40) { + if (ptcb_desc->packet_bw) { + SET_TX_DESC_DATA_BW(pdesc, 1); + SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3); + } else { + SET_TX_DESC_DATA_BW(pdesc, 0); + SET_TX_DESC_TX_SUB_CARRIER(pdesc, mac->cur_40_prime_sc); + } + } else { + SET_TX_DESC_DATA_BW(pdesc, 0); + SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0); + } + + SET_TX_DESC_LINIP(pdesc, 0); + SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb_len); + if (sta) { + u8 ampdu_density = sta->ht_cap.ampdu_density; + SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density); + } + if (info->control.hw_key) { + struct ieee80211_key_conf *keyconf = + info->control.hw_key; + switch (keyconf->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + case WLAN_CIPHER_SUITE_TKIP: + SET_TX_DESC_SEC_TYPE(pdesc, 0x1); + break; + case WLAN_CIPHER_SUITE_CCMP: + SET_TX_DESC_SEC_TYPE(pdesc, 0x3); + break; + default: + SET_TX_DESC_SEC_TYPE(pdesc, 0x0); + break; + } + } + + SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel); + SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F); + SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF); + SET_TX_DESC_DISABLE_FB(pdesc, ptcb_desc->disable_ratefallback ? + 1 : 0); + SET_TX_DESC_USE_RATE(pdesc, ptcb_desc->use_driver_rate ? 1 : 0); + + if (ieee80211_is_data_qos(fc)) { + if (mac->rdg_en) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, + "Enable RDG function.\n"); + SET_TX_DESC_RDG_ENABLE(pdesc, 1); + SET_TX_DESC_HTC(pdesc, 1); + } + } + } + + SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0)); + SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0)); + SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) buf_len); + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); + SET_TX_DESC_RATE_ID(pdesc, ptcb_desc->ratr_index); + SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id); + + if (!ieee80211_is_data_qos(fc)) { + SET_TX_DESC_HWSEQ_EN(pdesc, 1); + SET_TX_DESC_HWSEQ_SEL(pdesc, 0); + } + SET_TX_DESC_MORE_FRAG(pdesc, (lastseg ? 0 : 1)); + if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) || + is_broadcast_ether_addr(ieee80211_get_DA(hdr))) { + SET_TX_DESC_BMC(pdesc, 1); + } + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n"); +} + +void rtl8723be_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, + bool b_firstseg, bool b_lastseg, + struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 fw_queue = QSLT_BEACON; + + dma_addr_t mapping = pci_map_single(rtlpci->pdev, + skb->data, skb->len, + PCI_DMA_TODEVICE); + + if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, + "DMA mapping error"); + return; + } + CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE); + + SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); + + SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M); + + SET_TX_DESC_SEQ(pdesc, 0); + + SET_TX_DESC_LINIP(pdesc, 0); + + SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue); + + SET_TX_DESC_FIRST_SEG(pdesc, 1); + SET_TX_DESC_LAST_SEG(pdesc, 1); + + SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len)); + + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); + + SET_TX_DESC_RATE_ID(pdesc, 0); + SET_TX_DESC_MACID(pdesc, 0); + + SET_TX_DESC_OWN(pdesc, 1); + + SET_TX_DESC_PKT_SIZE((u8 *)pdesc, (u16)(skb->len)); + + SET_TX_DESC_FIRST_SEG(pdesc, 1); + SET_TX_DESC_LAST_SEG(pdesc, 1); + + SET_TX_DESC_USE_RATE(pdesc, 1); +} + +void rtl8723be_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +{ + if (istx) { + switch (desc_name) { + case HW_DESC_OWN: + SET_TX_DESC_OWN(pdesc, 1); + break; + case HW_DESC_TX_NEXTDESC_ADDR: + SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *)val); + break; + default: + RT_ASSERT(false, "ERR txdesc :%d not process\n", + desc_name); + break; + } + } else { + switch (desc_name) { + case HW_DESC_RXOWN: + SET_RX_DESC_OWN(pdesc, 1); + break; + case HW_DESC_RXBUFF_ADDR: + SET_RX_DESC_BUFF_ADDR(pdesc, *(u32 *)val); + break; + case HW_DESC_RXPKT_LEN: + SET_RX_DESC_PKT_LEN(pdesc, *(u32 *)val); + break; + case HW_DESC_RXERO: + SET_RX_DESC_EOR(pdesc, 1); + break; + default: + RT_ASSERT(false, "ERR rxdesc :%d not process\n", + desc_name); + break; + } + } +} + +u32 rtl8723be_get_desc(u8 *pdesc, bool istx, u8 desc_name) +{ + u32 ret = 0; + + if (istx) { + switch (desc_name) { + case HW_DESC_OWN: + ret = GET_TX_DESC_OWN(pdesc); + break; + case HW_DESC_TXBUFF_ADDR: + ret = GET_TX_DESC_TX_BUFFER_ADDRESS(pdesc); + break; + default: + RT_ASSERT(false, "ERR txdesc :%d not process\n", + desc_name); + break; + } + } else { + switch (desc_name) { + case HW_DESC_OWN: + ret = GET_RX_DESC_OWN(pdesc); + break; + case HW_DESC_RXPKT_LEN: + ret = GET_RX_DESC_PKT_LEN(pdesc); + break; + default: + RT_ASSERT(false, "ERR rxdesc :%d not process\n", + desc_name); + break; + } + } + return ret; +} + +bool rtl8723be_is_tx_desc_closed(struct ieee80211_hw *hw, + u8 hw_queue, u16 index) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; + u8 *entry = (u8 *)(&ring->desc[ring->idx]); + u8 own = (u8) rtl8723be_get_desc(entry, true, HW_DESC_OWN); + + /*beacon packet will only use the first + *descriptor by default, and the own may not + *be cleared by the hardware + */ + if (own) + return false; + else + return true; +} + +void rtl8723be_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + if (hw_queue == BEACON_QUEUE) { + rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, BIT(4)); + } else { + rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, + BIT(0) << (hw_queue)); + } +} diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/trx.h b/drivers/net/wireless/rtlwifi/rtl8723be/trx.h new file mode 100644 index 000000000000..d375cf01c3dc --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723be/trx.h @@ -0,0 +1,616 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2014 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#ifndef __RTL8723BE_TRX_H__ +#define __RTL8723BE_TRX_H__ + +#define TX_DESC_SIZE 40 +#define TX_DESC_AGGR_SUBFRAME_SIZE 32 + +#define RX_DESC_SIZE 32 +#define RX_DRV_INFO_SIZE_UNIT 8 + +#define TX_DESC_NEXT_DESC_OFFSET 40 +#define USB_HWDESC_HEADER_LEN 40 +#define CRCLENGTH 4 + +#define SET_TX_DESC_PKT_SIZE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 0, 16, __val) +#define SET_TX_DESC_OFFSET(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 16, 8, __val) +#define SET_TX_DESC_BMC(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 24, 1, __val) +#define SET_TX_DESC_HTC(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 25, 1, __val) +#define SET_TX_DESC_LAST_SEG(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 26, 1, __val) +#define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 27, 1, __val) +#define SET_TX_DESC_LINIP(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 28, 1, __val) +#define SET_TX_DESC_NO_ACM(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 29, 1, __val) +#define SET_TX_DESC_GF(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val) +#define SET_TX_DESC_OWN(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val) + +#define GET_TX_DESC_PKT_SIZE(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 0, 16) +#define GET_TX_DESC_OFFSET(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 16, 8) +#define GET_TX_DESC_BMC(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 24, 1) +#define GET_TX_DESC_HTC(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 25, 1) +#define GET_TX_DESC_LAST_SEG(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 26, 1) +#define GET_TX_DESC_FIRST_SEG(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 27, 1) +#define GET_TX_DESC_LINIP(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 28, 1) +#define GET_TX_DESC_NO_ACM(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 29, 1) +#define GET_TX_DESC_GF(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 30, 1) +#define GET_TX_DESC_OWN(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 31, 1) + +#define SET_TX_DESC_MACID(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+4, 0, 7, __val) +#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+4, 8, 5, __val) +#define SET_TX_DESC_RDG_NAV_EXT(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+4, 13, 1, __val) +#define SET_TX_DESC_LSIG_TXOP_EN(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+4, 14, 1, __val) +#define SET_TX_DESC_PIFS(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+4, 15, 1, __val) +#define SET_TX_DESC_RATE_ID(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+4, 16, 5, __val) +#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+4, 21, 1, __val) +#define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+4, 22, 2, __val) +#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+4, 24, 5, __val) + + +#define SET_TX_DESC_PAID(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 0, 9, __val) +#define SET_TX_DESC_CCA_RTS(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 10, 2, __val) +#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 12, 1, __val) +#define SET_TX_DESC_RDG_ENABLE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 13, 1, __val) +#define SET_TX_DESC_BAR_RTY_TH(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 14, 2, __val) +#define SET_TX_DESC_AGG_BREAK(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 16, 1, __val) +#define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 17, 1, __val) +#define SET_TX_DESC_RAW(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val) +#define SET_TX_DESC_SPE_RPT(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val) +#define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val) +#define SET_TX_DESC_BT_INT(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 23, 1, __val) +#define SET_TX_DESC_GID(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+8, 24, 6, __val) + + +#define SET_TX_DESC_WHEADER_LEN(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 0, 4, __val) +#define SET_TX_DESC_CHK_EN(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 4, 1, __val) +#define SET_TX_DESC_EARLY_MODE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 5, 1, __val) +#define SET_TX_DESC_HWSEQ_SEL(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 6, 2, __val) +#define SET_TX_DESC_USE_RATE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 8, 1, __val) +#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 9, 1, __val) +#define SET_TX_DESC_DISABLE_FB(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 10, 1, __val) +#define SET_TX_DESC_CTS2SELF(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 11, 1, __val) +#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 12, 1, __val) +#define SET_TX_DESC_HW_RTS_ENABLE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 13, 1, __val) +#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 15, 1, __val) +#define SET_TX_DESC_USE_MAX_LEN(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 16, 1, __val) +#define SET_TX_DESC_MAX_AGG_NUM(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 17, 5, __val) +#define SET_TX_DESC_NDPA(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 22, 2, __val) +#define SET_TX_DESC_AMPDU_MAX_TIME(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+12, 24, 8, __val) + + +#define SET_TX_DESC_TX_RATE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 7, __val) +#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+16, 8, 5, __val) +#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+16, 13, 4, __val) +#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+16, 17, 1, __val) +#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+16, 18, 6, __val) +#define SET_TX_DESC_RTS_RATE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+16, 24, 5, __val) + + +#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+20, 0, 4, __val) +#define SET_TX_DESC_DATA_SHORTGI(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+20, 4, 1, __val) +#define SET_TX_DESC_DATA_BW(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+20, 5, 2, __val) +#define SET_TX_DESC_DATA_LDPC(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+20, 7, 1, __val) +#define SET_TX_DESC_DATA_STBC(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+20, 8, 2, __val) +#define SET_TX_DESC_CTROL_STBC(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+20, 10, 2, __val) +#define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+20, 12, 1, __val) +#define SET_TX_DESC_RTS_SC(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+20, 13, 4, __val) + + +#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 16, __val) + +#define GET_TX_DESC_TX_BUFFER_SIZE(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+28, 0, 16) + +#define SET_TX_DESC_HWSEQ_EN(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+32, 15, 1, __val) + +#define SET_TX_DESC_SEQ(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+36, 12, 12, __val) + +#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+40, 0, 32, __val) + +#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+40, 0, 32) + + +#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+48, 0, 32, __val) + +#define GET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+48, 0, 32) + +#define GET_RX_DESC_PKT_LEN(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 0, 14) +#define GET_RX_DESC_CRC32(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 14, 1) +#define GET_RX_DESC_ICV(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 15, 1) +#define GET_RX_DESC_DRV_INFO_SIZE(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 16, 4) +#define GET_RX_DESC_SECURITY(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 20, 3) +#define GET_RX_DESC_QOS(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 23, 1) +#define GET_RX_DESC_SHIFT(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 24, 2) +#define GET_RX_DESC_PHYST(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 26, 1) +#define GET_RX_DESC_SWDEC(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 27, 1) +#define GET_RX_DESC_LS(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 28, 1) +#define GET_RX_DESC_FS(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 29, 1) +#define GET_RX_DESC_EOR(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 30, 1) +#define GET_RX_DESC_OWN(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc, 31, 1) + +#define SET_RX_DESC_PKT_LEN(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 0, 14, __val) +#define SET_RX_DESC_EOR(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val) +#define SET_RX_DESC_OWN(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val) + +#define GET_RX_DESC_MACID(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 0, 7) +#define GET_RX_DESC_TID(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 8, 4) +#define GET_RX_DESC_AMSDU(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 13, 1) +#define GET_RX_STATUS_DESC_RXID_MATCH(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 14, 1) +#define GET_RX_DESC_PAGGR(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 15, 1) +#define GET_RX_DESC_A1_FIT(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 16, 4) +#define GET_RX_DESC_CHKERR(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 20, 1) +#define GET_RX_DESC_IPVER(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 21, 1) +#define GET_RX_STATUS_DESC_IS_TCPUDP(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 22, 1) +#define GET_RX_STATUS_DESC_CHK_VLD(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 23, 1) +#define GET_RX_DESC_PAM(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 24, 1) +#define GET_RX_DESC_PWR(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 25, 1) +#define GET_RX_DESC_MD(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 26, 1) +#define GET_RX_DESC_MF(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 27, 1) +#define GET_RX_DESC_TYPE(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 28, 2) +#define GET_RX_DESC_MC(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 30, 1) +#define GET_RX_DESC_BC(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+4, 31, 1) + + +#define GET_RX_DESC_SEQ(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+8, 0, 12) +#define GET_RX_DESC_FRAG(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+8, 12, 4) +#define GET_RX_STATUS_DESC_RX_IS_QOS(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+8, 16, 1) +#define GET_RX_STATUS_DESC_WLANHD_IV_LEN(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+8, 18, 6) +#define GET_RX_STATUS_DESC_RPT_SEL(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+8, 28, 1) + + +#define GET_RX_DESC_RXMCS(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+12, 0, 7) +#define GET_RX_DESC_RXHT(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+12, 6, 1) +#define GET_RX_STATUS_DESC_RX_GF(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+12, 7, 1) +#define GET_RX_DESC_HTC(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+12, 10, 1) +#define GET_RX_STATUS_DESC_EOSP(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+12, 11, 1) +#define GET_RX_STATUS_DESC_BSSID_FIT(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+12, 12, 2) + +#define GET_RX_STATUS_DESC_PATTERN_MATCH(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+12, 29, 1) +#define GET_RX_STATUS_DESC_UNICAST_MATCH(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+12, 30, 1) +#define GET_RX_STATUS_DESC_MAGIC_MATCH(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+12, 31, 1) + +#define GET_RX_DESC_SPLCP(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+16, 0, 1) +#define GET_RX_STATUS_DESC_LDPC(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+16, 1, 1) +#define GET_RX_STATUS_DESC_STBC(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+16, 2, 1) +#define GET_RX_DESC_BW(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+16, 4, 2) + +#define GET_RX_DESC_TSFL(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+20, 0, 32) + +#define GET_RX_DESC_BUFF_ADDR(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+24, 0, 32) +#define GET_RX_DESC_BUFF_ADDR64(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+28, 0, 32) + +#define SET_RX_DESC_BUFF_ADDR(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 32, __val) +#define SET_RX_DESC_BUFF_ADDR64(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 32, __val) + + +/* TX report 2 format in Rx desc*/ + +#define GET_RX_RPT2_DESC_PKT_LEN(__rxstatusdesc) \ + LE_BITS_TO_4BYTE(__rxstatusdesc, 0, 9) +#define GET_RX_RPT2_DESC_MACID_VALID_1(__rxstatusdesc) \ + LE_BITS_TO_4BYTE(__rxstatusdesc+16, 0, 32) +#define GET_RX_RPT2_DESC_MACID_VALID_2(__rxstatusdesc) \ + LE_BITS_TO_4BYTE(__rxstatusdesc+20, 0, 32) + +#define SET_EARLYMODE_PKTNUM(__paddr, __value) \ + SET_BITS_TO_LE_4BYTE(__paddr, 0, 4, __value) +#define SET_EARLYMODE_LEN0(__paddr, __value) \ + SET_BITS_TO_LE_4BYTE(__paddr, 4, 12, __value) +#define SET_EARLYMODE_LEN1(__paddr, __value) \ + SET_BITS_TO_LE_4BYTE(__paddr, 16, 12, __value) +#define SET_EARLYMODE_LEN2_1(__paddr, __value) \ + SET_BITS_TO_LE_4BYTE(__paddr, 28, 4, __value) +#define SET_EARLYMODE_LEN2_2(__paddr, __value) \ + SET_BITS_TO_LE_4BYTE(__paddr+4, 0, 8, __value) +#define SET_EARLYMODE_LEN3(__paddr, __value) \ + SET_BITS_TO_LE_4BYTE(__paddr+4, 8, 12, __value) +#define SET_EARLYMODE_LEN4(__paddr, __value) \ + SET_BITS_TO_LE_4BYTE(__paddr+4, 20, 12, __value) + +#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \ +do { \ + if (_size > TX_DESC_NEXT_DESC_OFFSET) \ + memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \ + else \ + memset(__pdesc, 0, _size); \ +} while (0) + +struct phy_rx_agc_info_t { + #ifdef __LITTLE_ENDIAN + u8 gain:7, trsw:1; + #else + u8 trsw:1, gain:7; + #endif +}; +struct phy_status_rpt { + struct phy_rx_agc_info_t path_agc[2]; + u8 ch_corr[2]; + u8 cck_sig_qual_ofdm_pwdb_all; + u8 cck_agc_rpt_ofdm_cfosho_a; + u8 cck_rpt_b_ofdm_cfosho_b; + u8 rsvd_1;/* ch_corr_msb; */ + u8 noise_power_db_msb; + char path_cfotail[2]; + u8 pcts_mask[2]; + char stream_rxevm[2]; + u8 path_rxsnr[2]; + u8 noise_power_db_lsb; + u8 rsvd_2[3]; + u8 stream_csi[2]; + u8 stream_target_csi[2]; + u8 sig_evm; + u8 rsvd_3; +#ifdef __LITTLE_ENDIAN + u8 antsel_rx_keep_2:1; /*ex_intf_flg:1;*/ + u8 sgi_en:1; + u8 rxsc:2; + u8 idle_long:1; + u8 r_ant_train_en:1; + u8 ant_sel_b:1; + u8 ant_sel:1; +#else /* _BIG_ENDIAN_ */ + u8 ant_sel:1; + u8 ant_sel_b:1; + u8 r_ant_train_en:1; + u8 idle_long:1; + u8 rxsc:2; + u8 sgi_en:1; + u8 antsel_rx_keep_2:1; /*ex_intf_flg:1;*/ +#endif +} __packed; + +struct rx_fwinfo_8723be { + u8 gain_trsw[4]; + u8 pwdb_all; + u8 cfosho[4]; + u8 cfotail[4]; + char rxevm[2]; + char rxsnr[4]; + u8 pdsnr[2]; + u8 csi_current[2]; + u8 csi_target[2]; + u8 sigevm; + u8 max_ex_pwr; + u8 ex_intf_flag:1; + u8 sgi_en:1; + u8 rxsc:2; + u8 reserve:4; +} __packed; + +struct tx_desc_8723be { + u32 pktsize:16; + u32 offset:8; + u32 bmc:1; + u32 htc:1; + u32 lastseg:1; + u32 firstseg:1; + u32 linip:1; + u32 noacm:1; + u32 gf:1; + u32 own:1; + + u32 macid:6; + u32 rsvd0:2; + u32 queuesel:5; + u32 rd_nav_ext:1; + u32 lsig_txop_en:1; + u32 pifs:1; + u32 rateid:4; + u32 nav_usehdr:1; + u32 en_descid:1; + u32 sectype:2; + u32 pktoffset:8; + + u32 rts_rc:6; + u32 data_rc:6; + u32 agg_en:1; + u32 rdg_en:1; + u32 bar_retryht:2; + u32 agg_break:1; + u32 morefrag:1; + u32 raw:1; + u32 ccx:1; + u32 ampdudensity:3; + u32 bt_int:1; + u32 ant_sela:1; + u32 ant_selb:1; + u32 txant_cck:2; + u32 txant_l:2; + u32 txant_ht:2; + + u32 nextheadpage:8; + u32 tailpage:8; + u32 seq:12; + u32 cpu_handle:1; + u32 tag1:1; + u32 trigger_int:1; + u32 hwseq_en:1; + + u32 rtsrate:5; + u32 apdcfe:1; + u32 qos:1; + u32 hwseq_ssn:1; + u32 userrate:1; + u32 dis_rtsfb:1; + u32 dis_datafb:1; + u32 cts2self:1; + u32 rts_en:1; + u32 hwrts_en:1; + u32 portid:1; + u32 pwr_status:3; + u32 waitdcts:1; + u32 cts2ap_en:1; + u32 txsc:2; + u32 stbc:2; + u32 txshort:1; + u32 txbw:1; + u32 rtsshort:1; + u32 rtsbw:1; + u32 rtssc:2; + u32 rtsstbc:2; + + u32 txrate:6; + u32 shortgi:1; + u32 ccxt:1; + u32 txrate_fb_lmt:5; + u32 rtsrate_fb_lmt:4; + u32 retrylmt_en:1; + u32 txretrylmt:6; + u32 usb_txaggnum:8; + + u32 txagca:5; + u32 txagcb:5; + u32 usemaxlen:1; + u32 maxaggnum:5; + u32 mcsg1maxlen:4; + u32 mcsg2maxlen:4; + u32 mcsg3maxlen:4; + u32 mcs7sgimaxlen:4; + + u32 txbuffersize:16; + u32 sw_offset30:8; + u32 sw_offset31:4; + u32 rsvd1:1; + u32 antsel_c:1; + u32 null_0:1; + u32 null_1:1; + + u32 txbuffaddr; + u32 txbufferaddr64; + u32 nextdescaddress; + u32 nextdescaddress64; + + u32 reserve_pass_pcie_mm_limit[4]; +} __packed; + +struct rx_desc_8723be { + u32 length:14; + u32 crc32:1; + u32 icverror:1; + u32 drv_infosize:4; + u32 security:3; + u32 qos:1; + u32 shift:2; + u32 phystatus:1; + u32 swdec:1; + u32 lastseg:1; + u32 firstseg:1; + u32 eor:1; + u32 own:1; + + u32 macid:6; + u32 tid:4; + u32 hwrsvd:5; + u32 paggr:1; + u32 faggr:1; + u32 a1_fit:4; + u32 a2_fit:4; + u32 pam:1; + u32 pwr:1; + u32 moredata:1; + u32 morefrag:1; + u32 type:2; + u32 mc:1; + u32 bc:1; + + u32 seq:12; + u32 frag:4; + u32 nextpktlen:14; + u32 nextind:1; + u32 rsvd:1; + + u32 rxmcs:6; + u32 rxht:1; + u32 amsdu:1; + u32 splcp:1; + u32 bandwidth:1; + u32 htc:1; + u32 tcpchk_rpt:1; + u32 ipcchk_rpt:1; + u32 tcpchk_valid:1; + u32 hwpcerr:1; + u32 hwpcind:1; + u32 iv0:16; + + u32 iv1; + + u32 tsfl; + + u32 bufferaddress; + u32 bufferaddress64; + +} __packed; + +void rtl8723be_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, + struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, struct sk_buff *skb, + u8 hw_queue, struct rtl_tcb_desc *ptcb_desc); +bool rtl8723be_rx_query_desc(struct ieee80211_hw *hw, + struct rtl_stats *status, + struct ieee80211_rx_status *rx_status, + u8 *pdesc, struct sk_buff *skb); +void rtl8723be_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +u32 rtl8723be_get_desc(u8 *pdesc, bool istx, u8 desc_name); +bool rtl8723be_is_tx_desc_closed(struct ieee80211_hw *hw, + u8 hw_queue, u16 index); +void rtl8723be_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); +void rtl8723be_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, + bool b_firstseg, bool b_lastseg, + struct sk_buff *skb); +#endif From 76be3434f4150b282470bf71cd4aa0c82b29d603 Mon Sep 17 00:00:00 2001 From: Surendra Patil Date: Tue, 4 Mar 2014 00:18:52 -0800 Subject: [PATCH 395/414] Drivers:net:wireless:ti:wl1251: Fixed Sparse invalid assignment warning Sparse warns about invalid assignment in drivers/net/wireless/ti/wl1251/cmd.c:451:42: warning: invalid assignment: |= drivers/net/wireless/ti/wl1251/cmd.c:451:42: left side has type restricted __le16 drivers/net/wireless/ti/wl1251/cmd.c:451:42: right side has type int Hence type converted right side to __le16. Signed-off-by: Surendra Patil Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wl1251/cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ti/wl1251/cmd.c b/drivers/net/wireless/ti/wl1251/cmd.c index 223649bcaa5a..bf1fa18b9786 100644 --- a/drivers/net/wireless/ti/wl1251/cmd.c +++ b/drivers/net/wireless/ti/wl1251/cmd.c @@ -448,7 +448,7 @@ int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, * Note: This bug may be caused by the fw's DTIM handling. */ if (is_zero_ether_addr(wl->bssid)) - cmd->params.scan_options |= WL1251_SCAN_OPT_PRIORITY_HIGH; + cmd->params.scan_options |= cpu_to_le16(WL1251_SCAN_OPT_PRIORITY_HIGH); cmd->params.num_channels = n_channels; cmd->params.num_probe_requests = n_probes; cmd->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ From 997bc71a3601b25dbbe3ac75b77b4f49582c0ae5 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 4 Mar 2014 14:18:42 +0100 Subject: [PATCH 396/414] iwl4965: disable 8K A-MSDU by default iwlegacy version of this iwlwifi patch: commit aed7d9ac1836defe033b561f4306e39014ac56fd Author: Emmanuel Grumbach Date: Wed Feb 20 11:33:00 2013 +0200 iwlwifi: disable 8K A-MSDU by default Supporting 8K A-MSDU means that we need to allocate order 1 pages for every Rx packet. Even when there is no traffic. This adds stress on the memory manager. The handling of compound pages is also less trivial for the memory manager and not using them will make the allocation code run faster although I didn't really measure. Eric also pointed out that having huge buffers with little data in them is not very nice towards the TCP stack since the truesize of the skb is huge. This doesn't allow TCP to have a big Rx window. See https://patchwork.kernel.org/patch/2167711/ for details. Note that very few vendors will actually send A-MSDU. Disable this feature by default. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/4965-mac.c | 3 +-- drivers/net/wireless/iwlegacy/common.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 50673f7e30bc..888ad5c74639 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -92,7 +92,6 @@ il4965_check_abort_status(struct il_priv *il, u8 frame_count, u32 status) * EEPROM */ struct il_mod_params il4965_mod_params = { - .amsdu_size_8K = 1, .restart_fw = 1, /* the rest are 0 by default */ }; @@ -6866,6 +6865,6 @@ module_param_named(11n_disable, il4965_mod_params.disable_11n, int, S_IRUGO); MODULE_PARM_DESC(11n_disable, "disable 11n functionality"); module_param_named(amsdu_size_8K, il4965_mod_params.amsdu_size_8K, int, S_IRUGO); -MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); +MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0 [disabled])"); module_param_named(fw_restart, il4965_mod_params.restart_fw, int, S_IRUGO); MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h index 13145ad2c0db..dfb13c70efe8 100644 --- a/drivers/net/wireless/iwlegacy/common.h +++ b/drivers/net/wireless/iwlegacy/common.h @@ -1598,7 +1598,7 @@ struct il_mod_params { int disable_hw_scan; /* def: 0 = use h/w scan */ int num_of_queues; /* def: HW dependent */ int disable_11n; /* def: 0 = 11n capabilities enabled */ - int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ + int amsdu_size_8K; /* def: 0 = disable 8K amsdu size */ int antenna; /* def: 0 = both antennas (use diversity) */ int restart_fw; /* def: 1 = restart firmware */ }; From f3355dd9f7c261d2a3e505ba5c62ffe3cd4df97a Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 4 Mar 2014 16:53:47 -0600 Subject: [PATCH 397/414] rtlwifi: rtl8192ce: rtl8192cu: rtl8192de: rtl8192se: rtl8723ae: rtl8723be: rtl8188eu: Modify for new API The addition of a driver for the RTL8821AE requires a new API for the fill_tx_desc() and set_desc() callback routines. This commit makes the appropriate modifications in all the other drivers. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- .../wireless/rtlwifi/btcoexist/halbtcoutsrc.c | 2 +- drivers/net/wireless/rtlwifi/pci.c | 64 +++--- drivers/net/wireless/rtlwifi/pci.h | 10 + drivers/net/wireless/rtlwifi/rtl8188ee/trx.c | 8 +- drivers/net/wireless/rtlwifi/rtl8188ee/trx.h | 8 +- drivers/net/wireless/rtlwifi/rtl8192ce/trx.c | 5 +- drivers/net/wireless/rtlwifi/rtl8192ce/trx.h | 7 +- drivers/net/wireless/rtlwifi/rtl8192cu/trx.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192cu/trx.h | 2 +- drivers/net/wireless/rtlwifi/rtl8192de/trx.c | 5 +- drivers/net/wireless/rtlwifi/rtl8192de/trx.h | 7 +- drivers/net/wireless/rtlwifi/rtl8192se/trx.c | 5 +- drivers/net/wireless/rtlwifi/rtl8192se/trx.h | 8 +- drivers/net/wireless/rtlwifi/rtl8723ae/trx.c | 5 +- drivers/net/wireless/rtlwifi/rtl8723ae/trx.h | 7 +- drivers/net/wireless/rtlwifi/rtl8723be/trx.c | 5 +- drivers/net/wireless/rtlwifi/rtl8723be/trx.h | 7 +- drivers/net/wireless/rtlwifi/usb.c | 2 +- drivers/net/wireless/rtlwifi/wifi.h | 201 ++++++++++++++++-- 19 files changed, 282 insertions(+), 78 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c index 9e1217f2c966..b6722de64a31 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c @@ -980,7 +980,7 @@ void exhalbtc_set_chip_type(u8 chip_type) case BT_RTL8723A: gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_RTL8723A; break; - case BT_RTL8821: + case BT_RTL8821A: gl_bt_coexist.board_info.bt_chip_type = BTC_CHIP_RTL8821; break; case BT_RTL8723B: diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 257726860a43..f26f4ffc771d 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -811,19 +811,19 @@ done: if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress)) return; tmp_one = 1; - rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false, HW_DESC_RXBUFF_ADDR, (u8 *)&bufferaddress); - rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false, HW_DESC_RXPKT_LEN, (u8 *)&rtlpci->rxbuffersize); if (index == rtlpci->rxringcount - 1) - rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false, HW_DESC_RXERO, &tmp_one); - rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false, HW_DESC_RXOWN, &tmp_one); index = (index + 1) % rtlpci->rxringcount; @@ -983,6 +983,8 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) struct sk_buff *pskb = NULL; struct rtl_tx_desc *pdesc = NULL; struct rtl_tcb_desc tcb_desc; + /*This is for new trx flow*/ + struct rtl_tx_buffer_desc *pbuffer_desc = NULL; u8 temp_one = 1; memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); @@ -1004,11 +1006,12 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) info = IEEE80211_SKB_CB(pskb); pdesc = &ring->desc[0]; rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, - info, NULL, pskb, BEACON_QUEUE, &tcb_desc); + (u8 *)pbuffer_desc, info, NULL, pskb, + BEACON_QUEUE, &tcb_desc); __skb_queue_tail(&ring->queue, pskb); - rtlpriv->cfg->ops->set_desc((u8 *) pdesc, true, HW_DESC_OWN, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, HW_DESC_OWN, &temp_one); return; @@ -1113,7 +1116,7 @@ static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw, ((i + 1) % entries) * sizeof(*ring); - rtlpriv->cfg->ops->set_desc((u8 *)&(ring[i]), + rtlpriv->cfg->ops->set_desc(hw, (u8 *)&(ring[i]), true, HW_DESC_TX_NEXTDESC_ADDR, (u8 *)&nextdescaddress); } @@ -1188,19 +1191,19 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw) dev_kfree_skb_any(skb); return 1; } - rtlpriv->cfg->ops->set_desc((u8 *)entry, false, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, HW_DESC_RXBUFF_ADDR, (u8 *)&bufferaddress); - rtlpriv->cfg->ops->set_desc((u8 *)entry, false, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, HW_DESC_RXPKT_LEN, (u8 *)&rtlpci-> rxbuffersize); - rtlpriv->cfg->ops->set_desc((u8 *) entry, false, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, HW_DESC_RXOWN, &tmp_one); } - rtlpriv->cfg->ops->set_desc((u8 *) entry, false, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, HW_DESC_RXERO, &tmp_one); } return 0; @@ -1331,7 +1334,7 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw) for (i = 0; i < rtlpci->rxringcount; i++) { entry = &rtlpci->rx_ring[rx_queue_idx].desc[i]; - rtlpriv->cfg->ops->set_desc((u8 *) entry, + rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false, HW_DESC_RXOWN, &tmp_one); @@ -1424,6 +1427,7 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct rtl8192_tx_ring *ring; struct rtl_tx_desc *pdesc; + struct rtl_tx_buffer_desc *ptx_bd_desc = NULL; u8 idx; u8 hw_queue = _rtl_mac_to_hwqueue(hw, skb); unsigned long flags; @@ -1464,17 +1468,22 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, idx = 0; pdesc = &ring->desc[idx]; - own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, - true, HW_DESC_OWN); + if (rtlpriv->use_new_trx_flow) { + ptx_bd_desc = &ring->buffer_desc[idx]; + } else { + own = (u8) rtlpriv->cfg->ops->get_desc((u8 *)pdesc, + true, HW_DESC_OWN); - if ((own == 1) && (hw_queue != BEACON_QUEUE)) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - "No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n", - hw_queue, ring->idx, idx, - skb_queue_len(&ring->queue)); + if ((own == 1) && (hw_queue != BEACON_QUEUE)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n", + hw_queue, ring->idx, idx, + skb_queue_len(&ring->queue)); - spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); - return skb->len; + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, + flags); + return skb->len; + } } if (ieee80211_is_data_qos(fc)) { @@ -1494,17 +1503,20 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, - info, sta, skb, hw_queue, ptcb_desc); + (u8 *)ptx_bd_desc, info, sta, skb, hw_queue, ptcb_desc); __skb_queue_tail(&ring->queue, skb); - rtlpriv->cfg->ops->set_desc((u8 *)pdesc, true, - HW_DESC_OWN, &temp_one); - + if (rtlpriv->use_new_trx_flow) { + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, + HW_DESC_OWN, (u8 *)&hw_queue); + } else { + rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, + HW_DESC_OWN, (u8 *)&temp_one); + } if ((ring->entries - skb_queue_len(&ring->queue)) < 2 && hw_queue != BEACON_QUEUE) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, "less desc left, stop skb_queue@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n", hw_queue, ring->idx, idx, diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h index 2a3333523ac4..90174a814a6d 100644 --- a/drivers/net/wireless/rtlwifi/pci.h +++ b/drivers/net/wireless/rtlwifi/pci.h @@ -137,12 +137,22 @@ struct rtl_tx_cmd_desc { u32 dword[16]; } __packed; +/* In new TRX flow, Buffer_desc is new concept + * But TX wifi info == TX descriptor in old flow + * RX wifi info == RX descriptor in old flow + */ +struct rtl_tx_buffer_desc { + u32 dword[8]; /*seg = 4*/ +} __packed; + struct rtl8192_tx_ring { struct rtl_tx_desc *desc; dma_addr_t dma; unsigned int idx; unsigned int entries; struct sk_buff_head queue; + /*add for new trx flow*/ + struct rtl_tx_buffer_desc *buffer_desc; /*tx buffer descriptor*/ }; struct rtl8192_rx_ring { diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c index 27ace3054d56..2ba6f510d884 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c @@ -489,9 +489,8 @@ bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw, void rtl88ee_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, - struct ieee80211_sta *sta, - struct sk_buff *skb, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -734,7 +733,8 @@ void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw, pdesc, TX_DESC_SIZE); } -void rtl88ee_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +void rtl88ee_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val) { if (istx == true) { switch (desc_name) { diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h index 21ca33a7c770..8c2609412d2c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h @@ -777,15 +777,15 @@ struct rx_desc_88e { void rtl88ee_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, - struct ieee80211_sta *sta, - struct sk_buff *skb, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc); bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *status, struct ieee80211_rx_status *rx_status, u8 *pdesc, struct sk_buff *skb); -void rtl88ee_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +void rtl88ee_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val); u32 rtl88ee_get_desc(u8 *pdesc, bool istx, u8 desc_name); void rtl88ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index 114858d46158..8f04817cb7ec 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -426,7 +426,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *tcb_desc) @@ -666,7 +666,8 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, "H2C Tx Cmd Content", pdesc, TX_DESC_SIZE); } -void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +void rtl92ce_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val) { if (istx) { switch (desc_name) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h index a7cdd514cb2e..9a39ec4204dd 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h @@ -711,8 +711,8 @@ struct rx_desc_92c { } __packed; void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, - struct ieee80211_hdr *hdr, - u8 *pdesc, struct ieee80211_tx_info *info, + struct ieee80211_hdr *hdr, u8 *pdesc, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc); @@ -720,7 +720,8 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, struct ieee80211_rx_status *rx_status, u8 *pdesc, struct sk_buff *skb); -void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +void rtl92ce_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val); u32 rtl92ce_get_desc(u8 *pdesc, bool istx, u8 desc_name); void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index 1bc21ccfa71b..035e0dc3922c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -495,7 +495,7 @@ static void _rtl_tx_desc_checksum(u8 *txdesc) void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 queue_index, diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h index 725c53accc58..fd8051dcd98a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h @@ -420,7 +420,7 @@ struct sk_buff *rtl8192c_tx_aggregate_hdl(struct ieee80211_hw *, struct sk_buff_head *); void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 queue_index, diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c index 0eb0f4ae5920..99c2ab5dfceb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c @@ -545,7 +545,7 @@ static void _rtl92de_insert_emcontent(struct rtl_tcb_desc *ptcb_desc, void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) @@ -786,7 +786,8 @@ void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw, SET_TX_DESC_OWN(pdesc, 1); } -void rtl92de_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +void rtl92de_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val) { if (istx) { switch (desc_name) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.h b/drivers/net/wireless/rtlwifi/rtl8192de/trx.h index c1b5dfb79d53..fb5cf0634e8d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.h @@ -728,8 +728,8 @@ struct rx_desc_92d { } __packed; void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, - struct ieee80211_hdr *hdr, - u8 *pdesc, struct ieee80211_tx_info *info, + struct ieee80211_hdr *hdr, u8 *pdesc, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc); @@ -737,7 +737,8 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, struct ieee80211_rx_status *rx_status, u8 *pdesc, struct sk_buff *skb); -void rtl92de_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +void rtl92de_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val); u32 rtl92de_get_desc(u8 *pdesc, bool istx, u8 desc_name); void rtl92de_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c index 163a681962c6..36b48be8329c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c @@ -336,7 +336,7 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) @@ -573,7 +573,8 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, } } -void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +void rtl92se_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val) { if (istx) { switch (desc_name) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.h b/drivers/net/wireless/rtlwifi/rtl8192se/trx.h index 64dd66f287c1..5a13f17e3b41 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.h @@ -29,8 +29,9 @@ #ifndef __REALTEK_PCI92SE_TRX_H__ #define __REALTEK_PCI92SE_TRX_H__ -void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, - u8 *pdesc, struct ieee80211_tx_info *info, +void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc); @@ -39,7 +40,8 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, struct ieee80211_rx_status *rx_status, u8 *pdesc, struct sk_buff *skb); -void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +void rtl92se_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val); u32 rtl92se_get_desc(u8 *pdesc, bool istx, u8 desc_name); void rtl92se_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c index 721162cacc3a..29adf55c6fd3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c @@ -365,7 +365,7 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw, void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcdesc) @@ -597,7 +597,8 @@ void rtl8723ae_tx_fill_cmddesc(struct ieee80211_hw *hw, pdesc, TX_DESC_SIZE); } -void rtl8723ae_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +void rtl8723ae_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val) { if (istx == true) { switch (desc_name) { diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h index c75bfe8d570c..4380b7d3a91a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h @@ -700,8 +700,8 @@ struct rx_desc_8723e { } __packed; void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw, - struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, + struct ieee80211_hdr *hdr, u8 *pdesc, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc); @@ -709,7 +709,8 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *status, struct ieee80211_rx_status *rx_status, u8 *pdesc, struct sk_buff *skb); -void rtl8723ae_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +void rtl8723ae_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val); u32 rtl8723ae_get_desc(u8 *pdesc, bool istx, u8 desc_name); void rtl8723ae_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); void rtl8723ae_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/trx.c b/drivers/net/wireless/rtlwifi/rtl8723be/trx.c index 7779531919fb..74a75dceab08 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/trx.c @@ -639,7 +639,7 @@ bool rtl8723be_rx_query_desc(struct ieee80211_hw *hw, void rtl8723be_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) { @@ -858,7 +858,8 @@ void rtl8723be_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, SET_TX_DESC_USE_RATE(pdesc, 1); } -void rtl8723be_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +void rtl8723be_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val) { if (istx) { switch (desc_name) { diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/trx.h b/drivers/net/wireless/rtlwifi/rtl8723be/trx.h index d375cf01c3dc..102f33dcc988 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8723be/trx.h @@ -597,15 +597,16 @@ struct rx_desc_8723be { } __packed; void rtl8723be_tx_fill_desc(struct ieee80211_hw *hw, - struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, + struct ieee80211_hdr *hdr, u8 *pdesc, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc); bool rtl8723be_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *status, struct ieee80211_rx_status *rx_status, u8 *pdesc, struct sk_buff *skb); -void rtl8723be_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +void rtl8723be_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val); u32 rtl8723be_get_desc(u8 *pdesc, bool istx, u8 desc_name); bool rtl8723be_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, u16 index); diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 4e2a726cdb16..0398d3ea15b0 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -994,7 +994,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, seq_number += 1; seq_number <<= 4; } - rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, info, sta, skb, + rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, NULL, info, sta, skb, hw_queue, &tcb_desc); if (!ieee80211_has_morefrags(hdr->frame_control)) { if (qc) diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 2304c7f23361..5cb799e6bd08 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -41,6 +41,22 @@ #include #include "debug.h" +#define MASKBYTE0 0xff +#define MASKBYTE1 0xff00 +#define MASKBYTE2 0xff0000 +#define MASKBYTE3 0xff000000 +#define MASKHWORD 0xffff0000 +#define MASKLWORD 0x0000ffff +#define MASKDWORD 0xffffffff +#define MASK12BITS 0xfff +#define MASKH4BITS 0xf0000000 +#define MASKOFDM_D 0xffc00000 +#define MASKCCK 0x3f3f3f3f + +#define MASK4BITS 0x0f +#define MASK20BITS 0xfffff +#define RFREG_OFFSET_MASK 0xfffff + #define RF_CHANGE_BY_INIT 0 #define RF_CHANGE_BY_IPS BIT(28) #define RF_CHANGE_BY_PS BIT(29) @@ -87,7 +103,18 @@ #define MAC80211_4ADDR_LEN 30 #define CHANNEL_MAX_NUMBER (14 + 24 + 21) /* 14 is the max channel no */ +#define CHANNEL_MAX_NUMBER_2G 14 +#define CHANNEL_MAX_NUMBER_5G 54 /* Please refer to + *"phy_GetChnlGroup8812A" and + * "Hal_ReadTxPowerInfo8812A" + */ +#define CHANNEL_MAX_NUMBER_5G_80M 7 #define CHANNEL_GROUP_MAX (3 + 9) /* ch1~3, 4~9, 10~14 = three groups */ +#define CHANNEL_MAX_NUMBER_5G 54 /* Please refer to + *"phy_GetChnlGroup8812A" and + * "Hal_ReadTxPowerInfo8812A" + */ +#define CHANNEL_MAX_NUMBER_5G_80M 7 #define MAX_PG_GROUP 13 #define CHANNEL_GROUP_MAX_2G 3 #define CHANNEL_GROUP_IDX_5GL 3 @@ -115,6 +142,11 @@ #define MAX_BASE_NUM_IN_PHY_REG_PG_24G 6 #define MAX_BASE_NUM_IN_PHY_REG_PG_5G 5 +#define RTL8192EE_SEG_NUM 1 /* 0:2 seg, 1: 4 seg, 2: 8 seg */ + +#define DEL_SW_IDX_SZ 30 +#define BAND_NUM 3 + enum rf_tx_num { RF_1TX = 0, RF_2TX, @@ -140,6 +172,8 @@ struct txpower_info_5g { u8 ofdm_diff[MAX_RF_PATH][MAX_TX_COUNT]; u8 bw20_diff[MAX_RF_PATH][MAX_TX_COUNT]; u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw80_diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 bw160_diff[MAX_RF_PATH][MAX_TX_COUNT]; }; enum rate_section { @@ -186,6 +220,8 @@ enum hardware_type { HARDWARE_TYPE_RTL8723U, HARDWARE_TYPE_RTL8723BE, HARDWARE_TYPE_RTL8188EE, + HARDWARE_TYPE_RTL8821AE, + HARDWARE_TYPE_RTL8812AE, /* keep it last */ HARDWARE_TYPE_NUM @@ -230,6 +266,8 @@ enum hardware_type { enum scan_operation_backup_opt { SCAN_OPT_BACKUP = 0, + SCAN_OPT_BACKUP_BAND0 = 0, + SCAN_OPT_BACKUP_BAND1, SCAN_OPT_RESTORE, SCAN_OPT_MAX }; @@ -264,7 +302,9 @@ struct bb_reg_def { enum io_type { IO_CMD_PAUSE_DM_BY_SCAN = 0, - IO_CMD_RESUME_DM_BY_SCAN = 1, + IO_CMD_PAUSE_BAND0_DM_BY_SCAN = 0, + IO_CMD_PAUSE_BAND1_DM_BY_SCAN = 1, + IO_CMD_RESUME_DM_BY_SCAN = 2, }; enum hw_variables { @@ -331,6 +371,7 @@ enum hw_variables { HW_VAR_SET_RPWM, HW_VAR_H2C_FW_PWRMODE, HW_VAR_H2C_FW_JOINBSSRPT, + HW_VAR_H2C_FW_MEDIASTATUSRPT, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, HW_VAR_FW_PSMODE_STATUS, HW_VAR_RESUME_CLK_ON, @@ -364,6 +405,7 @@ enum hw_variables { HAL_DEF_WOWLAN, HW_VAR_MRC, HW_VAR_KEEP_ALIVE, + HW_VAR_NAV_UPPER, HW_VAR_MGT_FILTER, HW_VAR_CTRL_FILTER, @@ -423,6 +465,7 @@ enum hw_descs { HW_DESC_RXBUFF_ADDR, HW_DESC_RXPKT_LEN, HW_DESC_RXERO, + HW_DESC_RX_PREPARE, }; enum prime_sc { @@ -441,6 +484,7 @@ enum rf_type { enum ht_channel_width { HT_CHANNEL_WIDTH_20 = 0, HT_CHANNEL_WIDTH_20_40 = 1, + HT_CHANNEL_WIDTH_80 = 2, }; /* Ref: 802.11i sepc D10.0 7.3.2.25.1 @@ -505,6 +549,9 @@ enum rtl_var_map { MAC_RCR_ACRC32, MAC_RCR_ACF, MAC_RCR_AAP, + MAC_HIMR, + MAC_HIMRE, + MAC_HSISR, /*efuse map */ EFUSE_TEST, @@ -679,7 +726,9 @@ enum wireless_mode { WIRELESS_MODE_G = 0x04, WIRELESS_MODE_AUTO = 0x08, WIRELESS_MODE_N_24G = 0x10, - WIRELESS_MODE_N_5G = 0x20 + WIRELESS_MODE_N_5G = 0x20, + WIRELESS_MODE_AC_5G = 0x40, + WIRELESS_MODE_AC_24G = 0x80 }; #define IS_WIRELESS_MODE_A(wirelessmode) \ @@ -703,6 +752,8 @@ enum ratr_table_mode { RATR_INX_WIRELESS_B = 6, RATR_INX_WIRELESS_MC = 7, RATR_INX_WIRELESS_A = 8, + RATR_INX_WIRELESS_AC_5N = 8, + RATR_INX_WIRELESS_AC_24N = 9, }; enum rtl_link_state { @@ -837,8 +888,12 @@ struct wireless_stats { long signal_strength; u8 rx_rssi_percentage[4]; + u8 rx_evm_dbm[4]; u8 rx_evm_percentage[2]; + u16 rx_cfo_short[4]; + u16 rx_cfo_tail[4]; + struct rt_smooth_data ui_rssi; struct rt_smooth_data ui_link_quality; }; @@ -867,6 +922,10 @@ struct rate_adaptive { u32 ping_rssi_thresh_for_ra; u32 last_ratr; u8 pre_ratr_state; + u8 ldpc_thres; + bool use_ldpc; + bool lower_rts_rate; + bool is_special_data; }; struct regd_pair_mapping { @@ -875,6 +934,16 @@ struct regd_pair_mapping { u16 reg_2ghz_ctl; }; +struct dynamic_primary_cca { + u8 pricca_flag; + u8 intf_flag; + u8 intf_type; + u8 dup_rts_flag; + u8 monitor_flag; + u8 ch_offset; + u8 mf_state; +}; + struct rtl_regulatory { char alpha2[2]; u16 country_code; @@ -1010,11 +1079,14 @@ struct rtl_phy { u32 iqk_bb_backup[10]; bool iqk_initialized; + bool rfpath_rx_enable[MAX_RF_PATH]; + u8 reg_837; /* Dual mac */ bool need_iqk; struct iqk_matrix_regs iqk_matrix[IQK_MATRIX_SETTINGS_NUM]; bool rfpi_enable; + bool iqk_in_progress; u8 pwrgroup_cnt; u8 cck_high_power; @@ -1027,6 +1099,9 @@ struct rtl_phy { u8 txpwr_by_rate_base_24g[TX_PWR_BY_RATE_NUM_RF] [TX_PWR_BY_RATE_NUM_RF] [MAX_BASE_NUM_IN_PHY_REG_PG_24G]; + u8 txpwr_by_rate_base_5g[TX_PWR_BY_RATE_NUM_RF] + [TX_PWR_BY_RATE_NUM_RF] + [MAX_BASE_NUM_IN_PHY_REG_PG_5G]; u8 default_initialgain[4]; /* the current Tx power level */ @@ -1039,6 +1114,7 @@ struct rtl_phy { bool apk_done; u32 reg_rf3c[2]; /* pathA / pathB */ + u32 backup_rf_0x1a;/*92ee*/ /* bfsync */ u8 framesync; u32 framesync_c34; @@ -1047,6 +1123,7 @@ struct rtl_phy { struct phy_parameters hwparam_tables[MAX_TAB]; u16 rf_pathmap; + u8 hw_rof_enable; /*Enable GPIO[9] as WL RF HW PDn source*/ enum rt_polarity_ctl polarity_ctl; }; @@ -1174,6 +1251,7 @@ struct rtl_mac { u8 use_cts_protect; u8 cur_40_prime_sc; u8 cur_40_prime_sc_bk; + u8 cur_80_prime_sc; u64 tsf; u8 retry_short; u8 retry_long; @@ -1276,6 +1354,7 @@ struct rtl_hal { /*Reserve page start offset except beacon in TxQ. */ u8 fw_rsvdpage_startoffset; u8 h2c_txcmd_seq; + u8 current_ra_rate; /* FW Cmd IO related */ u16 fwcmd_iomap; @@ -1315,6 +1394,9 @@ struct rtl_hal { bool disable_amsdu_8k; bool master_of_dmsp; bool slave_of_dmsp; + + u16 rx_tag;/*for 92ee*/ + u8 rts_en; }; struct rtl_security { @@ -1412,11 +1494,18 @@ struct rtl_dm { u8 txpower_track_control; bool interrupt_migration; bool disable_tx_int; - char ofdm_index[2]; + char ofdm_index[MAX_RF_PATH]; + u8 default_ofdm_index; + u8 default_cck_index; char cck_index; char delta_power_index[MAX_RF_PATH]; char delta_power_index_last[MAX_RF_PATH]; char power_index_offset[MAX_RF_PATH]; + char absolute_ofdm_swing_idx[MAX_RF_PATH]; + char remnant_ofdm_swing_idx[MAX_RF_PATH]; + char remnant_cck_idx; + bool modify_txagc_flag_path_a; + bool modify_txagc_flag_path_b; bool one_entry_only; struct dm_phy_dbg_info dbginfo; @@ -1431,9 +1520,10 @@ struct rtl_dm { u8 cfo_threshold; u32 packet_count; u32 packet_count_pre; + u8 tx_rate; /*88e tx power tracking*/ - u8 swing_idx_ofdm[2]; + u8 swing_idx_ofdm[MAX_RF_PATH]; u8 swing_idx_ofdm_cur; u8 swing_idx_ofdm_base[MAX_RF_PATH]; bool swing_flag_ofdm; @@ -1442,10 +1532,43 @@ struct rtl_dm { u8 swing_idx_cck_base; bool swing_flag_cck; + char swing_diff_2g; + char swing_diff_5g; + + u8 delta_swing_table_idx_24gccka_p[DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_24gccka_n[DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_24gcckb_p[DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_24gcckb_n[DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_24ga_p[DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_24ga_n[DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_24gb_p[DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_24gb_n[DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_5ga_p[BAND_NUM][DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_5ga_n[BAND_NUM][DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_5gb_p[BAND_NUM][DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_5gb_n[BAND_NUM][DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_24ga_p_8188e[DEL_SW_IDX_SZ]; + u8 delta_swing_table_idx_24ga_n_8188e[DEL_SW_IDX_SZ]; + /* DMSP */ bool supp_phymode_switch; + /* DulMac */ struct fast_ant_training fat_table; + + u8 resp_tx_path; + u8 path_sel; + u32 patha_sum; + u32 pathb_sum; + u32 patha_cnt; + u32 pathb_cnt; + + u8 pre_channel; + u8 *p_channel; + u8 linked_interval; + + u64 last_tx_ok_cnt; + u64 last_rx_ok_cnt; }; #define EFUSE_MAX_LOGICAL_SIZE 256 @@ -1491,11 +1614,6 @@ struct rtl_efuse { u8 eeprom_chnlarea_txpwr_cck[MAX_RF_PATH][CHANNEL_GROUP_MAX_2G]; u8 eeprom_chnlarea_txpwr_ht40_1s[MAX_RF_PATH][CHANNEL_GROUP_MAX]; u8 eprom_chnl_txpwr_ht40_2sdf[MAX_RF_PATH][CHANNEL_GROUP_MAX]; - u8 txpwrlevel_cck[2][CHANNEL_MAX_NUMBER_2G]; - /* For HT 40MHZ pwr */ - u8 txpwrlevel_ht40_1s[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; - u8 txpwrlevel_ht40_2s[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; - u8 txpwr_ht40diff[MAX_RF_PATH][MAX_TX_COUNT];/*BW40_24G_Diff*/ u8 internal_pa_5g[2]; /* pathA / pathB */ u8 eeprom_c9; @@ -1506,9 +1624,38 @@ struct rtl_efuse { u8 pwrgroup_ht20[2][CHANNEL_MAX_NUMBER]; u8 pwrgroup_ht40[2][CHANNEL_MAX_NUMBER]; - char txpwr_ht20diff[2][CHANNEL_MAX_NUMBER]; /*HT 20<->40 Pwr diff */ - /*For HT<->legacy pwr diff*/ - u8 txpwr_legacyhtdiff[2][CHANNEL_MAX_NUMBER]; + u8 txpwrlevel_cck[MAX_RF_PATH][CHANNEL_MAX_NUMBER_2G]; + /*For HT 40MHZ pwr */ + u8 txpwrlevel_ht40_1s[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + /*For HT 40MHZ pwr */ + u8 txpwrlevel_ht40_2s[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + + /*--------------------------------------------------------* + * 8192CE\8192SE\8192DE\8723AE use the following 4 arrays, + * other ICs (8188EE\8723BE\8192EE\8812AE...) + * define new arrays in Windows code. + * BUT, in linux code, we use the same array for all ICs. + * + * The Correspondance relation between two arrays is: + * txpwr_cckdiff[][] == CCK_24G_Diff[][] + * txpwr_ht20diff[][] == BW20_24G_Diff[][] + * txpwr_ht40diff[][] == BW40_24G_Diff[][] + * txpwr_legacyhtdiff[][] == OFDM_24G_Diff[][] + * + * Sizes of these arrays are decided by the larger ones. + */ + char txpwr_cckdiff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + char txpwr_ht20diff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + char txpwr_ht40diff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + char txpwr_legacyhtdiff[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + + u8 txpwr_5g_bw40base[MAX_RF_PATH][CHANNEL_MAX_NUMBER]; + u8 txpwr_5g_bw80base[MAX_RF_PATH][CHANNEL_MAX_NUMBER_5G_80M]; + char txpwr_5g_ofdmdiff[MAX_RF_PATH][MAX_TX_COUNT]; + char txpwr_5g_bw20diff[MAX_RF_PATH][MAX_TX_COUNT]; + char txpwr_5g_bw40diff[MAX_RF_PATH][MAX_TX_COUNT]; + char txpwr_5g_bw80diff[MAX_RF_PATH][MAX_TX_COUNT]; + u8 txpwr_safetyflag; /* Band edge enable flag */ u16 eeprom_txpowerdiff; u8 legacy_httxpowerdiff; /* Legacy to HT rate power diff */ @@ -1639,7 +1786,9 @@ struct rtl_stats { bool rx_is40Mhzpacket; u32 rx_pwdb_all; u8 rx_mimo_signalstrength[4]; /*in 0~100 index */ - s8 rx_mimo_sig_qual[2]; + s8 rx_mimo_sig_qual[4]; + u8 rx_pwr[4]; /* per-path's pwdb */ + u8 rx_snr[4]; /* per-path's SNR */ bool packet_matchbssid; bool is_cck; bool is_ht; @@ -1743,9 +1892,17 @@ struct rtl_hal_ops { void (*set_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val); void (*update_rate_tbl) (struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 rssi_level); + void (*pre_fill_tx_bd_desc)(struct ieee80211_hw *hw, u8 *tx_bd_desc, + u8 *desc, u8 queue_index, + struct sk_buff *skb, dma_addr_t addr); void (*update_rate_mask) (struct ieee80211_hw *hw, u8 rssi_level); + u16 (*rx_desc_buff_remained_cnt)(struct ieee80211_hw *hw, + u8 queue_index); + void (*rx_check_dma_ok)(struct ieee80211_hw *hw, u8 *header_desc, + u8 queue_index); void (*fill_tx_desc) (struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, + u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, u8 hw_queue, @@ -1768,7 +1925,8 @@ struct rtl_hal_ops { enum rf_pwrstate rfpwr_state); void (*led_control) (struct ieee80211_hw *hw, enum led_ctl_mode ledaction); - void (*set_desc) (u8 *pdesc, bool istx, u8 desc_name, u8 *val); + void (*set_desc)(struct ieee80211_hw *hw, u8 *pdesc, bool istx, + u8 desc_name, u8 *val); u32 (*get_desc) (u8 *pdesc, bool istx, u8 desc_name); bool (*is_tx_desc_closed) (struct ieee80211_hw *hw, u8 hw_queue, u16 index); @@ -1812,6 +1970,8 @@ struct rtl_hal_ops { u32 cmd_len, u8 *p_cmdbuffer); bool (*get_btc_status) (void); bool (*is_fw_header) (struct rtl92c_firmware_header *hdr); + u32 (*rx_command_packet)(struct ieee80211_hw *hw, + struct rtl_stats status, struct sk_buff *skb); }; struct rtl_intf_ops { @@ -1921,6 +2081,8 @@ struct rtl_locks { /*Easy concurrent*/ spinlock_t check_sendpkt_lock; + + spinlock_t iqk_lock; }; struct rtl_works { @@ -2014,6 +2176,7 @@ struct dig_t { u8 cursta_cstate; u8 presta_cstate; u8 curmultista_cstate; + u8 stop_dig; char back_val; char back_range_max; char back_range_min; @@ -2031,6 +2194,7 @@ struct dig_t { u8 cur_ccasate; u8 large_fa_hit; u8 dig_dynamic_min; + u8 dig_dynamic_min_1; u8 forbidden_igi; u8 dig_state; u8 dig_highpwrstate; @@ -2174,6 +2338,7 @@ struct rtl_priv { struct rtl_ps_ctl psc; struct rate_adaptive ra; + struct dynamic_primary_cca primarycca; struct wireless_stats stats; struct rt_link_detect link_info; struct false_alarm_statistics falsealm_cnt; @@ -2259,9 +2424,15 @@ enum bt_co_type { BT_CSR_BC8 = 4, BT_RTL8756 = 5, BT_RTL8723A = 6, - BT_RTL8821 = 7, + BT_RTL8821A = 7, BT_RTL8723B = 8, BT_RTL8192E = 9, + BT_RTL8812A = 11, +}; + +enum bt_total_ant_num { + ANT_TOTAL_X2 = 0, + ANT_TOTAL_X1 = 1 }; enum bt_cur_state { From 25b13dbc38a74b76da5746d75867e306b70035bd Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 4 Mar 2014 16:53:48 -0600 Subject: [PATCH 398/414] rtlwifi: Move common routines to core Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- .../rtlwifi/btcoexist/halbt_precomp.h | 12 - drivers/net/wireless/rtlwifi/core.c | 60 +++ drivers/net/wireless/rtlwifi/core.h | 4 + drivers/net/wireless/rtlwifi/ps.c | 100 ++++ drivers/net/wireless/rtlwifi/ps.h | 60 +++ .../net/wireless/rtlwifi/rtl8188ee/Makefile | 1 - drivers/net/wireless/rtlwifi/rtl8188ee/hw.c | 19 +- drivers/net/wireless/rtlwifi/rtl8188ee/phy.c | 61 +-- .../net/wireless/rtlwifi/rtl8188ee/pwrseq.h | 1 - drivers/net/wireless/rtlwifi/rtl8188ee/reg.h | 16 - drivers/net/wireless/rtlwifi/rtl8192ce/phy.c | 71 +-- drivers/net/wireless/rtlwifi/rtl8192ce/reg.h | 16 - drivers/net/wireless/rtlwifi/rtl8192cu/phy.c | 71 +-- drivers/net/wireless/rtlwifi/rtl8192de/dm.c | 50 +- drivers/net/wireless/rtlwifi/rtl8192de/hw.c | 10 +- drivers/net/wireless/rtlwifi/rtl8192de/phy.c | 429 ++++++++---------- drivers/net/wireless/rtlwifi/rtl8192de/reg.h | 14 - drivers/net/wireless/rtlwifi/rtl8192de/rf.c | 6 +- drivers/net/wireless/rtlwifi/rtl8192se/phy.c | 87 +--- drivers/net/wireless/rtlwifi/rtl8192se/reg.h | 12 - .../net/wireless/rtlwifi/rtl8723ae/Makefile | 1 - drivers/net/wireless/rtlwifi/rtl8723ae/hw.c | 1 - drivers/net/wireless/rtlwifi/rtl8723ae/phy.c | 48 +- .../net/wireless/rtlwifi/rtl8723ae/pwrseq.h | 1 - drivers/net/wireless/rtlwifi/rtl8723ae/reg.h | 16 - .../net/wireless/rtlwifi/rtl8723be/Makefile | 1 - drivers/net/wireless/rtlwifi/rtl8723be/hw.c | 15 +- drivers/net/wireless/rtlwifi/rtl8723be/phy.c | 29 +- .../net/wireless/rtlwifi/rtl8723be/pwrseq.h | 1 - drivers/net/wireless/rtlwifi/rtl8723be/reg.h | 16 - drivers/net/wireless/rtlwifi/wifi.h | 16 + 31 files changed, 520 insertions(+), 725 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h b/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h index 582532fc199a..d76684eb24d0 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h @@ -72,16 +72,4 @@ #define BIT30 0x40000000 #define BIT31 0x80000000 -#define MASKBYTE0 0xff -#define MASKBYTE1 0xff00 -#define MASKBYTE2 0xff0000 -#define MASKBYTE3 0xff000000 -#define MASKHWORD 0xffff0000 -#define MASKLWORD 0x0000ffff -#define MASKDWORD 0xffffffff -#define MASK12BITS 0xfff -#define MASKH4BITS 0xf0000000 -#define MASKOFDM_D 0xffc00000 -#define MASKCCK 0x3f3f3f3f - #endif /* __HALBT_PRECOMP_H__ */ diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 724b830fe429..ded691f76f2f 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -36,6 +36,66 @@ #include +void rtl_addr_delay(u32 addr) +{ + if (addr == 0xfe) + mdelay(50); + else if (addr == 0xfd) + mdelay(5); + else if (addr == 0xfc) + mdelay(1); + else if (addr == 0xfb) + udelay(50); + else if (addr == 0xfa) + udelay(5); + else if (addr == 0xf9) + udelay(1); +} +EXPORT_SYMBOL(rtl_addr_delay); + +void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr, + u32 mask, u32 data) +{ + if (addr == 0xfe) { + mdelay(50); + } else if (addr == 0xfd) { + mdelay(5); + } else if (addr == 0xfc) { + mdelay(1); + } else if (addr == 0xfb) { + udelay(50); + } else if (addr == 0xfa) { + udelay(5); + } else if (addr == 0xf9) { + udelay(1); + } else { + rtl_set_rfreg(hw, rfpath, addr, mask, data); + udelay(1); + } +} +EXPORT_SYMBOL(rtl_rfreg_delay); + +void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data) +{ + if (addr == 0xfe) { + mdelay(50); + } else if (addr == 0xfd) { + mdelay(5); + } else if (addr == 0xfc) { + mdelay(1); + } else if (addr == 0xfb) { + udelay(50); + } else if (addr == 0xfa) { + udelay(5); + } else if (addr == 0xf9) { + udelay(1); + } else { + rtl_set_bbreg(hw, addr, MASKDWORD, data); + udelay(1); + } +} +EXPORT_SYMBOL(rtl_bb_delay); + void rtl_fw_cb(const struct firmware *firmware, void *context) { struct ieee80211_hw *hw = context; diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h index 2fe46a1b4f1f..027e75374dcc 100644 --- a/drivers/net/wireless/rtlwifi/core.h +++ b/drivers/net/wireless/rtlwifi/core.h @@ -41,5 +41,9 @@ extern const struct ieee80211_ops rtl_ops; void rtl_fw_cb(const struct firmware *firmware, void *context); +void rtl_addr_delay(u32 addr); +void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr, + u32 mask, u32 data); +void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data); #endif diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index d1c0191a195b..de7f05f848ef 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -32,6 +32,106 @@ #include "base.h" #include "ps.h" +/* Description: + * This routine deals with the Power Configuration CMD + * parsing for RTL8723/RTL8188E Series IC. + * Assumption: + * We should follow specific format that was released from HW SD. + */ +bool rtl_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version, + u8 faversion, u8 interface_type, + struct wlan_pwr_cfg pwrcfgcmd[]) +{ + struct wlan_pwr_cfg cfg_cmd = {0}; + bool polling_bit = false; + u32 ary_idx = 0; + u8 value = 0; + u32 offset = 0; + u32 polling_count = 0; + u32 max_polling_cnt = 5000; + + do { + cfg_cmd = pwrcfgcmd[ary_idx]; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "rtl_hal_pwrseqcmdparsing(): offset(%#x),cut_msk(%#x), famsk(%#x)," + "interface_msk(%#x), base(%#x), cmd(%#x), msk(%#x), value(%#x)\n", + GET_PWR_CFG_OFFSET(cfg_cmd), + GET_PWR_CFG_CUT_MASK(cfg_cmd), + GET_PWR_CFG_FAB_MASK(cfg_cmd), + GET_PWR_CFG_INTF_MASK(cfg_cmd), + GET_PWR_CFG_BASE(cfg_cmd), GET_PWR_CFG_CMD(cfg_cmd), + GET_PWR_CFG_MASK(cfg_cmd), GET_PWR_CFG_VALUE(cfg_cmd)); + + if ((GET_PWR_CFG_FAB_MASK(cfg_cmd)&faversion) && + (GET_PWR_CFG_CUT_MASK(cfg_cmd)&cut_version) && + (GET_PWR_CFG_INTF_MASK(cfg_cmd)&interface_type)) { + switch (GET_PWR_CFG_CMD(cfg_cmd)) { + case PWR_CMD_READ: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "rtl_hal_pwrseqcmdparsing(): PWR_CMD_READ\n"); + break; + case PWR_CMD_WRITE: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "rtl_hal_pwrseqcmdparsing(): PWR_CMD_WRITE\n"); + offset = GET_PWR_CFG_OFFSET(cfg_cmd); + + /*Read the value from system register*/ + value = rtl_read_byte(rtlpriv, offset); + value &= (~(GET_PWR_CFG_MASK(cfg_cmd))); + value |= (GET_PWR_CFG_VALUE(cfg_cmd) & + GET_PWR_CFG_MASK(cfg_cmd)); + + /*Write the value back to sytem register*/ + rtl_write_byte(rtlpriv, offset, value); + break; + case PWR_CMD_POLLING: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "rtl_hal_pwrseqcmdparsing(): PWR_CMD_POLLING\n"); + polling_bit = false; + offset = GET_PWR_CFG_OFFSET(cfg_cmd); + + do { + value = rtl_read_byte(rtlpriv, offset); + + value &= GET_PWR_CFG_MASK(cfg_cmd); + if (value == + (GET_PWR_CFG_VALUE(cfg_cmd) + & GET_PWR_CFG_MASK(cfg_cmd))) + polling_bit = true; + else + udelay(10); + + if (polling_count++ > max_polling_cnt) + return false; + } while (!polling_bit); + break; + case PWR_CMD_DELAY: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "rtl_hal_pwrseqcmdparsing(): PWR_CMD_DELAY\n"); + if (GET_PWR_CFG_VALUE(cfg_cmd) == + PWRSEQ_DELAY_US) + udelay(GET_PWR_CFG_OFFSET(cfg_cmd)); + else + mdelay(GET_PWR_CFG_OFFSET(cfg_cmd)); + break; + case PWR_CMD_END: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "rtl_hal_pwrseqcmdparsing(): PWR_CMD_END\n"); + return true; + default: + RT_ASSERT(false, + "rtl_hal_pwrseqcmdparsing(): Unknown CMD!!\n"); + break; + } + + } + ary_idx++; + } while (1); + + return true; +} +EXPORT_SYMBOL(rtl_hal_pwrseqcmdparsing); + bool rtl_ps_enable_nic(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); diff --git a/drivers/net/wireless/rtlwifi/ps.h b/drivers/net/wireless/rtlwifi/ps.h index 88bd76ea88f7..3bd41f958974 100644 --- a/drivers/net/wireless/rtlwifi/ps.h +++ b/drivers/net/wireless/rtlwifi/ps.h @@ -32,6 +32,66 @@ #define MAX_SW_LPS_SLEEP_INTV 5 +/*--------------------------------------------- + * 3 The value of cmd: 4 bits + *--------------------------------------------- + */ +#define PWR_CMD_READ 0x00 +#define PWR_CMD_WRITE 0x01 +#define PWR_CMD_POLLING 0x02 +#define PWR_CMD_DELAY 0x03 +#define PWR_CMD_END 0x04 + +/* define the base address of each block */ +#define PWR_BASEADDR_MAC 0x00 +#define PWR_BASEADDR_USB 0x01 +#define PWR_BASEADDR_PCIE 0x02 +#define PWR_BASEADDR_SDIO 0x03 + +#define PWR_FAB_ALL_MSK (BIT(0)|BIT(1)|BIT(2)|BIT(3)) +#define PWR_CUT_TESTCHIP_MSK BIT(0) +#define PWR_CUT_A_MSK BIT(1) +#define PWR_CUT_B_MSK BIT(2) +#define PWR_CUT_C_MSK BIT(3) +#define PWR_CUT_D_MSK BIT(4) +#define PWR_CUT_E_MSK BIT(5) +#define PWR_CUT_F_MSK BIT(6) +#define PWR_CUT_G_MSK BIT(7) +#define PWR_CUT_ALL_MSK 0xFF +#define PWR_INTF_SDIO_MSK BIT(0) +#define PWR_INTF_USB_MSK BIT(1) +#define PWR_INTF_PCI_MSK BIT(2) +#define PWR_INTF_ALL_MSK (BIT(0)|BIT(1)|BIT(2)|BIT(3)) + +enum pwrseq_delay_unit { + PWRSEQ_DELAY_US, + PWRSEQ_DELAY_MS, +}; + +struct wlan_pwr_cfg { + u16 offset; + u8 cut_msk; + u8 fab_msk:4; + u8 interface_msk:4; + u8 base:4; + u8 cmd:4; + u8 msk; + u8 value; +}; + +#define GET_PWR_CFG_OFFSET(__PWR_CMD) (__PWR_CMD.offset) +#define GET_PWR_CFG_CUT_MASK(__PWR_CMD) (__PWR_CMD.cut_msk) +#define GET_PWR_CFG_FAB_MASK(__PWR_CMD) (__PWR_CMD.fab_msk) +#define GET_PWR_CFG_INTF_MASK(__PWR_CMD) (__PWR_CMD.interface_msk) +#define GET_PWR_CFG_BASE(__PWR_CMD) (__PWR_CMD.base) +#define GET_PWR_CFG_CMD(__PWR_CMD) (__PWR_CMD.cmd) +#define GET_PWR_CFG_MASK(__PWR_CMD) (__PWR_CMD.msk) +#define GET_PWR_CFG_VALUE(__PWR_CMD) (__PWR_CMD.value) + +bool rtl_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version, + u8 fab_version, u8 interface_type, + struct wlan_pwr_cfg pwrcfgcmd[]); + bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, enum rf_pwrstate state_toset, u32 changesource); bool rtl_ps_enable_nic(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/Makefile b/drivers/net/wireless/rtlwifi/rtl8188ee/Makefile index 5b194e97f4b3..a85419a37651 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/Makefile +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/Makefile @@ -5,7 +5,6 @@ rtl8188ee-objs := \ led.o \ phy.o \ pwrseq.o \ - pwrseqcmd.o \ rf.o \ sw.o \ table.o \ diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c index d608d75ff6ff..6561805c3a88 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c @@ -41,7 +41,6 @@ #include "fw.h" #include "led.h" #include "hw.h" -#include "pwrseqcmd.h" #include "pwrseq.h" #define LLT_CONFIG 5 @@ -815,11 +814,11 @@ static bool _rtl88ee_init_mac(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00); /* HW Power on sequence */ - if (!rtl88_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, - PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, - Rtl8188E_NIC_ENABLE_FLOW)) { + if (!rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, + PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, + Rtl8188E_NIC_ENABLE_FLOW)) { RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "init MAC Fail as rtl88_hal_pwrseqcmdparsing\n"); + "init MAC Fail as rtl_hal_pwrseqcmdparsing\n"); return false; } @@ -1346,9 +1345,9 @@ static void _rtl88ee_poweroff_adapter(struct ieee80211_hw *hw) } rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG+1, 0xFF); - rtl88_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, - PWR_INTF_PCI_MSK, - Rtl8188E_NIC_LPS_ENTER_FLOW); + rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, + PWR_INTF_PCI_MSK, + Rtl8188E_NIC_LPS_ENTER_FLOW); rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00); @@ -1362,8 +1361,8 @@ static void _rtl88ee_poweroff_adapter(struct ieee80211_hw *hw) u1b_tmp = rtl_read_byte(rtlpriv, REG_32K_CTRL); rtl_write_byte(rtlpriv, REG_32K_CTRL, (u1b_tmp & (~BIT(0)))); - rtl88_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, - PWR_INTF_PCI_MSK, Rtl8188E_NIC_DISABLE_FLOW); + rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, + PWR_INTF_PCI_MSK, Rtl8188E_NIC_DISABLE_FLOW); u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL+1); rtl_write_byte(rtlpriv, REG_RSV_CTRL+1, (u1b_tmp & (~BIT(3)))); diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c index 54d4ec2dc26b..1cd6c16d597e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c @@ -29,6 +29,7 @@ #include "../wifi.h" #include "../pci.h" +#include "../core.h" #include "../ps.h" #include "reg.h" #include "def.h" @@ -151,18 +152,7 @@ static bool config_bb_with_pgheader(struct ieee80211_hw *hw, v2 = table_pg[i + 1]; if (v1 < 0xcdcdcdcd) { - if (table_pg[i] == 0xfe) - mdelay(50); - else if (table_pg[i] == 0xfd) - mdelay(5); - else if (table_pg[i] == 0xfc) - mdelay(1); - else if (table_pg[i] == 0xfb) - udelay(50); - else if (table_pg[i] == 0xfa) - udelay(5); - else if (table_pg[i] == 0xf9) - udelay(1); + rtl_addr_delay(table_pg[i]); store_pwrindex_offset(hw, table_pg[i], table_pg[i + 1], @@ -672,24 +662,9 @@ static void _rtl8188e_config_rf_reg(struct ieee80211_hw *hw, u32 addr, u32 data, enum radio_path rfpath, u32 regaddr) { - if (addr == 0xffe) { - mdelay(50); - } else if (addr == 0xfd) { - mdelay(5); - } else if (addr == 0xfc) { - mdelay(1); - } else if (addr == 0xfb) { - udelay(50); - } else if (addr == 0xfa) { - udelay(5); - } else if (addr == 0xf9) { - udelay(1); - } else { - rtl_set_rfreg(hw, rfpath, regaddr, - RFREG_OFFSET_MASK, - data); - udelay(1); - } + rtl_rfreg_delay(hw, rfpath, regaddr, + RFREG_OFFSET_MASK, + data); } static void rtl88_config_s(struct ieee80211_hw *hw, @@ -702,28 +677,6 @@ static void rtl88_config_s(struct ieee80211_hw *hw, addr | maskforphyset); } -static void _rtl8188e_config_bb_reg(struct ieee80211_hw *hw, - u32 addr, u32 data) -{ - if (addr == 0xfe) { - mdelay(50); - } else if (addr == 0xfd) { - mdelay(5); - } else if (addr == 0xfc) { - mdelay(1); - } else if (addr == 0xfb) { - udelay(50); - } else if (addr == 0xfa) { - udelay(5); - } else if (addr == 0xf9) { - udelay(1); - } else { - rtl_set_bbreg(hw, addr, MASKDWORD, data); - udelay(1); - } -} - - #define NEXT_PAIR(v1, v2, i) \ do { \ i += 2; v1 = array_table[i]; \ @@ -795,7 +748,7 @@ static void set_baseband_phy_config(struct ieee80211_hw *hw) v1 = array_table[i]; v2 = array_table[i + 1]; if (v1 < 0xcdcdcdcd) { - _rtl8188e_config_bb_reg(hw, v1, v2); + rtl_bb_delay(hw, v1, v2); } else {/*This line is the start line of branch.*/ if (!check_cond(hw, array_table[i])) { /*Discard the following (offset, data) pairs*/ @@ -811,7 +764,7 @@ static void set_baseband_phy_config(struct ieee80211_hw *hw) while (v2 != 0xDEAD && v2 != 0xCDEF && v2 != 0xCDCD && i < arraylen - 2) { - _rtl8188e_config_bb_reg(hw, v1, v2); + rtl_bb_delay(hw, v1, v2); NEXT_PAIR(v1, v2, i); } diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h index 028ec6dd52b4..32e135ab9a63 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h @@ -30,7 +30,6 @@ #ifndef __RTL8723E_PWRSEQ_H__ #define __RTL8723E_PWRSEQ_H__ -#include "pwrseqcmd.h" /* Check document WM-20110607-Paul-RTL8188E_Power_Architecture-R02.vsd There are 6 HW Power States: diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h b/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h index d849abf7d94a..7af85cfa8f87 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h @@ -2215,22 +2215,6 @@ #define BWORD1 0xc #define BWORD 0xf -#define MASKBYTE0 0xff -#define MASKBYTE1 0xff00 -#define MASKBYTE2 0xff0000 -#define MASKBYTE3 0xff000000 -#define MASKHWORD 0xffff0000 -#define MASKLWORD 0x0000ffff -#define MASKDWORD 0xffffffff -#define MASK12BITS 0xfff -#define MASKH4BITS 0xf0000000 -#define MASKOFDM_D 0xffc00000 -#define MASKCCK 0x3f3f3f3f - -#define MASK4BITS 0x0f -#define MASK20BITS 0xfffff -#define RFREG_OFFSET_MASK 0xfffff - #define BENABLE 0x1 #define BDISABLE 0x0 diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c index 73262ca3864b..98b22303c84d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c @@ -30,6 +30,7 @@ #include "../wifi.h" #include "../pci.h" #include "../ps.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "hw.h" @@ -198,18 +199,7 @@ bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, } if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_reg_arraylen; i = i + 2) { - if (phy_regarray_table[i] == 0xfe) - mdelay(50); - else if (phy_regarray_table[i] == 0xfd) - mdelay(5); - else if (phy_regarray_table[i] == 0xfc) - mdelay(1); - else if (phy_regarray_table[i] == 0xfb) - udelay(50); - else if (phy_regarray_table[i] == 0xfa) - udelay(5); - else if (phy_regarray_table[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_regarray_table[i]); rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD, phy_regarray_table[i + 1]); udelay(1); @@ -245,18 +235,7 @@ bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_regarray_pg_len; i = i + 3) { - if (phy_regarray_table_pg[i] == 0xfe) - mdelay(50); - else if (phy_regarray_table_pg[i] == 0xfd) - mdelay(5); - else if (phy_regarray_table_pg[i] == 0xfc) - mdelay(1); - else if (phy_regarray_table_pg[i] == 0xfb) - udelay(50); - else if (phy_regarray_table_pg[i] == 0xfa) - udelay(5); - else if (phy_regarray_table_pg[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_regarray_table_pg[i]); _rtl92c_store_pwrIndex_diffrate_offset(hw, phy_regarray_table_pg[i], @@ -305,46 +284,16 @@ bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, switch (rfpath) { case RF90_PATH_A: for (i = 0; i < radioa_arraylen; i = i + 2) { - if (radioa_array_table[i] == 0xfe) - mdelay(50); - else if (radioa_array_table[i] == 0xfd) - mdelay(5); - else if (radioa_array_table[i] == 0xfc) - mdelay(1); - else if (radioa_array_table[i] == 0xfb) - udelay(50); - else if (radioa_array_table[i] == 0xfa) - udelay(5); - else if (radioa_array_table[i] == 0xf9) - udelay(1); - else { - rtl_set_rfreg(hw, rfpath, radioa_array_table[i], - RFREG_OFFSET_MASK, - radioa_array_table[i + 1]); - udelay(1); - } + rtl_rfreg_delay(hw, rfpath, radioa_array_table[i], + RFREG_OFFSET_MASK, + radioa_array_table[i + 1]); } break; case RF90_PATH_B: for (i = 0; i < radiob_arraylen; i = i + 2) { - if (radiob_array_table[i] == 0xfe) { - mdelay(50); - } else if (radiob_array_table[i] == 0xfd) - mdelay(5); - else if (radiob_array_table[i] == 0xfc) - mdelay(1); - else if (radiob_array_table[i] == 0xfb) - udelay(50); - else if (radiob_array_table[i] == 0xfa) - udelay(5); - else if (radiob_array_table[i] == 0xf9) - udelay(1); - else { - rtl_set_rfreg(hw, rfpath, radiob_array_table[i], - RFREG_OFFSET_MASK, - radiob_array_table[i + 1]); - udelay(1); - } + rtl_rfreg_delay(hw, rfpath, radiob_array_table[i], + RFREG_OFFSET_MASK, + radiob_array_table[i + 1]); } break; case RF90_PATH_C: @@ -355,6 +304,8 @@ bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "switch case not processed\n"); break; + default: + break; } return true; } diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h index 8922ecb47ad2..ed703a1b3b7c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h @@ -2044,22 +2044,6 @@ #define BWORD1 0xc #define BWORD 0xf -#define MASKBYTE0 0xff -#define MASKBYTE1 0xff00 -#define MASKBYTE2 0xff0000 -#define MASKBYTE3 0xff000000 -#define MASKHWORD 0xffff0000 -#define MASKLWORD 0x0000ffff -#define MASKDWORD 0xffffffff -#define MASK12BITS 0xfff -#define MASKH4BITS 0xf0000000 -#define MASKOFDM_D 0xffc00000 -#define MASKCCK 0x3f3f3f3f - -#define MASK4BITS 0x0f -#define MASK20BITS 0xfffff -#define RFREG_OFFSET_MASK 0xfffff - #define BENABLE 0x1 #define BDISABLE 0x0 diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c index 0c09240eadcc..9831ff1128ca 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c @@ -30,6 +30,7 @@ #include "../wifi.h" #include "../pci.h" #include "../ps.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" @@ -188,18 +189,7 @@ bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, } if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_reg_arraylen; i = i + 2) { - if (phy_regarray_table[i] == 0xfe) - mdelay(50); - else if (phy_regarray_table[i] == 0xfd) - mdelay(5); - else if (phy_regarray_table[i] == 0xfc) - mdelay(1); - else if (phy_regarray_table[i] == 0xfb) - udelay(50); - else if (phy_regarray_table[i] == 0xfa) - udelay(5); - else if (phy_regarray_table[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_regarray_table[i]); rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD, phy_regarray_table[i + 1]); udelay(1); @@ -236,18 +226,7 @@ bool _rtl92cu_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, phy_regarray_table_pg = rtlphy->hwparam_tables[PHY_REG_PG].pdata; if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_regarray_pg_len; i = i + 3) { - if (phy_regarray_table_pg[i] == 0xfe) - mdelay(50); - else if (phy_regarray_table_pg[i] == 0xfd) - mdelay(5); - else if (phy_regarray_table_pg[i] == 0xfc) - mdelay(1); - else if (phy_regarray_table_pg[i] == 0xfb) - udelay(50); - else if (phy_regarray_table_pg[i] == 0xfa) - udelay(5); - else if (phy_regarray_table_pg[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_regarray_table_pg[i]); _rtl92c_store_pwrIndex_diffrate_offset(hw, phy_regarray_table_pg[i], phy_regarray_table_pg[i + 1], @@ -294,46 +273,16 @@ bool rtl92cu_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, switch (rfpath) { case RF90_PATH_A: for (i = 0; i < radioa_arraylen; i = i + 2) { - if (radioa_array_table[i] == 0xfe) - mdelay(50); - else if (radioa_array_table[i] == 0xfd) - mdelay(5); - else if (radioa_array_table[i] == 0xfc) - mdelay(1); - else if (radioa_array_table[i] == 0xfb) - udelay(50); - else if (radioa_array_table[i] == 0xfa) - udelay(5); - else if (radioa_array_table[i] == 0xf9) - udelay(1); - else { - rtl_set_rfreg(hw, rfpath, radioa_array_table[i], - RFREG_OFFSET_MASK, - radioa_array_table[i + 1]); - udelay(1); - } + rtl_rfreg_delay(hw, rfpath, radioa_array_table[i], + RFREG_OFFSET_MASK, + radioa_array_table[i + 1]); } break; case RF90_PATH_B: for (i = 0; i < radiob_arraylen; i = i + 2) { - if (radiob_array_table[i] == 0xfe) { - mdelay(50); - } else if (radiob_array_table[i] == 0xfd) - mdelay(5); - else if (radiob_array_table[i] == 0xfc) - mdelay(1); - else if (radiob_array_table[i] == 0xfb) - udelay(50); - else if (radiob_array_table[i] == 0xfa) - udelay(5); - else if (radiob_array_table[i] == 0xf9) - udelay(1); - else { - rtl_set_rfreg(hw, rfpath, radiob_array_table[i], - RFREG_OFFSET_MASK, - radiob_array_table[i + 1]); - udelay(1); - } + rtl_rfreg_delay(hw, rfpath, radiob_array_table[i], + RFREG_OFFSET_MASK, + radiob_array_table[i + 1]); } break; case RF90_PATH_C: @@ -344,6 +293,8 @@ bool rtl92cu_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "switch case not processed\n"); break; + default: + break; } return true; } diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c index 7908e1c85819..304c443b89b2 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c @@ -194,15 +194,15 @@ static void rtl92d_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) rtl_set_bbreg(hw, ROFDM0_LSTF, BIT(31), 1); /* hold page C counter */ rtl_set_bbreg(hw, ROFDM1_LSTF, BIT(31), 1); /*hold page D counter */ - ret_value = rtl_get_bbreg(hw, ROFDM0_FRAMESYNC, BMASKDWORD); + ret_value = rtl_get_bbreg(hw, ROFDM0_FRAMESYNC, MASKDWORD); falsealm_cnt->cnt_fast_fsync_fail = (ret_value & 0xffff); falsealm_cnt->cnt_sb_search_fail = ((ret_value & 0xffff0000) >> 16); - ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, BMASKDWORD); + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, MASKDWORD); falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16); - ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, BMASKDWORD); + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, MASKDWORD); falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff); falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16); - ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, BMASKDWORD); + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD); falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff); falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail + falsealm_cnt->cnt_rate_illegal + @@ -214,9 +214,9 @@ static void rtl92d_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) if (rtlpriv->rtlhal.current_bandtype != BAND_ON_5G) { /* hold cck counter */ rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); - ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, BMASKBYTE0); + ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, MASKBYTE0); falsealm_cnt->cnt_cck_fail = ret_value; - ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERUPPER, BMASKBYTE3); + ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERUPPER, MASKBYTE3); falsealm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8; rtl92d_release_cckandrw_pagea_ctl(hw, &flag); } else { @@ -331,11 +331,11 @@ static void rtl92d_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) if (de_digtable->pre_cck_pd_state != de_digtable->cur_cck_pd_state) { if (de_digtable->cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI) { rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); - rtl_set_bbreg(hw, RCCK0_CCA, BMASKBYTE2, 0x83); + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x83); rtl92d_release_cckandrw_pagea_ctl(hw, &flag); } else { rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); - rtl_set_bbreg(hw, RCCK0_CCA, BMASKBYTE2, 0xcd); + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd); rtl92d_release_cckandrw_pagea_ctl(hw, &flag); } de_digtable->pre_cck_pd_state = de_digtable->cur_cck_pd_state; @@ -722,7 +722,7 @@ static void rtl92d_dm_rxgain_tracking_thermalmeter(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "===> Rx Gain %x\n", u4tmp); for (i = RF90_PATH_A; i < rtlpriv->phy.num_total_rfpath; i++) - rtl_set_rfreg(hw, i, 0x3C, BRFREGOFFSETMASK, + rtl_set_rfreg(hw, i, 0x3C, RFREG_OFFSET_MASK, (rtlpriv->phy.reg_rf3c[i] & (~(0xF000))) | u4tmp); } @@ -737,7 +737,7 @@ static void rtl92d_bandtype_2_4G(struct ieee80211_hw *hw, long *temp_cckg, /* Query CCK default setting From 0xa24 */ rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); temp_cck = rtl_get_bbreg(hw, RCCK0_TXFILTER2, - BMASKDWORD) & BMASKCCK; + MASKDWORD) & MASKCCK; rtl92d_release_cckandrw_pagea_ctl(hw, &flag); for (i = 0; i < CCK_TABLE_LENGTH; i++) { if (rtlpriv->dm.cck_inch14) { @@ -896,9 +896,9 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter( rf = 1; if (thermalvalue) { ele_d = rtl_get_bbreg(hw, ROFDM0_XATxIQIMBALANCE, - BMASKDWORD) & BMASKOFDM_D; + MASKDWORD) & MASKOFDM_D; for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) { - if (ele_d == (ofdmswing_table[i] & BMASKOFDM_D)) { + if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) { ofdm_index_old[0] = (u8) i; RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, @@ -910,10 +910,10 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter( } if (is2t) { ele_d = rtl_get_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, - BMASKDWORD) & BMASKOFDM_D; + MASKDWORD) & MASKOFDM_D; for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) { if (ele_d == - (ofdmswing_table[i] & BMASKOFDM_D)) { + (ofdmswing_table[i] & MASKOFDM_D)) { ofdm_index_old[1] = (u8) i; RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, @@ -1091,10 +1091,10 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter( value32 = (ele_d << 22) | ((ele_c & 0x3F) << 16) | ele_a; rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, - BMASKDWORD, value32); + MASKDWORD, value32); value32 = (ele_c & 0x000003C0) >> 6; - rtl_set_bbreg(hw, ROFDM0_XCTxAFE, BMASKH4BITS, + rtl_set_bbreg(hw, ROFDM0_XCTxAFE, MASKH4BITS, value32); value32 = ((val_x * ele_d) >> 7) & 0x01; @@ -1103,10 +1103,10 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter( } else { rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, - BMASKDWORD, + MASKDWORD, ofdmswing_table [(u8)ofdm_index[0]]); - rtl_set_bbreg(hw, ROFDM0_XCTxAFE, BMASKH4BITS, + rtl_set_bbreg(hw, ROFDM0_XCTxAFE, MASKH4BITS, 0x00); rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(24), 0x00); @@ -1204,21 +1204,21 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter( ele_a; rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, - BMASKDWORD, value32); + MASKDWORD, value32); value32 = (ele_c & 0x000003C0) >> 6; rtl_set_bbreg(hw, ROFDM0_XDTxAFE, - BMASKH4BITS, value32); + MASKH4BITS, value32); value32 = ((val_x * ele_d) >> 7) & 0x01; rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(28), value32); } else { rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, - BMASKDWORD, + MASKDWORD, ofdmswing_table [(u8) ofdm_index[1]]); rtl_set_bbreg(hw, ROFDM0_XDTxAFE, - BMASKH4BITS, 0x00); + MASKH4BITS, 0x00); rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(28), 0x00); } @@ -1229,10 +1229,10 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter( } RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "TxPwrTracking 0xc80 = 0x%x, 0xc94 = 0x%x RF 0x24 = 0x%x\n", - rtl_get_bbreg(hw, 0xc80, BMASKDWORD), - rtl_get_bbreg(hw, 0xc94, BMASKDWORD), + rtl_get_bbreg(hw, 0xc80, MASKDWORD), + rtl_get_bbreg(hw, 0xc94, MASKDWORD), rtl_get_rfreg(hw, RF90_PATH_A, 0x24, - BRFREGOFFSETMASK)); + RFREG_OFFSET_MASK)); } if ((delta_iqk > rtlefuse->delta_iqk) && (rtlefuse->delta_iqk != 0)) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c index c9f6ee7e1765..2b08671004a0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c @@ -985,9 +985,9 @@ int rtl92de_hw_init(struct ieee80211_hw *hw) /* set default value after initialize RF, */ rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0); rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0, - RF_CHNLBW, BRFREGOFFSETMASK); + RF_CHNLBW, RFREG_OFFSET_MASK); rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, (enum radio_path)1, - RF_CHNLBW, BRFREGOFFSETMASK); + RF_CHNLBW, RFREG_OFFSET_MASK); /*---- Set CCK and OFDM Block "ON"----*/ if (rtlhal->current_bandtype == BAND_ON_2_4G) @@ -1035,7 +1035,7 @@ int rtl92de_hw_init(struct ieee80211_hw *hw) tmp_rega = rtl_get_rfreg(hw, (enum radio_path)RF90_PATH_A, - 0x2a, BMASKDWORD); + 0x2a, MASKDWORD); if (((tmp_rega & BIT(11)) == BIT(11))) break; @@ -1334,13 +1334,13 @@ void rtl92de_card_disable(struct ieee80211_hw *hw) /* c. ========RF OFF sequence========== */ /* 0x88c[23:20] = 0xf. */ rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0x00f00000, 0xf); - rtl_set_rfreg(hw, RF90_PATH_A, 0x00, BRFREGOFFSETMASK, 0x00); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); /* APSD_CTRL 0x600[7:0] = 0x40 */ rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); /* Close antenna 0,0xc04,0xd04 */ - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0); rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0); /* SYS_FUNC_EN 0x02[7:0] = 0xE2 reset BB state machine */ diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c index 13196cc4b1d3..3d1f0dd4e52d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c @@ -30,6 +30,7 @@ #include "../wifi.h" #include "../pci.h" #include "../ps.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" @@ -242,7 +243,7 @@ void rtl92d_phy_set_bb_reg(struct ieee80211_hw *hw, else if (rtlhal->during_mac0init_radiob) /* mac0 use phy1 write radio_b. */ dbi_direct = BIT(3) | BIT(2); - if (bitmask != BMASKDWORD) { + if (bitmask != MASKDWORD) { if (rtlhal->during_mac1init_radioa || rtlhal->during_mac0init_radiob) originalvalue = rtl92de_read_dword_dbi(hw, @@ -275,20 +276,20 @@ static u32 _rtl92d_phy_rf_serial_read(struct ieee80211_hw *hw, u32 retvalue; newoffset = offset; - tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, BMASKDWORD); + tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD); if (rfpath == RF90_PATH_A) tmplong2 = tmplong; else - tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, BMASKDWORD); + tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD); tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) | (newoffset << 23) | BLSSIREADEDGE; - rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, BMASKDWORD, + rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, tmplong & (~BLSSIREADEDGE)); udelay(10); - rtl_set_bbreg(hw, pphyreg->rfhssi_para2, BMASKDWORD, tmplong2); + rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2); udelay(50); udelay(50); - rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, BMASKDWORD, + rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, tmplong | BLSSIREADEDGE); udelay(10); if (rfpath == RF90_PATH_A) @@ -321,7 +322,7 @@ static void _rtl92d_phy_rf_serial_write(struct ieee80211_hw *hw, newoffset = offset; /* T65 RF */ data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff; - rtl_set_bbreg(hw, pphyreg->rf3wire_offset, BMASKDWORD, data_and_addr); + rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFW-%d Addr[0x%x]=0x%x\n", rfpath, pphyreg->rf3wire_offset, data_and_addr); } @@ -362,7 +363,7 @@ void rtl92d_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, return; spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); if (rtlphy->rf_mode != RF_OP_BY_FW) { - if (bitmask != BRFREGOFFSETMASK) { + if (bitmask != RFREG_OFFSET_MASK) { original_value = _rtl92d_phy_rf_serial_read(hw, rfpath, regaddr); bitshift = _rtl92d_phy_calculate_bit_shift(bitmask); @@ -567,19 +568,8 @@ static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, " ===> phy:Rtl819XPHY_REG_Array_PG\n"); if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_reg_arraylen; i = i + 2) { - if (phy_regarray_table[i] == 0xfe) - mdelay(50); - else if (phy_regarray_table[i] == 0xfd) - mdelay(5); - else if (phy_regarray_table[i] == 0xfc) - mdelay(1); - else if (phy_regarray_table[i] == 0xfb) - udelay(50); - else if (phy_regarray_table[i] == 0xfa) - udelay(5); - else if (phy_regarray_table[i] == 0xf9) - udelay(1); - rtl_set_bbreg(hw, phy_regarray_table[i], BMASKDWORD, + rtl_addr_delay(phy_regarray_table[i]); + rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD, phy_regarray_table[i + 1]); udelay(1); RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, @@ -591,7 +581,7 @@ static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, if (rtlhal->interfaceindex == 0) { for (i = 0; i < agctab_arraylen; i = i + 2) { rtl_set_bbreg(hw, agctab_array_table[i], - BMASKDWORD, + MASKDWORD, agctab_array_table[i + 1]); /* Add 1us delay between BB/RF register * setting. */ @@ -607,7 +597,7 @@ static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, if (rtlhal->current_bandtype == BAND_ON_2_4G) { for (i = 0; i < agctab_arraylen; i = i + 2) { rtl_set_bbreg(hw, agctab_array_table[i], - BMASKDWORD, + MASKDWORD, agctab_array_table[i + 1]); /* Add 1us delay between BB/RF register * setting. */ @@ -623,7 +613,7 @@ static bool _rtl92d_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, for (i = 0; i < agctab_5garraylen; i = i + 2) { rtl_set_bbreg(hw, agctab_5garray_table[i], - BMASKDWORD, + MASKDWORD, agctab_5garray_table[i + 1]); /* Add 1us delay between BB/RF registeri * setting. */ @@ -705,18 +695,7 @@ static bool _rtl92d_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, phy_regarray_table_pg = rtl8192de_phy_reg_array_pg; if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_regarray_pg_len; i = i + 3) { - if (phy_regarray_table_pg[i] == 0xfe) - mdelay(50); - else if (phy_regarray_table_pg[i] == 0xfd) - mdelay(5); - else if (phy_regarray_table_pg[i] == 0xfc) - mdelay(1); - else if (phy_regarray_table_pg[i] == 0xfb) - udelay(50); - else if (phy_regarray_table_pg[i] == 0xfa) - udelay(5); - else if (phy_regarray_table_pg[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_regarray_table_pg[i]); _rtl92d_store_pwrindex_diffrate_offset(hw, phy_regarray_table_pg[i], phy_regarray_table_pg[i + 1], @@ -843,54 +822,16 @@ bool rtl92d_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, switch (rfpath) { case RF90_PATH_A: for (i = 0; i < radioa_arraylen; i = i + 2) { - if (radioa_array_table[i] == 0xfe) { - mdelay(50); - } else if (radioa_array_table[i] == 0xfd) { - /* delay_ms(5); */ - mdelay(5); - } else if (radioa_array_table[i] == 0xfc) { - /* delay_ms(1); */ - mdelay(1); - } else if (radioa_array_table[i] == 0xfb) { - udelay(50); - } else if (radioa_array_table[i] == 0xfa) { - udelay(5); - } else if (radioa_array_table[i] == 0xf9) { - udelay(1); - } else { - rtl_set_rfreg(hw, rfpath, radioa_array_table[i], - BRFREGOFFSETMASK, - radioa_array_table[i + 1]); - /* Add 1us delay between BB/RF register set. */ - udelay(1); - } + rtl_rfreg_delay(hw, rfpath, radioa_array_table[i], + RFREG_OFFSET_MASK, + radioa_array_table[i + 1]); } break; case RF90_PATH_B: for (i = 0; i < radiob_arraylen; i = i + 2) { - if (radiob_array_table[i] == 0xfe) { - /* Delay specific ms. Only RF configuration - * requires delay. */ - mdelay(50); - } else if (radiob_array_table[i] == 0xfd) { - /* delay_ms(5); */ - mdelay(5); - } else if (radiob_array_table[i] == 0xfc) { - /* delay_ms(1); */ - mdelay(1); - } else if (radiob_array_table[i] == 0xfb) { - udelay(50); - } else if (radiob_array_table[i] == 0xfa) { - udelay(5); - } else if (radiob_array_table[i] == 0xf9) { - udelay(1); - } else { - rtl_set_rfreg(hw, rfpath, radiob_array_table[i], - BRFREGOFFSETMASK, - radiob_array_table[i + 1]); - /* Add 1us delay between BB/RF register set. */ - udelay(1); - } + rtl_rfreg_delay(hw, rfpath, radiob_array_table[i], + RFREG_OFFSET_MASK, + radiob_array_table[i + 1]); } break; case RF90_PATH_C: @@ -911,13 +852,13 @@ void rtl92d_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw) struct rtl_phy *rtlphy = &(rtlpriv->phy); rtlphy->default_initialgain[0] = - (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, BMASKBYTE0); + (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0); rtlphy->default_initialgain[1] = - (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, BMASKBYTE0); + (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0); rtlphy->default_initialgain[2] = - (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, BMASKBYTE0); + (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0); rtlphy->default_initialgain[3] = - (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, BMASKBYTE0); + (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0); RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Default initial gain (c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x\n", rtlphy->default_initialgain[0], @@ -925,9 +866,9 @@ void rtl92d_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw) rtlphy->default_initialgain[2], rtlphy->default_initialgain[3]); rtlphy->framesync = (u8)rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3, - BMASKBYTE0); + MASKBYTE0); rtlphy->framesync_c34 = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR2, - BMASKDWORD); + MASKDWORD); RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Default framesync (0x%x) = 0x%x\n", ROFDM0_RXDETECTOR3, rtlphy->framesync); @@ -1106,7 +1047,7 @@ static void _rtl92d_phy_stop_trx_before_changeband(struct ieee80211_hw *hw) { rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0); rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0); - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0x00); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0x00); rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0x0); } @@ -1168,7 +1109,7 @@ static void _rtl92d_phy_reload_imr_setting(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 imr_num = MAX_RF_IMR_INDEX; - u32 rfmask = BRFREGOFFSETMASK; + u32 rfmask = RFREG_OFFSET_MASK; u8 group, i; unsigned long flag = 0; @@ -1211,7 +1152,7 @@ static void _rtl92d_phy_reload_imr_setting(struct ieee80211_hw *hw, for (i = 0; i < imr_num; i++) { rtl_set_rfreg(hw, (enum radio_path)rfpath, rf_reg_for_5g_swchnl_normal[i], - BRFREGOFFSETMASK, + RFREG_OFFSET_MASK, rf_imr_param_normal[0][0][i]); } rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, @@ -1329,7 +1270,7 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel) if (i == 0 && (rtlhal->macphymode == DUALMAC_DUALPHY)) { rtl_set_rfreg(hw, (enum radio_path)path, rf_reg_for_c_cut_5g[i], - BRFREGOFFSETMASK, 0xE439D); + RFREG_OFFSET_MASK, 0xE439D); } else if (rf_reg_for_c_cut_5g[i] == RF_SYN_G4) { u4tmp2 = (rf_reg_pram_c_5g[index][i] & 0x7FF) | (u4tmp << 11); @@ -1337,11 +1278,11 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel) u4tmp2 &= ~(BIT(7) | BIT(6)); rtl_set_rfreg(hw, (enum radio_path)path, rf_reg_for_c_cut_5g[i], - BRFREGOFFSETMASK, u4tmp2); + RFREG_OFFSET_MASK, u4tmp2); } else { rtl_set_rfreg(hw, (enum radio_path)path, rf_reg_for_c_cut_5g[i], - BRFREGOFFSETMASK, + RFREG_OFFSET_MASK, rf_reg_pram_c_5g[index][i]); } RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, @@ -1351,7 +1292,7 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel) path, index, rtl_get_rfreg(hw, (enum radio_path)path, rf_reg_for_c_cut_5g[i], - BRFREGOFFSETMASK)); + RFREG_OFFSET_MASK)); } if (need_pwr_down) _rtl92d_phy_restore_rf_env(hw, path, &u4regvalue); @@ -1381,7 +1322,7 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel) i++) { rtl_set_rfreg(hw, rfpath, rf_for_c_cut_5g_internal_pa[i], - BRFREGOFFSETMASK, + RFREG_OFFSET_MASK, rf_pram_c_5g_int_pa[index][i]); RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, "offset 0x%x value 0x%x path %d index %d\n", @@ -1422,13 +1363,13 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel) if (rf_reg_for_c_cut_2g[i] == RF_SYN_G7) rtl_set_rfreg(hw, (enum radio_path)path, rf_reg_for_c_cut_2g[i], - BRFREGOFFSETMASK, + RFREG_OFFSET_MASK, (rf_reg_param_for_c_cut_2g[index][i] | BIT(17))); else rtl_set_rfreg(hw, (enum radio_path)path, rf_reg_for_c_cut_2g[i], - BRFREGOFFSETMASK, + RFREG_OFFSET_MASK, rf_reg_param_for_c_cut_2g [index][i]); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, @@ -1438,14 +1379,14 @@ static void _rtl92d_phy_switch_rf_setting(struct ieee80211_hw *hw, u8 channel) rf_reg_mask_for_c_cut_2g[i], path, index, rtl_get_rfreg(hw, (enum radio_path)path, rf_reg_for_c_cut_2g[i], - BRFREGOFFSETMASK)); + RFREG_OFFSET_MASK)); } RTPRINT(rtlpriv, FINIT, INIT_IQK, "cosa ver 3 set RF-B, 2G, 0x28 = 0x%x !!\n", rf_syn_g4_for_c_cut_2g | (u4tmp << 11)); rtl_set_rfreg(hw, (enum radio_path)path, RF_SYN_G4, - BRFREGOFFSETMASK, + RFREG_OFFSET_MASK, rf_syn_g4_for_c_cut_2g | (u4tmp << 11)); if (need_pwr_down) _rtl92d_phy_restore_rf_env(hw, path, &u4regvalue); @@ -1493,41 +1434,41 @@ static u8 _rtl92d_phy_patha_iqk(struct ieee80211_hw *hw, bool configpathb) /* path-A IQK setting */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path-A IQK setting!\n"); if (rtlhal->interfaceindex == 0) { - rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x10008c1f); - rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x10008c1f); + rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c1f); + rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x10008c1f); } else { - rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x10008c22); - rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x10008c22); + rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c22); + rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x10008c22); } - rtl_set_bbreg(hw, 0xe38, BMASKDWORD, 0x82140102); - rtl_set_bbreg(hw, 0xe3c, BMASKDWORD, 0x28160206); + rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x82140102); + rtl_set_bbreg(hw, 0xe3c, MASKDWORD, 0x28160206); /* path-B IQK setting */ if (configpathb) { - rtl_set_bbreg(hw, 0xe50, BMASKDWORD, 0x10008c22); - rtl_set_bbreg(hw, 0xe54, BMASKDWORD, 0x10008c22); - rtl_set_bbreg(hw, 0xe58, BMASKDWORD, 0x82140102); - rtl_set_bbreg(hw, 0xe5c, BMASKDWORD, 0x28160206); + rtl_set_bbreg(hw, 0xe50, MASKDWORD, 0x10008c22); + rtl_set_bbreg(hw, 0xe54, MASKDWORD, 0x10008c22); + rtl_set_bbreg(hw, 0xe58, MASKDWORD, 0x82140102); + rtl_set_bbreg(hw, 0xe5c, MASKDWORD, 0x28160206); } /* LO calibration setting */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "LO calibration setting!\n"); - rtl_set_bbreg(hw, 0xe4c, BMASKDWORD, 0x00462911); + rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x00462911); /* One shot, path A LOK & IQK */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "One shot, path A LOK & IQK!\n"); - rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf9000000); - rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf8000000); + rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf9000000); + rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000); /* delay x ms */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "Delay %d ms for One shot, path A LOK & IQK\n", IQK_DELAY_TIME); mdelay(IQK_DELAY_TIME); /* Check failed */ - regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD); + regeac = rtl_get_bbreg(hw, 0xeac, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeac = 0x%x\n", regeac); - rege94 = rtl_get_bbreg(hw, 0xe94, BMASKDWORD); + rege94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xe94 = 0x%x\n", rege94); - rege9c = rtl_get_bbreg(hw, 0xe9c, BMASKDWORD); + rege9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xe9c = 0x%x\n", rege9c); - regea4 = rtl_get_bbreg(hw, 0xea4, BMASKDWORD); + regea4 = rtl_get_bbreg(hw, 0xea4, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xea4 = 0x%x\n", regea4); if (!(regeac & BIT(28)) && (((rege94 & 0x03FF0000) >> 16) != 0x142) && (((rege9c & 0x03FF0000) >> 16) != 0x42)) @@ -1563,42 +1504,42 @@ static u8 _rtl92d_phy_patha_iqk_5g_normal(struct ieee80211_hw *hw, RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK!\n"); /* path-A IQK setting */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path-A IQK setting!\n"); - rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x18008c1f); - rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x18008c1f); - rtl_set_bbreg(hw, 0xe38, BMASKDWORD, 0x82140307); - rtl_set_bbreg(hw, 0xe3c, BMASKDWORD, 0x68160960); + rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x18008c1f); + rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x18008c1f); + rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x82140307); + rtl_set_bbreg(hw, 0xe3c, MASKDWORD, 0x68160960); /* path-B IQK setting */ if (configpathb) { - rtl_set_bbreg(hw, 0xe50, BMASKDWORD, 0x18008c2f); - rtl_set_bbreg(hw, 0xe54, BMASKDWORD, 0x18008c2f); - rtl_set_bbreg(hw, 0xe58, BMASKDWORD, 0x82110000); - rtl_set_bbreg(hw, 0xe5c, BMASKDWORD, 0x68110000); + rtl_set_bbreg(hw, 0xe50, MASKDWORD, 0x18008c2f); + rtl_set_bbreg(hw, 0xe54, MASKDWORD, 0x18008c2f); + rtl_set_bbreg(hw, 0xe58, MASKDWORD, 0x82110000); + rtl_set_bbreg(hw, 0xe5c, MASKDWORD, 0x68110000); } /* LO calibration setting */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "LO calibration setting!\n"); - rtl_set_bbreg(hw, 0xe4c, BMASKDWORD, 0x00462911); + rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x00462911); /* path-A PA on */ - rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, 0x07000f60); - rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BMASKDWORD, 0x66e60e30); + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, MASKDWORD, 0x07000f60); + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, MASKDWORD, 0x66e60e30); for (i = 0; i < retrycount; i++) { /* One shot, path A LOK & IQK */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "One shot, path A LOK & IQK!\n"); - rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf9000000); - rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf8000000); + rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf9000000); + rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000); /* delay x ms */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME); mdelay(IQK_DELAY_TIME * 10); /* Check failed */ - regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD); + regeac = rtl_get_bbreg(hw, 0xeac, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeac = 0x%x\n", regeac); - rege94 = rtl_get_bbreg(hw, 0xe94, BMASKDWORD); + rege94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xe94 = 0x%x\n", rege94); - rege9c = rtl_get_bbreg(hw, 0xe9c, BMASKDWORD); + rege9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xe9c = 0x%x\n", rege9c); - regea4 = rtl_get_bbreg(hw, 0xea4, BMASKDWORD); + regea4 = rtl_get_bbreg(hw, 0xea4, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xea4 = 0x%x\n", regea4); if (!(regeac & TxOKBit) && (((rege94 & 0x03FF0000) >> 16) != 0x142)) { @@ -1620,9 +1561,9 @@ static u8 _rtl92d_phy_patha_iqk_5g_normal(struct ieee80211_hw *hw, } } /* path A PA off */ - rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, MASKDWORD, rtlphy->iqk_bb_backup[0]); - rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BMASKDWORD, + rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, MASKDWORD, rtlphy->iqk_bb_backup[1]); return result; } @@ -1637,22 +1578,22 @@ static u8 _rtl92d_phy_pathb_iqk(struct ieee80211_hw *hw) RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path B IQK!\n"); /* One shot, path B LOK & IQK */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "One shot, path A LOK & IQK!\n"); - rtl_set_bbreg(hw, 0xe60, BMASKDWORD, 0x00000002); - rtl_set_bbreg(hw, 0xe60, BMASKDWORD, 0x00000000); + rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000002); + rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000000); /* delay x ms */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "Delay %d ms for One shot, path B LOK & IQK\n", IQK_DELAY_TIME); mdelay(IQK_DELAY_TIME); /* Check failed */ - regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD); + regeac = rtl_get_bbreg(hw, 0xeac, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeac = 0x%x\n", regeac); - regeb4 = rtl_get_bbreg(hw, 0xeb4, BMASKDWORD); + regeb4 = rtl_get_bbreg(hw, 0xeb4, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeb4 = 0x%x\n", regeb4); - regebc = rtl_get_bbreg(hw, 0xebc, BMASKDWORD); + regebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xebc = 0x%x\n", regebc); - regec4 = rtl_get_bbreg(hw, 0xec4, BMASKDWORD); + regec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xec4 = 0x%x\n", regec4); - regecc = rtl_get_bbreg(hw, 0xecc, BMASKDWORD); + regecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xecc = 0x%x\n", regecc); if (!(regeac & BIT(31)) && (((regeb4 & 0x03FF0000) >> 16) != 0x142) && (((regebc & 0x03FF0000) >> 16) != 0x42)) @@ -1680,31 +1621,31 @@ static u8 _rtl92d_phy_pathb_iqk_5g_normal(struct ieee80211_hw *hw) RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path B IQK!\n"); /* path-A IQK setting */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path-A IQK setting!\n"); - rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x18008c1f); - rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x18008c1f); - rtl_set_bbreg(hw, 0xe38, BMASKDWORD, 0x82110000); - rtl_set_bbreg(hw, 0xe3c, BMASKDWORD, 0x68110000); + rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x18008c1f); + rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x18008c1f); + rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x82110000); + rtl_set_bbreg(hw, 0xe3c, MASKDWORD, 0x68110000); /* path-B IQK setting */ - rtl_set_bbreg(hw, 0xe50, BMASKDWORD, 0x18008c2f); - rtl_set_bbreg(hw, 0xe54, BMASKDWORD, 0x18008c2f); - rtl_set_bbreg(hw, 0xe58, BMASKDWORD, 0x82140307); - rtl_set_bbreg(hw, 0xe5c, BMASKDWORD, 0x68160960); + rtl_set_bbreg(hw, 0xe50, MASKDWORD, 0x18008c2f); + rtl_set_bbreg(hw, 0xe54, MASKDWORD, 0x18008c2f); + rtl_set_bbreg(hw, 0xe58, MASKDWORD, 0x82140307); + rtl_set_bbreg(hw, 0xe5c, MASKDWORD, 0x68160960); /* LO calibration setting */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "LO calibration setting!\n"); - rtl_set_bbreg(hw, 0xe4c, BMASKDWORD, 0x00462911); + rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x00462911); /* path-B PA on */ - rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, 0x0f600700); - rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BMASKDWORD, 0x061f0d30); + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, MASKDWORD, 0x0f600700); + rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, MASKDWORD, 0x061f0d30); for (i = 0; i < retrycount; i++) { /* One shot, path B LOK & IQK */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "One shot, path A LOK & IQK!\n"); - rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xfa000000); - rtl_set_bbreg(hw, 0xe48, BMASKDWORD, 0xf8000000); + rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xfa000000); + rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000); /* delay x ms */ RTPRINT(rtlpriv, FINIT, INIT_IQK, @@ -1712,15 +1653,15 @@ static u8 _rtl92d_phy_pathb_iqk_5g_normal(struct ieee80211_hw *hw) mdelay(IQK_DELAY_TIME * 10); /* Check failed */ - regeac = rtl_get_bbreg(hw, 0xeac, BMASKDWORD); + regeac = rtl_get_bbreg(hw, 0xeac, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeac = 0x%x\n", regeac); - regeb4 = rtl_get_bbreg(hw, 0xeb4, BMASKDWORD); + regeb4 = rtl_get_bbreg(hw, 0xeb4, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xeb4 = 0x%x\n", regeb4); - regebc = rtl_get_bbreg(hw, 0xebc, BMASKDWORD); + regebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xebc = 0x%x\n", regebc); - regec4 = rtl_get_bbreg(hw, 0xec4, BMASKDWORD); + regec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xec4 = 0x%x\n", regec4); - regecc = rtl_get_bbreg(hw, 0xecc, BMASKDWORD); + regecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xecc = 0x%x\n", regecc); if (!(regeac & BIT(31)) && (((regeb4 & 0x03FF0000) >> 16) != 0x142)) @@ -1738,9 +1679,9 @@ static u8 _rtl92d_phy_pathb_iqk_5g_normal(struct ieee80211_hw *hw) } /* path B PA off */ - rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BMASKDWORD, + rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, MASKDWORD, rtlphy->iqk_bb_backup[0]); - rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BMASKDWORD, + rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, MASKDWORD, rtlphy->iqk_bb_backup[2]); return result; } @@ -1754,7 +1695,7 @@ static void _rtl92d_phy_save_adda_registers(struct ieee80211_hw *hw, RTPRINT(rtlpriv, FINIT, INIT_IQK, "Save ADDA parameters.\n"); for (i = 0; i < regnum; i++) - adda_backup[i] = rtl_get_bbreg(hw, adda_reg[i], BMASKDWORD); + adda_backup[i] = rtl_get_bbreg(hw, adda_reg[i], MASKDWORD); } static void _rtl92d_phy_save_mac_registers(struct ieee80211_hw *hw, @@ -1779,7 +1720,7 @@ static void _rtl92d_phy_reload_adda_registers(struct ieee80211_hw *hw, RTPRINT(rtlpriv, FINIT, INIT_IQK, "Reload ADDA power saving parameters !\n"); for (i = 0; i < regnum; i++) - rtl_set_bbreg(hw, adda_reg[i], BMASKDWORD, adda_backup[i]); + rtl_set_bbreg(hw, adda_reg[i], MASKDWORD, adda_backup[i]); } static void _rtl92d_phy_reload_mac_registers(struct ieee80211_hw *hw, @@ -1807,7 +1748,7 @@ static void _rtl92d_phy_path_adda_on(struct ieee80211_hw *hw, pathon = rtlpriv->rtlhal.interfaceindex == 0 ? 0x04db25a4 : 0x0b1b25a4; for (i = 0; i < IQK_ADDA_REG_NUM; i++) - rtl_set_bbreg(hw, adda_reg[i], BMASKDWORD, pathon); + rtl_set_bbreg(hw, adda_reg[i], MASKDWORD, pathon); } static void _rtl92d_phy_mac_setting_calibration(struct ieee80211_hw *hw, @@ -1830,9 +1771,9 @@ static void _rtl92d_phy_patha_standby(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path-A standby mode!\n"); - rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x0); - rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, BMASKDWORD, 0x00010000); - rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x80800000); + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x0); + rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, MASKDWORD, 0x00010000); + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000); } static void _rtl92d_phy_pimode_switch(struct ieee80211_hw *hw, bool pi_mode) @@ -1843,8 +1784,8 @@ static void _rtl92d_phy_pimode_switch(struct ieee80211_hw *hw, bool pi_mode) RTPRINT(rtlpriv, FINIT, INIT_IQK, "BB Switch to %s mode!\n", pi_mode ? "PI" : "SI"); mode = pi_mode ? 0x01000100 : 0x01000000; - rtl_set_bbreg(hw, 0x820, BMASKDWORD, mode); - rtl_set_bbreg(hw, 0x828, BMASKDWORD, mode); + rtl_set_bbreg(hw, 0x820, MASKDWORD, mode); + rtl_set_bbreg(hw, 0x828, MASKDWORD, mode); } static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8], @@ -1875,7 +1816,7 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8], RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK for 2.4G :Start!!!\n"); if (t == 0) { - bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, BMASKDWORD); + bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "==>0x%08x\n", bbvalue); RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQ Calibration for %s\n", is2t ? "2T2R" : "1T1R"); @@ -1898,40 +1839,40 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8], _rtl92d_phy_pimode_switch(hw, true); rtl_set_bbreg(hw, RFPGA0_RFMOD, BIT(24), 0x00); - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKDWORD, 0x03a05600); - rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, BMASKDWORD, 0x000800e4); - rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, BMASKDWORD, 0x22204000); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKDWORD, 0x03a05600); + rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, MASKDWORD, 0x000800e4); + rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, MASKDWORD, 0x22204000); rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0xf00000, 0x0f); if (is2t) { - rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, BMASKDWORD, + rtl_set_bbreg(hw, RFPGA0_XA_LSSIPARAMETER, MASKDWORD, 0x00010000); - rtl_set_bbreg(hw, RFPGA0_XB_LSSIPARAMETER, BMASKDWORD, + rtl_set_bbreg(hw, RFPGA0_XB_LSSIPARAMETER, MASKDWORD, 0x00010000); } /* MAC settings */ _rtl92d_phy_mac_setting_calibration(hw, iqk_mac_reg, rtlphy->iqk_mac_backup); /* Page B init */ - rtl_set_bbreg(hw, 0xb68, BMASKDWORD, 0x0f600000); + rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x0f600000); if (is2t) - rtl_set_bbreg(hw, 0xb6c, BMASKDWORD, 0x0f600000); + rtl_set_bbreg(hw, 0xb6c, MASKDWORD, 0x0f600000); /* IQ calibration setting */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK setting!\n"); - rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x80800000); - rtl_set_bbreg(hw, 0xe40, BMASKDWORD, 0x01007c00); - rtl_set_bbreg(hw, 0xe44, BMASKDWORD, 0x01004800); + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000); + rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x01007c00); + rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x01004800); for (i = 0; i < retrycount; i++) { patha_ok = _rtl92d_phy_patha_iqk(hw, is2t); if (patha_ok == 0x03) { RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK Success!!\n"); - result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) & + result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) & 0x3FF0000) >> 16; - result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) & + result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16; - result[t][2] = (rtl_get_bbreg(hw, 0xea4, BMASKDWORD) & + result[t][2] = (rtl_get_bbreg(hw, 0xea4, MASKDWORD) & 0x3FF0000) >> 16; - result[t][3] = (rtl_get_bbreg(hw, 0xeac, BMASKDWORD) & + result[t][3] = (rtl_get_bbreg(hw, 0xeac, MASKDWORD) & 0x3FF0000) >> 16; break; } else if (i == (retrycount - 1) && patha_ok == 0x01) { @@ -1939,9 +1880,9 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8], RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK Only Tx Success!!\n"); - result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) & + result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) & 0x3FF0000) >> 16; - result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) & + result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16; } } @@ -1957,22 +1898,22 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8], RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path B IQK Success!!\n"); result[t][4] = (rtl_get_bbreg(hw, 0xeb4, - BMASKDWORD) & 0x3FF0000) >> 16; + MASKDWORD) & 0x3FF0000) >> 16; result[t][5] = (rtl_get_bbreg(hw, 0xebc, - BMASKDWORD) & 0x3FF0000) >> 16; + MASKDWORD) & 0x3FF0000) >> 16; result[t][6] = (rtl_get_bbreg(hw, 0xec4, - BMASKDWORD) & 0x3FF0000) >> 16; + MASKDWORD) & 0x3FF0000) >> 16; result[t][7] = (rtl_get_bbreg(hw, 0xecc, - BMASKDWORD) & 0x3FF0000) >> 16; + MASKDWORD) & 0x3FF0000) >> 16; break; } else if (i == (retrycount - 1) && pathb_ok == 0x01) { /* Tx IQK OK */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path B Only Tx IQK Success!!\n"); result[t][4] = (rtl_get_bbreg(hw, 0xeb4, - BMASKDWORD) & 0x3FF0000) >> 16; + MASKDWORD) & 0x3FF0000) >> 16; result[t][5] = (rtl_get_bbreg(hw, 0xebc, - BMASKDWORD) & 0x3FF0000) >> 16; + MASKDWORD) & 0x3FF0000) >> 16; } } if (0x00 == pathb_ok) @@ -1984,7 +1925,7 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8], RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK:Back to BB mode, load original value!\n"); - rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0); + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0); if (t != 0) { /* Switch back BB to SI mode after finish IQ Calibration. */ if (!rtlphy->rfpi_enable) @@ -2004,8 +1945,8 @@ static void _rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw, long result[][8], rtlphy->iqk_bb_backup, IQK_BB_REG_NUM - 1); /* load 0xe30 IQC default value */ - rtl_set_bbreg(hw, 0xe30, BMASKDWORD, 0x01008c00); - rtl_set_bbreg(hw, 0xe34, BMASKDWORD, 0x01008c00); + rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x01008c00); + rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x01008c00); } RTPRINT(rtlpriv, FINIT, INIT_IQK, "<==\n"); } @@ -2042,7 +1983,7 @@ static void _rtl92d_phy_iq_calibrate_5g_normal(struct ieee80211_hw *hw, RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK for 5G NORMAL:Start!!!\n"); mdelay(IQK_DELAY_TIME * 20); if (t == 0) { - bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, BMASKDWORD); + bbvalue = rtl_get_bbreg(hw, RFPGA0_RFMOD, MASKDWORD); RTPRINT(rtlpriv, FINIT, INIT_IQK, "==>0x%08x\n", bbvalue); RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQ Calibration for %s\n", is2t ? "2T2R" : "1T1R"); @@ -2072,38 +2013,38 @@ static void _rtl92d_phy_iq_calibrate_5g_normal(struct ieee80211_hw *hw, if (!rtlphy->rfpi_enable) _rtl92d_phy_pimode_switch(hw, true); rtl_set_bbreg(hw, RFPGA0_RFMOD, BIT(24), 0x00); - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKDWORD, 0x03a05600); - rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, BMASKDWORD, 0x000800e4); - rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, BMASKDWORD, 0x22208000); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKDWORD, 0x03a05600); + rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, MASKDWORD, 0x000800e4); + rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, MASKDWORD, 0x22208000); rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER4, 0xf00000, 0x0f); /* Page B init */ - rtl_set_bbreg(hw, 0xb68, BMASKDWORD, 0x0f600000); + rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x0f600000); if (is2t) - rtl_set_bbreg(hw, 0xb6c, BMASKDWORD, 0x0f600000); + rtl_set_bbreg(hw, 0xb6c, MASKDWORD, 0x0f600000); /* IQ calibration setting */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK setting!\n"); - rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0x80800000); - rtl_set_bbreg(hw, 0xe40, BMASKDWORD, 0x10007c00); - rtl_set_bbreg(hw, 0xe44, BMASKDWORD, 0x01004800); + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000); + rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x10007c00); + rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x01004800); patha_ok = _rtl92d_phy_patha_iqk_5g_normal(hw, is2t); if (patha_ok == 0x03) { RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK Success!!\n"); - result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) & + result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) & 0x3FF0000) >> 16; - result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) & + result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16; - result[t][2] = (rtl_get_bbreg(hw, 0xea4, BMASKDWORD) & + result[t][2] = (rtl_get_bbreg(hw, 0xea4, MASKDWORD) & 0x3FF0000) >> 16; - result[t][3] = (rtl_get_bbreg(hw, 0xeac, BMASKDWORD) & + result[t][3] = (rtl_get_bbreg(hw, 0xeac, MASKDWORD) & 0x3FF0000) >> 16; } else if (patha_ok == 0x01) { /* Tx IQK OK */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK Only Tx Success!!\n"); - result[t][0] = (rtl_get_bbreg(hw, 0xe94, BMASKDWORD) & + result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) & 0x3FF0000) >> 16; - result[t][1] = (rtl_get_bbreg(hw, 0xe9c, BMASKDWORD) & + result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16; } else { RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path A IQK Fail!!\n"); @@ -2116,20 +2057,20 @@ static void _rtl92d_phy_iq_calibrate_5g_normal(struct ieee80211_hw *hw, if (pathb_ok == 0x03) { RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path B IQK Success!!\n"); - result[t][4] = (rtl_get_bbreg(hw, 0xeb4, BMASKDWORD) & + result[t][4] = (rtl_get_bbreg(hw, 0xeb4, MASKDWORD) & 0x3FF0000) >> 16; - result[t][5] = (rtl_get_bbreg(hw, 0xebc, BMASKDWORD) & + result[t][5] = (rtl_get_bbreg(hw, 0xebc, MASKDWORD) & 0x3FF0000) >> 16; - result[t][6] = (rtl_get_bbreg(hw, 0xec4, BMASKDWORD) & + result[t][6] = (rtl_get_bbreg(hw, 0xec4, MASKDWORD) & 0x3FF0000) >> 16; - result[t][7] = (rtl_get_bbreg(hw, 0xecc, BMASKDWORD) & + result[t][7] = (rtl_get_bbreg(hw, 0xecc, MASKDWORD) & 0x3FF0000) >> 16; } else if (pathb_ok == 0x01) { /* Tx IQK OK */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "Path B Only Tx IQK Success!!\n"); - result[t][4] = (rtl_get_bbreg(hw, 0xeb4, BMASKDWORD) & + result[t][4] = (rtl_get_bbreg(hw, 0xeb4, MASKDWORD) & 0x3FF0000) >> 16; - result[t][5] = (rtl_get_bbreg(hw, 0xebc, BMASKDWORD) & + result[t][5] = (rtl_get_bbreg(hw, 0xebc, MASKDWORD) & 0x3FF0000) >> 16; } else { RTPRINT(rtlpriv, FINIT, INIT_IQK, @@ -2140,7 +2081,7 @@ static void _rtl92d_phy_iq_calibrate_5g_normal(struct ieee80211_hw *hw, /* Back to BB mode, load original value */ RTPRINT(rtlpriv, FINIT, INIT_IQK, "IQK:Back to BB mode, load original value!\n"); - rtl_set_bbreg(hw, 0xe28, BMASKDWORD, 0); + rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0); if (t != 0) { if (is2t) _rtl92d_phy_reload_adda_registers(hw, iqk_bb_reg, @@ -2240,7 +2181,7 @@ static void _rtl92d_phy_patha_fill_iqk_matrix(struct ieee80211_hw *hw, return; } else if (iqk_ok) { oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATxIQIMBALANCE, - BMASKDWORD) >> 22) & 0x3FF; /* OFDM0_D */ + MASKDWORD) >> 22) & 0x3FF; /* OFDM0_D */ val_x = result[final_candidate][0]; if ((val_x & 0x00000200) != 0) val_x = val_x | 0xFFFFFC00; @@ -2271,7 +2212,7 @@ static void _rtl92d_phy_patha_fill_iqk_matrix(struct ieee80211_hw *hw, ((val_y * oldval_0 >> 7) & 0x1)); RTPRINT(rtlpriv, FINIT, INIT_IQK, "0xC80 = 0x%x\n", rtl_get_bbreg(hw, ROFDM0_XATxIQIMBALANCE, - BMASKDWORD)); + MASKDWORD)); if (txonly) { RTPRINT(rtlpriv, FINIT, INIT_IQK, "only Tx OK\n"); return; @@ -2299,7 +2240,7 @@ static void _rtl92d_phy_pathb_fill_iqk_matrix(struct ieee80211_hw *hw, return; } else if (iqk_ok) { oldval_1 = (rtl_get_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, - BMASKDWORD) >> 22) & 0x3FF; + MASKDWORD) >> 22) & 0x3FF; val_x = result[final_candidate][4]; if ((val_x & 0x00000200) != 0) val_x = val_x | 0xFFFFFC00; @@ -2657,7 +2598,7 @@ static void _rtl92d_phy_lc_calibrate_sw(struct ieee80211_hw *hw, bool is2t) rf_mode[index] = rtl_read_byte(rtlpriv, offset); /* 2. Set RF mode = standby mode */ rtl_set_rfreg(hw, (enum radio_path)index, RF_AC, - BRFREGOFFSETMASK, 0x010000); + RFREG_OFFSET_MASK, 0x010000); if (rtlpci->init_ready) { /* switch CV-curve control by LC-calibration */ rtl_set_rfreg(hw, (enum radio_path)index, RF_SYN_G7, @@ -2667,16 +2608,16 @@ static void _rtl92d_phy_lc_calibrate_sw(struct ieee80211_hw *hw, bool is2t) 0x08000, 0x01); } u4tmp = rtl_get_rfreg(hw, (enum radio_path)index, RF_SYN_G6, - BRFREGOFFSETMASK); + RFREG_OFFSET_MASK); while ((!(u4tmp & BIT(11))) && timecount <= timeout) { mdelay(50); timecount += 50; u4tmp = rtl_get_rfreg(hw, (enum radio_path)index, - RF_SYN_G6, BRFREGOFFSETMASK); + RF_SYN_G6, RFREG_OFFSET_MASK); } RTPRINT(rtlpriv, FINIT, INIT_IQK, "PHY_LCK finish delay for %d ms=2\n", timecount); - u4tmp = rtl_get_rfreg(hw, index, RF_SYN_G4, BRFREGOFFSETMASK); + u4tmp = rtl_get_rfreg(hw, index, RF_SYN_G4, RFREG_OFFSET_MASK); if (index == 0 && rtlhal->interfaceindex == 0) { RTPRINT(rtlpriv, FINIT, INIT_IQK, "path-A / 5G LCK\n"); @@ -2696,9 +2637,9 @@ static void _rtl92d_phy_lc_calibrate_sw(struct ieee80211_hw *hw, bool is2t) 0x7f, i); rtl_set_rfreg(hw, (enum radio_path)index, 0x4D, - BRFREGOFFSETMASK, 0x0); + RFREG_OFFSET_MASK, 0x0); readval = rtl_get_rfreg(hw, (enum radio_path)index, - 0x4F, BRFREGOFFSETMASK); + 0x4F, RFREG_OFFSET_MASK); curvecount_val[2 * i + 1] = (readval & 0xfffe0) >> 5; /* reg 0x4f [4:0] */ /* reg 0x50 [19:10] */ @@ -2912,7 +2853,7 @@ static bool _rtl92d_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, } rtl_set_rfreg(hw, (enum radio_path)rfpath, currentcmd->para1, - BRFREGOFFSETMASK, + RFREG_OFFSET_MASK, rtlphy->rfreg_chnlval[rfpath]); _rtl92d_phy_reload_imr_setting(hw, channel, rfpath); @@ -2960,7 +2901,7 @@ u8 rtl92d_phy_sw_chnl(struct ieee80211_hw *hw) if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY && rtlhal->bandset == BAND_ON_BOTH) { ret_value = rtl_get_bbreg(hw, RFPGA0_XAB_RFPARAMETER, - BMASKDWORD); + MASKDWORD); if (rtlphy->current_channel > 14 && !(ret_value & BIT(0))) rtl92d_phy_switch_wirelessband(hw, BAND_ON_5G); else if (rtlphy->current_channel <= 14 && (ret_value & BIT(0))) @@ -3112,7 +3053,7 @@ static void _rtl92d_phy_set_rfsleep(struct ieee80211_hw *hw) /* a. TXPAUSE 0x522[7:0] = 0xFF Pause MAC TX queue */ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); /* b. RF path 0 offset 0x00 = 0x00 disable RF */ - rtl_set_rfreg(hw, RF90_PATH_A, 0x00, BRFREGOFFSETMASK, 0x00); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); /* c. APSD_CTRL 0x600[7:0] = 0x40 */ rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); /* d. APSD_CTRL 0x600[7:0] = 0x00 @@ -3120,12 +3061,12 @@ static void _rtl92d_phy_set_rfsleep(struct ieee80211_hw *hw) * RF path 0 offset 0x00 = 0x00 * APSD_CTRL 0x600[7:0] = 0x40 * */ - u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, BRFREGOFFSETMASK); + u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); while (u4btmp != 0 && delay > 0) { rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x0); - rtl_set_rfreg(hw, RF90_PATH_A, 0x00, BRFREGOFFSETMASK, 0x00); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); - u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, BRFREGOFFSETMASK); + u4btmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); delay--; } if (delay == 0) { @@ -3468,9 +3409,9 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw) /* 5G LAN ON */ rtl_set_bbreg(hw, 0xB30, 0x00F00000, 0xa); /* TX BB gain shift*1,Just for testchip,0xc80,0xc88 */ - rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, BMASKDWORD, + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, MASKDWORD, 0x40000100); - rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, BMASKDWORD, + rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, MASKDWORD, 0x40000100); if (rtlhal->macphymode == DUALMAC_DUALPHY) { rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, @@ -3524,16 +3465,16 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw) rtl_set_bbreg(hw, 0xB30, 0x00F00000, 0x0); /* TX BB gain shift,Just for testchip,0xc80,0xc88 */ if (rtlefuse->internal_pa_5g[0]) - rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, BMASKDWORD, + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, MASKDWORD, 0x2d4000b5); else - rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, BMASKDWORD, + rtl_set_bbreg(hw, ROFDM0_XATxIQIMBALANCE, MASKDWORD, 0x20000080); if (rtlefuse->internal_pa_5g[1]) - rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, BMASKDWORD, + rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, MASKDWORD, 0x2d4000b5); else - rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, BMASKDWORD, + rtl_set_bbreg(hw, ROFDM0_XBTxIQIMBALANCE, MASKDWORD, 0x20000080); if (rtlhal->macphymode == DUALMAC_DUALPHY) { rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, @@ -3560,8 +3501,8 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw) } } /* update IQK related settings */ - rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, BMASKDWORD, 0x40000100); - rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, BMASKDWORD, 0x40000100); + rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, MASKDWORD, 0x40000100); + rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, MASKDWORD, 0x40000100); rtl_set_bbreg(hw, ROFDM0_XCTxAFE, 0xF0000000, 0x00); rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(30) | BIT(28) | BIT(26) | BIT(24), 0x00); @@ -3590,7 +3531,7 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw) /* DMDP */ if (rtlphy->rf_type == RF_1T1R) { /* Use antenna 0,0xc04,0xd04 */ - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0x11); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0x11); rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0x1); /* enable ad/da clock1 for dual-phy reg0x888 */ @@ -3612,7 +3553,7 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw) } else { /* Single PHY */ /* Use antenna 0 & 1,0xc04,0xd04 */ - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, BMASKBYTE0, 0x33); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0x33); rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, BDWORD, 0x3); /* disable ad/da clock1,0x888 */ rtl_set_bbreg(hw, RFPGA0_ADDALLOCKEN, BIT(12) | BIT(13), 0); @@ -3620,9 +3561,9 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw) for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; rfpath++) { rtlphy->rfreg_chnlval[rfpath] = rtl_get_rfreg(hw, rfpath, - RF_CHNLBW, BRFREGOFFSETMASK); + RF_CHNLBW, RFREG_OFFSET_MASK); rtlphy->reg_rf3c[rfpath] = rtl_get_rfreg(hw, rfpath, 0x3C, - BRFREGOFFSETMASK); + RFREG_OFFSET_MASK); } for (i = 0; i < 2; i++) RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, "RF 0x18 = 0x%x\n", diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/reg.h b/drivers/net/wireless/rtlwifi/rtl8192de/reg.h index b7498c5bafc5..7f29b8d765b3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8192de/reg.h @@ -1295,18 +1295,4 @@ #define BWORD1 0xc #define BDWORD 0xf -#define BMASKBYTE0 0xff -#define BMASKBYTE1 0xff00 -#define BMASKBYTE2 0xff0000 -#define BMASKBYTE3 0xff000000 -#define BMASKHWORD 0xffff0000 -#define BMASKLWORD 0x0000ffff -#define BMASKDWORD 0xffffffff -#define BMASK12BITS 0xfff -#define BMASKH4BITS 0xf0000000 -#define BMASKOFDM_D 0xffc00000 -#define BMASKCCK 0x3f3f3f3f - -#define BRFREGOFFSETMASK 0xfffff - #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/rf.c b/drivers/net/wireless/rtlwifi/rtl8192de/rf.c index 20144e0b4142..6a6ac540d5b5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/rf.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/rf.c @@ -125,7 +125,7 @@ void rtl92d_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, } tmpval = tx_agc[RF90_PATH_A] & 0xff; - rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, BMASKBYTE1, tmpval); + rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval); RTPRINT(rtlpriv, FPHY, PHY_TXPWR, "CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", tmpval, RTXAGC_A_CCK1_MCS32); @@ -135,7 +135,7 @@ void rtl92d_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, "CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval, RTXAGC_B_CCK11_A_CCK2_11); tmpval = tx_agc[RF90_PATH_B] >> 24; - rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, BMASKBYTE0, tmpval); + rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval); RTPRINT(rtlpriv, FPHY, PHY_TXPWR, "CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval, RTXAGC_B_CCK11_A_CCK2_11); @@ -360,7 +360,7 @@ static void _rtl92d_write_ofdm_power_reg(struct ieee80211_hw *hw, regoffset = regoffset_a[index]; else regoffset = regoffset_b[index]; - rtl_set_bbreg(hw, regoffset, BMASKDWORD, writeval); + rtl_set_bbreg(hw, regoffset, MASKDWORD, writeval); RTPRINT(rtlpriv, FPHY, PHY_TXPWR, "Set 0x%x = %08x\n", regoffset, writeval); if (((get_rf_type(rtlphy) == RF_2T2R) && diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c index 9c092e6eb3fe..77c5b5f35244 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c @@ -30,6 +30,7 @@ #include "../wifi.h" #include "../pci.h" #include "../ps.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" @@ -833,18 +834,7 @@ static bool _rtl92s_phy_config_bb(struct ieee80211_hw *hw, u8 configtype) if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_reg_len; i = i + 2) { - if (phy_reg_table[i] == 0xfe) - mdelay(50); - else if (phy_reg_table[i] == 0xfd) - mdelay(5); - else if (phy_reg_table[i] == 0xfc) - mdelay(1); - else if (phy_reg_table[i] == 0xfb) - udelay(50); - else if (phy_reg_table[i] == 0xfa) - udelay(5); - else if (phy_reg_table[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_reg_table[i]); /* Add delay for ECS T20 & LG malow platform, */ udelay(1); @@ -886,18 +876,7 @@ static bool _rtl92s_phy_set_bb_to_diff_rf(struct ieee80211_hw *hw, if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_regarray2xtxr_len; i = i + 3) { - if (phy_regarray2xtxr_table[i] == 0xfe) - mdelay(50); - else if (phy_regarray2xtxr_table[i] == 0xfd) - mdelay(5); - else if (phy_regarray2xtxr_table[i] == 0xfc) - mdelay(1); - else if (phy_regarray2xtxr_table[i] == 0xfb) - udelay(50); - else if (phy_regarray2xtxr_table[i] == 0xfa) - udelay(5); - else if (phy_regarray2xtxr_table[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_regarray2xtxr_table[i]); rtl92s_phy_set_bb_reg(hw, phy_regarray2xtxr_table[i], phy_regarray2xtxr_table[i + 1], @@ -920,18 +899,7 @@ static bool _rtl92s_phy_config_bb_with_pg(struct ieee80211_hw *hw, if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_pg_len; i = i + 3) { - if (phy_table_pg[i] == 0xfe) - mdelay(50); - else if (phy_table_pg[i] == 0xfd) - mdelay(5); - else if (phy_table_pg[i] == 0xfc) - mdelay(1); - else if (phy_table_pg[i] == 0xfb) - udelay(50); - else if (phy_table_pg[i] == 0xfa) - udelay(5); - else if (phy_table_pg[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_table_pg[i]); _rtl92s_store_pwrindex_diffrate_offset(hw, phy_table_pg[i], @@ -1034,28 +1002,9 @@ u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath) switch (rfpath) { case RF90_PATH_A: for (i = 0; i < radio_a_tblen; i = i + 2) { - if (radio_a_table[i] == 0xfe) - /* Delay specific ms. Only RF configuration - * requires delay. */ - mdelay(50); - else if (radio_a_table[i] == 0xfd) - mdelay(5); - else if (radio_a_table[i] == 0xfc) - mdelay(1); - else if (radio_a_table[i] == 0xfb) - udelay(50); - else if (radio_a_table[i] == 0xfa) - udelay(5); - else if (radio_a_table[i] == 0xf9) - udelay(1); - else - rtl92s_phy_set_rf_reg(hw, rfpath, - radio_a_table[i], - MASK20BITS, - radio_a_table[i + 1]); + rtl_rfreg_delay(hw, rfpath, radio_a_table[i], + MASK20BITS, radio_a_table[i + 1]); - /* Add delay for ECS T20 & LG malow platform */ - udelay(1); } /* PA Bias current for inferiority IC */ @@ -1063,28 +1012,8 @@ u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath) break; case RF90_PATH_B: for (i = 0; i < radio_b_tblen; i = i + 2) { - if (radio_b_table[i] == 0xfe) - /* Delay specific ms. Only RF configuration - * requires delay.*/ - mdelay(50); - else if (radio_b_table[i] == 0xfd) - mdelay(5); - else if (radio_b_table[i] == 0xfc) - mdelay(1); - else if (radio_b_table[i] == 0xfb) - udelay(50); - else if (radio_b_table[i] == 0xfa) - udelay(5); - else if (radio_b_table[i] == 0xf9) - udelay(1); - else - rtl92s_phy_set_rf_reg(hw, rfpath, - radio_b_table[i], - MASK20BITS, - radio_b_table[i + 1]); - - /* Add delay for ECS T20 & LG malow platform */ - udelay(1); + rtl_rfreg_delay(hw, rfpath, radio_b_table[i], + MASK20BITS, radio_b_table[i + 1]); } break; case RF90_PATH_C: diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/reg.h b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h index c81c83591940..e13043479b71 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h @@ -1165,16 +1165,4 @@ #define BTX_AGCRATECCK 0x7f00 -#define MASKBYTE0 0xff -#define MASKBYTE1 0xff00 -#define MASKBYTE2 0xff0000 -#define MASKBYTE3 0xff000000 -#define MASKHWORD 0xffff0000 -#define MASKLWORD 0x0000ffff -#define MASKDWORD 0xffffffff - -#define MAKS12BITS 0xfffff -#define MASK20BITS 0xfffff -#define RFREG_OFFSET_MASK 0xfffff - #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile b/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile index 4ed731f09b1f..9c34a85fdb89 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile @@ -10,7 +10,6 @@ rtl8723ae-objs := \ led.o \ phy.o \ pwrseq.o \ - pwrseqcmd.o \ rf.o \ sw.o \ table.o \ diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c index 8a8577a1783b..b47167c96b58 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c @@ -43,7 +43,6 @@ #include "../rtl8723com/fw_common.h" #include "led.h" #include "hw.h" -#include "pwrseqcmd.h" #include "pwrseq.h" #include "btc.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c index 4f8189d3bb44..3ea78afdec73 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c @@ -30,6 +30,7 @@ #include "../wifi.h" #include "../pci.h" #include "../ps.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" @@ -277,18 +278,7 @@ static bool _phy_cfg_bb_w_header(struct ieee80211_hw *hw, u8 configtype) phy_regarray_table = RTL8723EPHY_REG_1TARRAY; if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_reg_arraylen; i = i + 2) { - if (phy_regarray_table[i] == 0xfe) - mdelay(50); - else if (phy_regarray_table[i] == 0xfd) - mdelay(5); - else if (phy_regarray_table[i] == 0xfc) - mdelay(1); - else if (phy_regarray_table[i] == 0xfb) - udelay(50); - else if (phy_regarray_table[i] == 0xfa) - udelay(5); - else if (phy_regarray_table[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_regarray_table[i]); rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD, phy_regarray_table[i + 1]); udelay(1); @@ -450,18 +440,7 @@ static bool _phy_cfg_bb_w_pgheader(struct ieee80211_hw *hw, u8 configtype) if (configtype == BASEBAND_CONFIG_PHY_REG) { for (i = 0; i < phy_regarray_pg_len; i = i + 3) { - if (phy_regarray_table_pg[i] == 0xfe) - mdelay(50); - else if (phy_regarray_table_pg[i] == 0xfd) - mdelay(5); - else if (phy_regarray_table_pg[i] == 0xfc) - mdelay(1); - else if (phy_regarray_table_pg[i] == 0xfb) - udelay(50); - else if (phy_regarray_table_pg[i] == 0xfa) - udelay(5); - else if (phy_regarray_table_pg[i] == 0xf9) - udelay(1); + rtl_addr_delay(phy_regarray_table_pg[i]); _st_pwrIdx_dfrate_off(hw, phy_regarray_table_pg[i], phy_regarray_table_pg[i + 1], @@ -488,24 +467,9 @@ bool rtl8723ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, switch (rfpath) { case RF90_PATH_A: for (i = 0; i < radioa_arraylen; i = i + 2) { - if (radioa_array_table[i] == 0xfe) - mdelay(50); - else if (radioa_array_table[i] == 0xfd) - mdelay(5); - else if (radioa_array_table[i] == 0xfc) - mdelay(1); - else if (radioa_array_table[i] == 0xfb) - udelay(50); - else if (radioa_array_table[i] == 0xfa) - udelay(5); - else if (radioa_array_table[i] == 0xf9) - udelay(1); - else { - rtl_set_rfreg(hw, rfpath, radioa_array_table[i], - RFREG_OFFSET_MASK, - radioa_array_table[i + 1]); - udelay(1); - } + rtl_rfreg_delay(hw, rfpath, radioa_array_table[i], + RFREG_OFFSET_MASK, + radioa_array_table[i + 1]); } break; case RF90_PATH_B: diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h index 7a46f9fdf558..a418acb4d0ca 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h @@ -30,7 +30,6 @@ #ifndef __RTL8723E_PWRSEQ_H__ #define __RTL8723E_PWRSEQ_H__ -#include "pwrseqcmd.h" /* Check document WM-20110607-Paul-RTL8723A_Power_Architecture-R02.vsd There are 6 HW Power States: diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h b/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h index 199da366c6da..64376b38708b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h @@ -2059,22 +2059,6 @@ #define BWORD1 0xc #define BWORD 0xf -#define MASKBYTE0 0xff -#define MASKBYTE1 0xff00 -#define MASKBYTE2 0xff0000 -#define MASKBYTE3 0xff000000 -#define MASKHWORD 0xffff0000 -#define MASKLWORD 0x0000ffff -#define MASKDWORD 0xffffffff -#define MASK12BITS 0xfff -#define MASKH4BITS 0xf0000000 -#define MASKOFDM_D 0xffc00000 -#define MASKCCK 0x3f3f3f3f - -#define MASK4BITS 0x0f -#define MASK20BITS 0xfffff -#define RFREG_OFFSET_MASK 0xfffff - #define BENABLE 0x1 #define BDISABLE 0x0 diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/Makefile b/drivers/net/wireless/rtlwifi/rtl8723be/Makefile index 4a75aab0539a..59e416abd93a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/Makefile +++ b/drivers/net/wireless/rtlwifi/rtl8723be/Makefile @@ -8,7 +8,6 @@ rtl8723be-objs := \ led.o \ phy.o \ pwrseq.o \ - pwrseqcmd.o \ rf.o \ sw.o \ table.o \ diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c index a500d266fae5..fc2af714e9ec 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c @@ -39,7 +39,6 @@ #include "../rtl8723com/fw_common.h" #include "led.h" #include "hw.h" -#include "pwrseqcmd.h" #include "pwrseq.h" #include "../btcoexist/rtl_btc.h" @@ -818,9 +817,9 @@ static bool _rtl8723be_init_mac(struct ieee80211_hw *hw) mac_func_enable = false; /* HW Power on sequence */ - if (!rtlbe_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, - PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, - RTL8723_NIC_ENABLE_FLOW)) { + if (!rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, + PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, + RTL8723_NIC_ENABLE_FLOW)) { RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "init MAC Fail as power on failure\n"); return false; @@ -1309,8 +1308,8 @@ static void _rtl8723be_poweroff_adapter(struct ieee80211_hw *hw) /* Combo (PCIe + USB) Card and PCIe-MF Card */ /* 1. Run LPS WL RFOFF flow */ - rtlbe_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, - PWR_INTF_PCI_MSK, RTL8723_NIC_LPS_ENTER_FLOW); + rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, + PWR_INTF_PCI_MSK, RTL8723_NIC_LPS_ENTER_FLOW); /* 2. 0x1F[7:0] = 0 */ /* turn off RF */ @@ -1328,8 +1327,8 @@ static void _rtl8723be_poweroff_adapter(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); /* HW card disable configuration. */ - rtlbe_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, - PWR_INTF_PCI_MSK, RTL8723_NIC_DISABLE_FLOW); + rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, + PWR_INTF_PCI_MSK, RTL8723_NIC_DISABLE_FLOW); /* Reset MCU IO Wrapper */ u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1); diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/phy.c b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c index ebc1e2788fca..cadae9bc4e3f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c @@ -26,6 +26,7 @@ #include "../wifi.h" #include "../pci.h" #include "../ps.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" @@ -41,9 +42,6 @@ static bool _rtl8723be_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, static bool rtl8723be_phy_sw_chn_step_by_step(struct ieee80211_hw *hw, u8 channel, u8 *stage, u8 *step, u32 *delay); -static void _rtl8723be_config_bb_reg(struct ieee80211_hw *hw, - u32 addr, u32 data); - static bool _rtl8723be_check_condition(struct ieee80211_hw *hw, const u32 condition) { @@ -114,7 +112,7 @@ static bool _rtl8723be_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, v1 = array_table[i]; v2 = array_table[i+1]; if (v1 < 0xcdcdcdcd) { - _rtl8723be_config_bb_reg(hw, v1, v2); + rtl_bb_delay(hw, v1, v2); } else {/*This line is the start line of branch.*/ if (!_rtl8723be_check_condition(hw, array_table[i])) { /*Discard the following (offset, data) pairs*/ @@ -135,7 +133,7 @@ static bool _rtl8723be_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, v2 != 0xCDEF && v2 != 0xCDCD && i < arraylen - 2) { - _rtl8723be_config_bb_reg(hw, + rtl_bb_delay(hw, v1, v2); READ_NEXT_PAIR(v1, v2, i); } @@ -389,27 +387,6 @@ static void _rtl8723be_phy_init_tx_power_by_rate(struct ieee80211_hw *hw) [path][txnum][section] = 0; } -static void _rtl8723be_config_bb_reg(struct ieee80211_hw *hw, - u32 addr, u32 data) -{ - if (addr == 0xfe) { - mdelay(50); - } else if (addr == 0xfd) { - mdelay(5); - } else if (addr == 0xfc) { - mdelay(1); - } else if (addr == 0xfb) { - udelay(50); - } else if (addr == 0xfa) { - udelay(5); - } else if (addr == 0xf9) { - udelay(1); - } else { - rtl_set_bbreg(hw, addr, MASKDWORD, data); - udelay(1); - } -} - static void phy_set_txpwr_by_rate_base(struct ieee80211_hw *hw, u8 band, u8 path, u8 rate_section, u8 txnum, u8 value) diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h index 960b408216df..a62f43ed8d32 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h +++ b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h @@ -26,7 +26,6 @@ #ifndef __RTL8723BE_PWRSEQ_H__ #define __RTL8723BE_PWRSEQ_H__ -#include "pwrseqcmd.h" /* Check document WM-20130425-JackieLau-RTL8723B_Power_Architecture v05.vsd * There are 6 HW Power States: * 0: POFF--Power Off diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/reg.h b/drivers/net/wireless/rtlwifi/rtl8723be/reg.h index 65221e678230..4c653fab8795 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8723be/reg.h @@ -2242,22 +2242,6 @@ #define BWORD1 0xc #define BWORD 0xf -#define MASKBYTE0 0xff -#define MASKBYTE1 0xff00 -#define MASKBYTE2 0xff0000 -#define MASKBYTE3 0xff000000 -#define MASKHWORD 0xffff0000 -#define MASKLWORD 0x0000ffff -#define MASKDWORD 0xffffffff -#define MASK12BITS 0xfff -#define MASKH4BITS 0xf0000000 -#define MASKOFDM_D 0xffc00000 -#define MASKCCK 0x3f3f3f3f - -#define MASK4BITS 0x0f -#define MASK20BITS 0xfffff -#define RFREG_OFFSET_MASK 0xfffff - #define BENABLE 0x1 #define BDISABLE 0x0 diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 5cb799e6bd08..0b4d641bf715 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -57,6 +57,22 @@ #define MASK20BITS 0xfffff #define RFREG_OFFSET_MASK 0xfffff +#define MASKBYTE0 0xff +#define MASKBYTE1 0xff00 +#define MASKBYTE2 0xff0000 +#define MASKBYTE3 0xff000000 +#define MASKHWORD 0xffff0000 +#define MASKLWORD 0x0000ffff +#define MASKDWORD 0xffffffff +#define MASK12BITS 0xfff +#define MASKH4BITS 0xf0000000 +#define MASKOFDM_D 0xffc00000 +#define MASKCCK 0x3f3f3f3f + +#define MASK4BITS 0x0f +#define MASK20BITS 0xfffff +#define RFREG_OFFSET_MASK 0xfffff + #define RF_CHANGE_BY_INIT 0 #define RF_CHANGE_BY_IPS BIT(28) #define RF_CHANGE_BY_PS BIT(29) From 1bae2ae3647393b8ce185135ef0854486ce5a4c2 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 4 Mar 2014 16:53:49 -0600 Subject: [PATCH 399/414] rtlwifi: rtl8723be: rtl8723com: Remove unused allow_all_destaddr functions In a previous commit, Peter Wu removed this call as configure_filter takes care of setting/clearing RCR_AAP. This patch makes the same change for rtl8723be. In addition, a change is made in the logging level for one debug printout. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8723be/sw.c | 1 - drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c index 7834ae577b52..cc4ab3f9ffc8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c @@ -239,7 +239,6 @@ static struct rtl_hal_ops rtl8723be_hal_ops = { .enable_hw_sec = rtl8723be_enable_hw_security_config, .set_key = rtl8723be_set_key, .init_sw_leds = rtl8723be_init_sw_leds, - .allow_all_destaddr = rtl8723be_allow_all_destaddr, .get_bbreg = rtl8723_phy_query_bb_reg, .set_bbreg = rtl8723_phy_set_bb_reg, .get_rfreg = rtl8723be_phy_query_rf_reg, diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c index 32c390ffc7d2..c12da552b7f7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c @@ -263,7 +263,7 @@ int rtl8723_download_fw(struct ieee80211_hw *hw, "normal Firmware SIZE %d\n", fwsize); if (rtlpriv->cfg->ops->is_fw_header(pfwheader)) { - RT_TRACE(rtlpriv, COMP_FW, DBG_EMERG, + RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "Firmware Version(%d), Signature(%#x), Size(%d)\n", pfwheader->version, pfwheader->signature, (int)sizeof(struct rtl92c_firmware_header)); From a53268be0cb9763f11da4f6fe3fb924cbe3a7d4a Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 4 Mar 2014 16:53:50 -0600 Subject: [PATCH 400/414] rtlwifi: rtl8192cu: Fix too long disable of IRQs In commit f78bccd79ba3cd9d9664981b501d57bdb81ab8a4 entitled "rtlwifi: rtl8192ce: Fix too long disable of IRQs", Olivier Langlois fixed a problem caused by an extra long disabling of interrupts. This patch makes the same fix for rtl8192cu. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192cu/hw.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index db7df7f83a02..68b5c7e92cfb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -985,6 +985,17 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw) struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); int err = 0; static bool iqk_initialized; + unsigned long flags; + + /* As this function can take a very long time (up to 350 ms) + * and can be called with irqs disabled, reenable the irqs + * to let the other devices continue being serviced. + * + * It is safe doing so since our own interrupts will only be enabled + * in a subsequent step. + */ + local_save_flags(flags); + local_irq_enable(); rtlhal->hw_type = HARDWARE_TYPE_RTL8192CU; err = _rtl92cu_init_mac(hw); @@ -997,7 +1008,7 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "Failed to download FW. Init HW without FW now..\n"); err = 1; - return err; + goto exit; } rtlhal->last_hmeboxnum = 0; /* h2c */ _rtl92cu_phy_param_tab_init(hw); @@ -1034,6 +1045,8 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw) _InitPABias(hw); _update_mac_setting(hw); rtl92c_dm_init(hw); +exit: + local_irq_restore(flags); return err; } From 2610decdd0b3808ba20471a999835cfee5275f98 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 4 Mar 2014 16:53:51 -0600 Subject: [PATCH 401/414] rtlwifi: rtl8192se: Fix too long disable of IRQs In commit f78bccd79ba3cd9d9664981b501d57bdb81ab8a4 entitled "rtlwifi: rtl8192ce: Fix too long disable of IRQs", Olivier Langlois fixed a problem caused by an extra long disabling of interrupts. This patch makes the same fix for rtl8192se. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192se/hw.c | 27 ++++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c index 7c4b39cc5dbf..3015af167b2b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c @@ -955,7 +955,7 @@ int rtl92se_hw_init(struct ieee80211_hw *hw) struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); u8 tmp_byte = 0; - + unsigned long flags; bool rtstatus = true; u8 tmp_u1b; int err = false; @@ -967,6 +967,16 @@ int rtl92se_hw_init(struct ieee80211_hw *hw) rtlpci->being_init_adapter = true; + /* As this function can take a very long time (up to 350 ms) + * and can be called with irqs disabled, reenable the irqs + * to let the other devices continue being serviced. + * + * It is safe doing so since our own interrupts will only be enabled + * in a subsequent step. + */ + local_save_flags(flags); + local_irq_enable(); + rtlpriv->intf_ops->disable_aspm(hw); /* 1. MAC Initialize */ @@ -984,7 +994,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "Failed to download FW. Init HW without FW now... " "Please copy FW into /lib/firmware/rtlwifi\n"); - return 1; + err = 1; + goto exit; } /* After FW download, we have to reset MAC register */ @@ -997,7 +1008,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw) /* 3. Initialize MAC/PHY Config by MACPHY_reg.txt */ if (!rtl92s_phy_mac_config(hw)) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "MAC Config failed\n"); - return rtstatus; + err = rtstatus; + goto exit; } /* because last function modify RCR, so we update @@ -1016,7 +1028,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw) /* 4. Initialize BB After MAC Config PHY_reg.txt, AGC_Tab.txt */ if (!rtl92s_phy_bb_config(hw)) { RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, "BB Config failed\n"); - return rtstatus; + err = rtstatus; + goto exit; } /* 5. Initiailze RF RAIO_A.txt RF RAIO_B.txt */ @@ -1033,7 +1046,8 @@ int rtl92se_hw_init(struct ieee80211_hw *hw) if (!rtl92s_phy_rf_config(hw)) { RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "RF Config failed\n"); - return rtstatus; + err = rtstatus; + goto exit; } /* After read predefined TXT, we must set BB/MAC/RF @@ -1122,8 +1136,9 @@ int rtl92se_hw_init(struct ieee80211_hw *hw) rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_ON); rtl92s_dm_init(hw); +exit: + local_irq_restore(flags); rtlpci->being_init_adapter = false; - return err; } From 6b6392715856d563719991e9ce95e773491a8983 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 4 Mar 2014 16:53:52 -0600 Subject: [PATCH 402/414] rtlwifi: rtl8188ee: Fix too long disable of IRQs In commit f78bccd79ba3cd9d9664981b501d57bdb81ab8a4 entitled "rtlwifi: rtl8192ce: Fix too long disable of IRQs", Olivier Langlois fixed a problem caused by an extra long disabling of interrupts. This patch makes the same fix for rtl8188ee. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8188ee/hw.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c index 6561805c3a88..bd2a26bafb69 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c @@ -1024,9 +1024,20 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw) bool rtstatus = true; int err = 0; u8 tmp_u1b, u1byte; + unsigned long flags; RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Rtl8188EE hw init\n"); rtlpriv->rtlhal.being_init_adapter = true; + /* As this function can take a very long time (up to 350 ms) + * and can be called with irqs disabled, reenable the irqs + * to let the other devices continue being serviced. + * + * It is safe doing so since our own interrupts will only be enabled + * in a subsequent step. + */ + local_save_flags(flags); + local_irq_enable(); + rtlpriv->intf_ops->disable_aspm(hw); tmp_u1b = rtl_read_byte(rtlpriv, REG_SYS_CLKR+1); @@ -1042,7 +1053,7 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw) if (rtstatus != true) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n"); err = 1; - return err; + goto exit; } err = rtl88e_download_fw(hw, false); @@ -1050,8 +1061,7 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "Failed to download FW. Init HW without FW now..\n"); err = 1; - rtlhal->fw_ready = false; - return err; + goto exit; } else { rtlhal->fw_ready = true; } @@ -1134,10 +1144,12 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw) } rtl_write_byte(rtlpriv, REG_NAV_CTRL+2, ((30000+127)/128)); rtl88e_dm_init(hw); +exit: + local_irq_restore(flags); rtlpriv->rtlhal.being_init_adapter = false; RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "end of Rtl8188EE hw init %x\n", err); - return 0; + return err; } static enum version_8188e _rtl88ee_read_chip_version(struct ieee80211_hw *hw) From bfc1010c418a22cbebd8b1bd1e75dad6a527a609 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 4 Mar 2014 16:53:53 -0600 Subject: [PATCH 403/414] rtlwifi: rtl8723ae: Fix too long disable of IRQs In commit f78bccd79ba3cd9d9664981b501d57bdb81ab8a4 entitled "rtlwifi: rtl8192ce: Fix too long disable of IRQs", Olivier Langlois fixed a problem caused by an extra long disabling of interrupts. This patch makes the same fix for rtl8723ae. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8723ae/hw.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c index b47167c96b58..f4c9852d1e1e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c @@ -881,14 +881,25 @@ int rtl8723ae_hw_init(struct ieee80211_hw *hw) bool rtstatus = true; int err; u8 tmp_u1b; + unsigned long flags; rtlpriv->rtlhal.being_init_adapter = true; + /* As this function can take a very long time (up to 350 ms) + * and can be called with irqs disabled, reenable the irqs + * to let the other devices continue being serviced. + * + * It is safe doing so since our own interrupts will only be enabled + * in a subsequent step. + */ + local_save_flags(flags); + local_irq_enable(); + rtlpriv->intf_ops->disable_aspm(hw); rtstatus = _rtl8712e_init_mac(hw); if (rtstatus != true) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n"); err = 1; - return err; + goto exit; } err = rtl8723_download_fw(hw, false); @@ -896,8 +907,7 @@ int rtl8723ae_hw_init(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "Failed to download FW. Init HW without FW now..\n"); err = 1; - rtlhal->fw_ready = false; - return err; + goto exit; } else { rtlhal->fw_ready = true; } @@ -972,6 +982,8 @@ int rtl8723ae_hw_init(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n"); } rtl8723ae_dm_init(hw); +exit: + local_irq_restore(flags); rtlpriv->rtlhal.being_init_adapter = false; return err; } From 2d9d532ff754c352e4b55527569d0552fc33c0db Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 5 Mar 2014 17:25:59 -0600 Subject: [PATCH 404/414] rtlwifi: rtl8192ce: Handle unused switch case This patch prevents log spamming by adding a case for a previously unhandled case. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index c6a38201ac81..4ae51d5b436f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -542,9 +542,11 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) (u8 *)(&fw_current_inps)); } break; } + case HW_VAR_KEEP_ALIVE: + break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "switch case not processed\n"); + "switch case %d not processed\n", variable); break; } } From 2903d04b5abe10393f659c5a0a4f8adec1b67b65 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 5 Mar 2014 17:26:00 -0600 Subject: [PATCH 405/414] rtlwifi: rtl8723be: Fix sparse errors Sparse reports the following: drivers/net/wireless/rtlwifi/rtl8723be/sw.c:374:14: sparse: duplicate const drivers/net/wireless/rtlwifi/rtl8723be/hw.c:2214:30: sparse: cast to restricted __le32 Reported-by: Dan Carpenter Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8723be/hw.c | 3 +-- drivers/net/wireless/rtlwifi/rtl8723be/sw.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c index fc2af714e9ec..7e70c7108d91 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c @@ -2210,8 +2210,7 @@ static void rtl8723be_update_hal_rate_mask(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "ratr_bitmap :%x\n", ratr_bitmap); - *(u32 *)&rate_mask = EF4BYTE((ratr_bitmap & 0x0fffffff) | - (ratr_index << 28)); + *(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) | (ratr_index << 28); rate_mask[0] = macid; rate_mask[1] = _rtl8723be_mrate_idx_to_arfr_id(hw, ratr_index) | (shortgi ? 0x80 : 0x00); diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c index cc4ab3f9ffc8..b4577ebc4bb0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c @@ -370,7 +370,7 @@ MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n"); MODULE_PARM_DESC(fwlps, "using linked fw control power save (default 1 is open)\n"); MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); -static const SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); +static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); static struct pci_driver rtl8723be_driver = { .name = KBUILD_MODNAME, From 7ce24ab74c04ce0ce238b5dce30e9bc3823527be Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 5 Mar 2014 17:26:01 -0600 Subject: [PATCH 406/414] rtlwifi: rtl8723be: Fix smatch warnings Smatch reports the following: drivers/net/wireless/rtlwifi/rtl8723be/fw.c:208 _rtl8723be_fill_h2c_command() warn: variable dereferenced before check 'rtlhal' (see line 69) drivers/net/wireless/rtlwifi/rtl8723be/hw.c:1732 _rtl8723be_read_adapter_info() error: __builtin_memcpy() '&rtlefuse->efuse_map[0][0]' too small (256 vs 512) The first one is fixed by removing two pointless tests for NULL pointers. Reported-by: Dan Carpenter Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8723be/fw.c | 8 -------- drivers/net/wireless/rtlwifi/wifi.h | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/fw.c b/drivers/net/wireless/rtlwifi/rtl8723be/fw.c index 0f3522db5b37..f856be6fc138 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/fw.c @@ -201,14 +201,6 @@ static void _rtl8723be_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id, "pHalData->last_hmeboxnum = %d\n", rtlhal->last_hmeboxnum); } - if (!rtlpriv) { - pr_err("rtlpriv bad\n"); - return; - } - if (!rtlhal) { - pr_err("rtlhal bad\n"); - return; - } spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); rtlhal->h2c_setinprogress = false; spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 0b4d641bf715..6965afdf572a 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -1587,7 +1587,7 @@ struct rtl_dm { u64 last_rx_ok_cnt; }; -#define EFUSE_MAX_LOGICAL_SIZE 256 +#define EFUSE_MAX_LOGICAL_SIZE 512 struct rtl_efuse { bool autoLoad_ok; From 561e722201e41e304936b8a2aaa282c46ad4f393 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Thu, 6 Mar 2014 10:16:11 +0100 Subject: [PATCH 407/414] Revert "brcmfmac: Use atomic functions for intstatus update." This reverts commit c98db0bec72ac7ef127119c1ed962d6f56802b12. The function atomic_set_mask() is not architecture independent so it can not be used in the driver as is. Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../wireless/brcm80211/brcmfmac/dhd_sdio.c | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 5c2706e50775..70bab5e089eb 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -2444,7 +2444,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) struct brcmf_core *buscore; u32 addr; unsigned long val; - int ret; + int n, ret; buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV); addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus); @@ -2452,7 +2452,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret); bus->sdcnt.f1regdata++; if (ret != 0) - return ret; + val = 0; val &= bus->hostintmask; atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE)); @@ -2461,7 +2461,13 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) if (val) { brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret); bus->sdcnt.f1regdata++; - atomic_set_mask(val, &bus->intstatus); + } + + if (ret) { + atomic_set(&bus->intstatus, 0); + } else if (val) { + for_each_set_bit(n, &val, 32) + set_bit(n, (unsigned long *)&bus->intstatus.counter); } return ret; @@ -2473,7 +2479,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) unsigned long intstatus; uint txlimit = bus->txbound; /* Tx frames to send before resched */ uint framecnt; /* Temporary counter of tx/rx frames */ - int err = 0; + int err = 0, n; brcmf_dbg(TRACE, "Enter\n"); @@ -2577,8 +2583,10 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) } /* Keep still-pending events for next scheduling */ - if (intstatus) - atomic_set_mask(intstatus, &bus->intstatus); + if (intstatus) { + for_each_set_bit(n, &intstatus, 32) + set_bit(n, (unsigned long *)&bus->intstatus.counter); + } brcmf_sdio_clrintr(bus); From 5cbb9c285bdcc14ee381120dab7e23a81060f1c0 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Thu, 6 Mar 2014 10:16:12 +0100 Subject: [PATCH 408/414] brcmfmac: Use atomic functions for intstatus update. The intstatus in sdio code can be updated from different threads. To protect intstatus access, atomic functions are used. One of them is set_bit, but this function is not guaranteed atomic on all platforms. The loop was replaced with local created OR function. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../wireless/brcm80211/brcmfmac/dhd_sdio.c | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 70bab5e089eb..a111b6fbbeba 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -2439,12 +2439,21 @@ static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus) } } +static void atomic_orr(int val, atomic_t *v) +{ + int old_val; + + old_val = atomic_read(v); + while (atomic_cmpxchg(v, old_val, val | old_val) != old_val) + old_val = atomic_read(v); +} + static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) { struct brcmf_core *buscore; u32 addr; unsigned long val; - int n, ret; + int ret; buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV); addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus); @@ -2452,7 +2461,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret); bus->sdcnt.f1regdata++; if (ret != 0) - val = 0; + return ret; val &= bus->hostintmask; atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE)); @@ -2461,13 +2470,7 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) if (val) { brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret); bus->sdcnt.f1regdata++; - } - - if (ret) { - atomic_set(&bus->intstatus, 0); - } else if (val) { - for_each_set_bit(n, &val, 32) - set_bit(n, (unsigned long *)&bus->intstatus.counter); + atomic_orr(val, &bus->intstatus); } return ret; @@ -2479,7 +2482,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) unsigned long intstatus; uint txlimit = bus->txbound; /* Tx frames to send before resched */ uint framecnt; /* Temporary counter of tx/rx frames */ - int err = 0, n; + int err = 0; brcmf_dbg(TRACE, "Enter\n"); @@ -2583,10 +2586,8 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) } /* Keep still-pending events for next scheduling */ - if (intstatus) { - for_each_set_bit(n, &intstatus, 32) - set_bit(n, (unsigned long *)&bus->intstatus.counter); - } + if (intstatus) + atomic_orr(intstatus, &bus->intstatus); brcmf_sdio_clrintr(bus); From aa0bee1f409f76222ed009980425dbf12bc7133b Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Thu, 6 Mar 2014 20:42:43 +0530 Subject: [PATCH 409/414] mwl8k: le32_to_cpu cast to restricted It fixes couple of sparse check >#make C=1 CF=-D__CHECK_ENDIAN__ drivers/net/wireless/mwl8k.o >drivers/net/wireless/mwl8k.c:3104:19: warning: cast to restricted __le32 >drivers/net/wireless/mwl8k.c:3108:18: warning: cast to restricted __le32 Reported-by: Fengguang Wu Signed-off-by: Nishant Sarmukadam Signed-off-by: Yogesh Ashok Powar Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index b6d83f6888fa..706a445dba37 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3103,11 +3103,11 @@ void mwl8k_update_survey(struct mwl8k_priv *priv, survey = &priv->survey[idx]; - cca_cnt = le32_to_cpu(ioread32(priv->regs + NOK_CCA_CNT_REG)); + cca_cnt = ioread32(priv->regs + NOK_CCA_CNT_REG); cca_cnt /= 1000; /* uSecs to mSecs */ survey->channel_time_busy = (u64) cca_cnt; - rx_rdy = le32_to_cpu(ioread32(priv->regs + BBU_RXRDY_CNT_REG)); + rx_rdy = ioread32(priv->regs + BBU_RXRDY_CNT_REG); rx_rdy /= 1000; /* uSecs to mSecs */ survey->channel_time_rx = (u64) rx_rdy; From c7c361efc49681962c5361e55a56d7ad8f5654a7 Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Thu, 6 Mar 2014 20:42:58 +0530 Subject: [PATCH 410/414] mwl8k: mwl8k_update_survey can be static It fixes following sparse check warning >#make C=1 CF=-D__CHECK_ENDIAN__ drivers/net/wireless/mwl8k.o >drivers/net/wireless/mwl8k.c:3089:6: warning: symbol 'mwl8k_update_survey' was not declared. Should it be static? Reported-by: Fengguang Wu Signed-off-by: Nishant Sarmukadam Signed-off-by: Yogesh Ashok Powar Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 706a445dba37..3c0a0a86ba12 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3088,8 +3088,8 @@ exit: return idx; } -void mwl8k_update_survey(struct mwl8k_priv *priv, - struct ieee80211_channel *channel) +static void mwl8k_update_survey(struct mwl8k_priv *priv, + struct ieee80211_channel *channel) { u32 cca_cnt, rx_rdy; s8 nf = 0, idx; From e46215fe678a9271c4eb98645187ef048d04e15f Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 13 Mar 2014 11:11:49 -0400 Subject: [PATCH 411/414] Revert "Revert "Staging: rtl8812ae: remove modules field of rate_control_ops"" This reverts commit 161d7855543520cde5f49df788b0ea0553a9f83a. Reversal of fortune -- I thought this was going to be resolved by other means, but that hasn't materialized. Plus, apparently we now care more than I realized about not breaking staging drivers... Signed-off-by: John W. Linville --- drivers/staging/rtl8821ae/rc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/rtl8821ae/rc.c b/drivers/staging/rtl8821ae/rc.c index d387f13ea7dc..0cc32c60ddee 100644 --- a/drivers/staging/rtl8821ae/rc.c +++ b/drivers/staging/rtl8821ae/rc.c @@ -286,7 +286,6 @@ static void rtl_rate_free_sta(void *rtlpriv, } static struct rate_control_ops rtl_rate_ops = { - .module = NULL, .name = "rtl_rc", .alloc = rtl_rate_alloc, .free = rtl_rate_free, From a699248613f7c32292fac23a60a75bcee14fb4a8 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 13 Mar 2014 12:53:52 -0400 Subject: [PATCH 412/414] rtl8821ae: fixup staging driver for revised ieee80211_is_robust_mgmt_frame Commit d8ca16db6bb2 ("mac80211: add length check in ieee80211_is_robust_mgmt_frame()") changed that API to take an skb, and added "_ieee80211_is_robust_mgmt_frame" as a direct replacement for the older API. This is the same fix that was applied to the other rtlwifi drivers in that commit. Cc: Johannes Berg Signed-off-by: John W. Linville --- drivers/staging/rtl8821ae/rtl8821ae/trx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/rtl8821ae/rtl8821ae/trx.c b/drivers/staging/rtl8821ae/rtl8821ae/trx.c index 75ae4387fe19..963b55f661c8 100644 --- a/drivers/staging/rtl8821ae/rtl8821ae/trx.c +++ b/drivers/staging/rtl8821ae/rtl8821ae/trx.c @@ -616,7 +616,7 @@ bool rtl8821ae_rx_query_desc(struct ieee80211_hw *hw, return false; } - if ((ieee80211_is_robust_mgmt_frame(hdr)) && + if ((_ieee80211_is_robust_mgmt_frame(hdr)) && (ieee80211_has_protected(hdr->frame_control))) rx_status->flag &= ~RX_FLAG_DECRYPTED; else From 3ead0d2e220ea7ced14027336bb168bafa01b7af Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 13 Mar 2014 13:08:27 -0400 Subject: [PATCH 413/414] wlan-ng: fixup staging driver for removal of ieee80211_dsss_chan_to_freq Commit 3ebe8e257307 ("ieee80211: remove function ieee80211_{dsss_chan_to_freq, freq_to_dsss_chan}") removed ieee80211_dsss_chan_to_freq, but it neglected to account for this staging driver... Cc: Zhao, Gang Signed-off-by: John W. Linville --- drivers/staging/wlan-ng/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c index a7d24c95191d..7dd2b95416e8 100644 --- a/drivers/staging/wlan-ng/cfg80211.c +++ b/drivers/staging/wlan-ng/cfg80211.c @@ -416,7 +416,7 @@ static int prism2_scan(struct wiphy *wiphy, memcpy(&ie_buf[2], &(msg2.ssid.data.data), msg2.ssid.data.len); bss = cfg80211_inform_bss(wiphy, ieee80211_get_channel(wiphy, - ieee80211_dsss_chan_to_freq(msg2.dschannel.data)), + ieee80211_channel_to_frequency(msg2.dschannel.data, IEEE80211_BAND_2GHZ)), (const u8 *) &(msg2.bssid.data.data), msg2.timestamp.data, msg2.capinfo.data, msg2.beaconperiod.data, From 4e3b3bcd81776527fa6f11624d68849de8c8802e Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 10 Mar 2014 18:53:10 -0500 Subject: [PATCH 414/414] rtlwifi: rtl8723be: Fix array dimension problems Commit a619d1abe20c leads to the following static checker warning: drivers/net/wireless/rtlwifi/rtl8723be/phy.c:667 _rtl8723be_store_tx_power_by_rate() error: buffer overflow 'rtlphy->tx_power_by_rate_offset[band]' 4 <= 5 This warning arises because the code is testing the indices for the wrong maximum values. In addition, the tests merely putput a warning, and then procedes to corrupt memory. With this change, any such invalid memory access is avoided. Signed-off-by: Larry Finger Reported-by: Dan Carpenter Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8723be/phy.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/phy.c b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c index cadae9bc4e3f..1575ef9ece9f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c @@ -629,18 +629,22 @@ static void _rtl8723be_store_tx_power_by_rate(struct ieee80211_hw *hw, struct rtl_phy *rtlphy = &(rtlpriv->phy); u8 rate_section = _rtl8723be_get_rate_section_index(regaddr); - if (band != BAND_ON_2_4G && band != BAND_ON_5G) + if (band != BAND_ON_2_4G && band != BAND_ON_5G) { RT_TRACE(rtlpriv, COMP_POWER, PHY_TXPWR, "Invalid Band %d\n", band); + return; + } - if (rfpath > MAX_RF_PATH) + if (rfpath > TX_PWR_BY_RATE_NUM_RF) { RT_TRACE(rtlpriv, COMP_POWER, PHY_TXPWR, "Invalid RfPath %d\n", rfpath); - - if (txnum > MAX_RF_PATH) + return; + } + if (txnum > TX_PWR_BY_RATE_NUM_RF) { RT_TRACE(rtlpriv, COMP_POWER, PHY_TXPWR, "Invalid TxNum %d\n", txnum); - + return; + } rtlphy->tx_power_by_rate_offset[band][rfpath][txnum][rate_section] = data; }