Merge branch 'for-linville' of git://github.com/kvalo/ath

This commit is contained in:
John W. Linville 2013-08-15 15:54:06 -04:00
commit 946951e141
11 changed files with 270 additions and 43 deletions

View File

@ -637,6 +637,7 @@ static int ath10k_ce_completed_send_next_nolock(struct ce_state *ce_state,
ath10k_pci_wake(ar); ath10k_pci_wake(ar);
src_ring->hw_index = src_ring->hw_index =
ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); ath10k_ce_src_ring_read_index_get(ar, ctrl_addr);
src_ring->hw_index &= nentries_mask;
ath10k_pci_sleep(ar); ath10k_pci_sleep(ar);
} }
read_index = src_ring->hw_index; read_index = src_ring->hw_index;
@ -950,10 +951,12 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,
ath10k_pci_wake(ar); ath10k_pci_wake(ar);
src_ring->sw_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); src_ring->sw_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr);
src_ring->sw_index &= src_ring->nentries_mask;
src_ring->hw_index = src_ring->sw_index; src_ring->hw_index = src_ring->sw_index;
src_ring->write_index = src_ring->write_index =
ath10k_ce_src_ring_write_index_get(ar, ctrl_addr); ath10k_ce_src_ring_write_index_get(ar, ctrl_addr);
src_ring->write_index &= src_ring->nentries_mask;
ath10k_pci_sleep(ar); ath10k_pci_sleep(ar);
src_ring->per_transfer_context = (void **)ptr; src_ring->per_transfer_context = (void **)ptr;
@ -1035,8 +1038,10 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar,
ath10k_pci_wake(ar); ath10k_pci_wake(ar);
dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr); dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr);
dest_ring->sw_index &= dest_ring->nentries_mask;
dest_ring->write_index = dest_ring->write_index =
ath10k_ce_dest_ring_write_index_get(ar, ctrl_addr); ath10k_ce_dest_ring_write_index_get(ar, ctrl_addr);
dest_ring->write_index &= dest_ring->nentries_mask;
ath10k_pci_sleep(ar); ath10k_pci_sleep(ar);
dest_ring->per_transfer_context = (void **)ptr; dest_ring->per_transfer_context = (void **)ptr;

View File

@ -38,6 +38,7 @@
#define ATH10K_SCAN_ID 0 #define ATH10K_SCAN_ID 0
#define WMI_READY_TIMEOUT (5 * HZ) #define WMI_READY_TIMEOUT (5 * HZ)
#define ATH10K_FLUSH_TIMEOUT_HZ (5*HZ) #define ATH10K_FLUSH_TIMEOUT_HZ (5*HZ)
#define ATH10K_NUM_CHANS 38
/* Antenna noise floor */ /* Antenna noise floor */
#define ATH10K_DEFAULT_NOISE_FLOOR -95 #define ATH10K_DEFAULT_NOISE_FLOOR -95
@ -285,6 +286,7 @@ struct ath10k {
u32 hw_max_tx_power; u32 hw_max_tx_power;
u32 ht_cap_info; u32 ht_cap_info;
u32 vht_cap_info; u32 vht_cap_info;
u32 num_rf_chains;
struct targetdef *targetdef; struct targetdef *targetdef;
struct hostdef *hostdef; struct hostdef *hostdef;
@ -374,6 +376,12 @@ struct ath10k {
struct work_struct restart_work; struct work_struct restart_work;
/* cycle count is reported twice for each visited channel during scan.
* access protected by data_lock */
u32 survey_last_rx_clear_count;
u32 survey_last_cycle_count;
struct survey_info survey[ATH10K_NUM_CHANS];
#ifdef CONFIG_ATH10K_DEBUGFS #ifdef CONFIG_ATH10K_DEBUGFS
struct ath10k_debug debug; struct ath10k_debug debug;
#endif #endif

View File

@ -804,6 +804,37 @@ static bool ath10k_htt_rx_has_fcs_err(struct sk_buff *skb)
return false; return false;
} }
static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb)
{
struct htt_rx_desc *rxd;
u32 flags, info;
bool is_ip4, is_ip6;
bool is_tcp, is_udp;
bool ip_csum_ok, tcpudp_csum_ok;
rxd = (void *)skb->data - sizeof(*rxd);
flags = __le32_to_cpu(rxd->attention.flags);
info = __le32_to_cpu(rxd->msdu_start.info1);
is_ip4 = !!(info & RX_MSDU_START_INFO1_IPV4_PROTO);
is_ip6 = !!(info & RX_MSDU_START_INFO1_IPV6_PROTO);
is_tcp = !!(info & RX_MSDU_START_INFO1_TCP_PROTO);
is_udp = !!(info & RX_MSDU_START_INFO1_UDP_PROTO);
ip_csum_ok = !(flags & RX_ATTENTION_FLAGS_IP_CHKSUM_FAIL);
tcpudp_csum_ok = !(flags & RX_ATTENTION_FLAGS_TCP_UDP_CHKSUM_FAIL);
if (!is_ip4 && !is_ip6)
return CHECKSUM_NONE;
if (!is_tcp && !is_udp)
return CHECKSUM_NONE;
if (!ip_csum_ok)
return CHECKSUM_NONE;
if (!tcpudp_csum_ok)
return CHECKSUM_NONE;
return CHECKSUM_UNNECESSARY;
}
static void ath10k_htt_rx_handler(struct ath10k_htt *htt, static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
struct htt_rx_indication *rx) struct htt_rx_indication *rx)
{ {
@ -815,6 +846,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
u8 *fw_desc; u8 *fw_desc;
int i, j; int i, j;
int ret; int ret;
int ip_summed;
memset(&info, 0, sizeof(info)); memset(&info, 0, sizeof(info));
@ -889,6 +921,11 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
continue; continue;
} }
/* The skb is not yet processed and it may be
* reallocated. Since the offload is in the original
* skb extract the checksum now and assign it later */
ip_summed = ath10k_htt_rx_get_csum_state(msdu_head);
info.skb = msdu_head; info.skb = msdu_head;
info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head); info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head);
info.signal = ATH10K_DEFAULT_NOISE_FLOOR; info.signal = ATH10K_DEFAULT_NOISE_FLOOR;
@ -914,6 +951,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
if (ath10k_htt_rx_hdr_is_amsdu((void *)info.skb->data)) if (ath10k_htt_rx_hdr_is_amsdu((void *)info.skb->data))
ath10k_dbg(ATH10K_DBG_HTT, "htt mpdu is amsdu\n"); ath10k_dbg(ATH10K_DBG_HTT, "htt mpdu is amsdu\n");
info.skb->ip_summed = ip_summed;
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt mpdu: ", ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt mpdu: ",
info.skb->data, info.skb->len); info.skb->data, info.skb->len);
ath10k_process_rx(htt->ar, &info); ath10k_process_rx(htt->ar, &info);
@ -980,6 +1019,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
info.status = HTT_RX_IND_MPDU_STATUS_OK; info.status = HTT_RX_IND_MPDU_STATUS_OK;
info.encrypt_type = MS(__le32_to_cpu(rxd->mpdu_start.info0), info.encrypt_type = MS(__le32_to_cpu(rxd->mpdu_start.info0),
RX_MPDU_START_INFO0_ENCRYPT_TYPE); RX_MPDU_START_INFO0_ENCRYPT_TYPE);
info.skb->ip_summed = ath10k_htt_rx_get_csum_state(info.skb);
if (tkip_mic_err) { if (tkip_mic_err) {
ath10k_warn("tkip mic error\n"); ath10k_warn("tkip mic error\n");

View File

@ -465,6 +465,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
flags1 = 0; flags1 = 0;
flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID); flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID);
flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID); flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID);
flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD;
flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD;
frags_paddr = ATH10K_SKB_CB(txfrag)->paddr; frags_paddr = ATH10K_SKB_CB(txfrag)->paddr;

View File

@ -1406,9 +1406,9 @@ static void ath10k_tx_h_qos_workaround(struct ieee80211_hw *hw,
return; return;
qos_ctl = ieee80211_get_qos_ctl(hdr); qos_ctl = ieee80211_get_qos_ctl(hdr);
memmove(qos_ctl, qos_ctl + IEEE80211_QOS_CTL_LEN, memmove(skb->data + IEEE80211_QOS_CTL_LEN,
skb->len - ieee80211_hdrlen(hdr->frame_control)); skb->data, (void *)qos_ctl - (void *)skb->data);
skb_trim(skb, skb->len - IEEE80211_QOS_CTL_LEN); skb_pull(skb, IEEE80211_QOS_CTL_LEN);
} }
static void ath10k_tx_h_update_wep_key(struct sk_buff *skb) static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)
@ -1925,6 +1925,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
mutex_lock(&ar->conf_mutex); mutex_lock(&ar->conf_mutex);
memset(arvif, 0, sizeof(*arvif));
arvif->ar = ar; arvif->ar = ar;
arvif->vif = vif; arvif->vif = vif;
@ -2338,6 +2340,8 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw,
arg.ssids[i].len = req->ssids[i].ssid_len; arg.ssids[i].len = req->ssids[i].ssid_len;
arg.ssids[i].ssid = req->ssids[i].ssid; arg.ssids[i].ssid = req->ssids[i].ssid;
} }
} else {
arg.scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE;
} }
if (req->n_channels) { if (req->n_channels) {
@ -2934,6 +2938,41 @@ static void ath10k_restart_complete(struct ieee80211_hw *hw)
mutex_unlock(&ar->conf_mutex); mutex_unlock(&ar->conf_mutex);
} }
static int ath10k_get_survey(struct ieee80211_hw *hw, int idx,
struct survey_info *survey)
{
struct ath10k *ar = hw->priv;
struct ieee80211_supported_band *sband;
struct survey_info *ar_survey = &ar->survey[idx];
int ret = 0;
mutex_lock(&ar->conf_mutex);
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) {
ret = -ENOENT;
goto exit;
}
spin_lock_bh(&ar->data_lock);
memcpy(survey, ar_survey, sizeof(*survey));
spin_unlock_bh(&ar->data_lock);
survey->channel = &sband->channels[idx];
exit:
mutex_unlock(&ar->conf_mutex);
return ret;
}
static const struct ieee80211_ops ath10k_ops = { static const struct ieee80211_ops ath10k_ops = {
.tx = ath10k_tx, .tx = ath10k_tx,
.start = ath10k_start, .start = ath10k_start,
@ -2955,6 +2994,7 @@ static const struct ieee80211_ops ath10k_ops = {
.flush = ath10k_flush, .flush = ath10k_flush,
.tx_last_beacon = ath10k_tx_last_beacon, .tx_last_beacon = ath10k_tx_last_beacon,
.restart_complete = ath10k_restart_complete, .restart_complete = ath10k_restart_complete,
.get_survey = ath10k_get_survey,
#ifdef CONFIG_PM #ifdef CONFIG_PM
.suspend = ath10k_suspend, .suspend = ath10k_suspend,
.resume = ath10k_resume, .resume = ath10k_resume,
@ -3076,9 +3116,15 @@ static const struct ieee80211_iface_limit ath10k_if_limits[] = {
.max = 8, .max = 8,
.types = BIT(NL80211_IFTYPE_STATION) .types = BIT(NL80211_IFTYPE_STATION)
| BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_CLIENT)
| BIT(NL80211_IFTYPE_P2P_GO) },
| BIT(NL80211_IFTYPE_AP) {
} .max = 3,
.types = BIT(NL80211_IFTYPE_P2P_GO)
},
{
.max = 7,
.types = BIT(NL80211_IFTYPE_AP)
},
}; };
static const struct ieee80211_iface_combination ath10k_if_comb = { static const struct ieee80211_iface_combination ath10k_if_comb = {
@ -3093,19 +3139,18 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
{ {
struct ieee80211_sta_vht_cap vht_cap = {0}; struct ieee80211_sta_vht_cap vht_cap = {0};
u16 mcs_map; u16 mcs_map;
int i;
vht_cap.vht_supported = 1; vht_cap.vht_supported = 1;
vht_cap.cap = ar->vht_cap_info; vht_cap.cap = ar->vht_cap_info;
/* FIXME: check dynamically how many streams board supports */ mcs_map = 0;
mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | for (i = 0; i < 8; i++) {
IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 | if (i < ar->num_rf_chains)
IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 | mcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << (i*2);
IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | else
IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i*2);
IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | }
IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
IEEE80211_VHT_MCS_NOT_SUPPORTED << 14;
vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
@ -3168,7 +3213,7 @@ static struct ieee80211_sta_ht_cap ath10k_get_ht_cap(struct ath10k *ar)
if (ar->vht_cap_info & WMI_VHT_CAP_MAX_MPDU_LEN_MASK) if (ar->vht_cap_info & WMI_VHT_CAP_MAX_MPDU_LEN_MASK)
ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU; ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU;
for (i = 0; i < WMI_MAX_SPATIAL_STREAM; i++) for (i = 0; i < ar->num_rf_chains; i++)
ht_cap.mcs.rx_mask[i] = 0xFF; ht_cap.mcs.rx_mask[i] = 0xFF;
ht_cap.mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; ht_cap.mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
@ -3310,6 +3355,8 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->wiphy->iface_combinations = &ath10k_if_comb; ar->hw->wiphy->iface_combinations = &ath10k_if_comb;
ar->hw->wiphy->n_iface_combinations = 1; ar->hw->wiphy->n_iface_combinations = 1;
ar->hw->netdev_features = NETIF_F_HW_CSUM;
ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy, ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy,
ath10k_reg_notifier); ath10k_reg_notifier);
if (ret) { if (ret) {

View File

@ -32,7 +32,7 @@
#include "ce.h" #include "ce.h"
#include "pci.h" #include "pci.h"
unsigned int ath10k_target_ps; static unsigned int ath10k_target_ps;
module_param(ath10k_target_ps, uint, 0644); module_param(ath10k_target_ps, uint, 0644);
MODULE_PARM_DESC(ath10k_target_ps, "Enable ath10k Target (SoC) PS option"); MODULE_PARM_DESC(ath10k_target_ps, "Enable ath10k Target (SoC) PS option");
@ -56,6 +56,8 @@ static void ath10k_pci_rx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info);
static void ath10k_pci_stop_ce(struct ath10k *ar); static void ath10k_pci_stop_ce(struct ath10k *ar);
static void ath10k_pci_device_reset(struct ath10k *ar); static void ath10k_pci_device_reset(struct ath10k *ar);
static int ath10k_pci_reset_target(struct ath10k *ar); static int ath10k_pci_reset_target(struct ath10k *ar);
static int ath10k_pci_start_intr(struct ath10k *ar);
static void ath10k_pci_stop_intr(struct ath10k *ar);
static const struct ce_attr host_ce_config_wlan[] = { static const struct ce_attr host_ce_config_wlan[] = {
/* host->target HTC control and raw streams */ /* host->target HTC control and raw streams */
@ -1254,10 +1256,25 @@ static void ath10k_pci_ce_deinit(struct ath10k *ar)
} }
} }
static void ath10k_pci_disable_irqs(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int i;
for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
disable_irq(ar_pci->pdev->irq + i);
}
static void ath10k_pci_hif_stop(struct ath10k *ar) static void ath10k_pci_hif_stop(struct ath10k *ar)
{ {
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__); ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
/* Irqs are never explicitly re-enabled. They are implicitly re-enabled
* by ath10k_pci_start_intr(). */
ath10k_pci_disable_irqs(ar);
ath10k_pci_stop_ce(ar); ath10k_pci_stop_ce(ar);
/* At this point, asynchronous threads are stopped, the target should /* At this point, asynchronous threads are stopped, the target should
@ -1267,6 +1284,8 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
ath10k_pci_process_ce(ar); ath10k_pci_process_ce(ar);
ath10k_pci_cleanup_ce(ar); ath10k_pci_cleanup_ce(ar);
ath10k_pci_buffer_cleanup(ar); ath10k_pci_buffer_cleanup(ar);
ar_pci->started = 0;
} }
static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
@ -1740,8 +1759,15 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
static int ath10k_pci_hif_power_up(struct ath10k *ar) static int ath10k_pci_hif_power_up(struct ath10k *ar)
{ {
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int ret; int ret;
ret = ath10k_pci_start_intr(ar);
if (ret) {
ath10k_err("could not start interrupt handling (%d)\n", ret);
goto err;
}
/* /*
* Bring the target up cleanly. * Bring the target up cleanly.
* *
@ -1756,15 +1782,11 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
ret = ath10k_pci_reset_target(ar); ret = ath10k_pci_reset_target(ar);
if (ret) if (ret)
goto err; goto err_irq;
if (ath10k_target_ps) { if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
ath10k_dbg(ATH10K_DBG_PCI, "on-chip power save enabled\n");
} else {
/* Force AWAKE forever */ /* Force AWAKE forever */
ath10k_dbg(ATH10K_DBG_PCI, "on-chip power save disabled\n");
ath10k_do_pci_wake(ar); ath10k_do_pci_wake(ar);
}
ret = ath10k_pci_ce_init(ar); ret = ath10k_pci_ce_init(ar);
if (ret) if (ret)
@ -1785,16 +1807,22 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
err_ce: err_ce:
ath10k_pci_ce_deinit(ar); ath10k_pci_ce_deinit(ar);
err_ps: err_ps:
if (!ath10k_target_ps) if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
ath10k_do_pci_sleep(ar); ath10k_do_pci_sleep(ar);
err_irq:
ath10k_pci_stop_intr(ar);
err: err:
return ret; return ret;
} }
static void ath10k_pci_hif_power_down(struct ath10k *ar) static void ath10k_pci_hif_power_down(struct ath10k *ar)
{ {
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
ath10k_pci_stop_intr(ar);
ath10k_pci_ce_deinit(ar); ath10k_pci_ce_deinit(ar);
if (!ath10k_target_ps) if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
ath10k_do_pci_sleep(ar); ath10k_do_pci_sleep(ar);
} }
@ -1990,8 +2018,13 @@ static int ath10k_pci_start_intr_msix(struct ath10k *ar, int num)
ret = request_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW, ret = request_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW,
ath10k_pci_msi_fw_handler, ath10k_pci_msi_fw_handler,
IRQF_SHARED, "ath10k_pci", ar); IRQF_SHARED, "ath10k_pci", ar);
if (ret) if (ret) {
ath10k_warn("request_irq(%d) failed %d\n",
ar_pci->pdev->irq + MSI_ASSIGN_FW, ret);
pci_disable_msi(ar_pci->pdev);
return ret; return ret;
}
for (i = MSI_ASSIGN_CE_INITIAL; i <= MSI_ASSIGN_CE_MAX; i++) { for (i = MSI_ASSIGN_CE_INITIAL; i <= MSI_ASSIGN_CE_MAX; i++) {
ret = request_irq(ar_pci->pdev->irq + i, ret = request_irq(ar_pci->pdev->irq + i,
@ -2239,6 +2272,9 @@ static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci)
case ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND: case ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND:
ath10k_dbg(ATH10K_DBG_PCI, "QCA988X_1.0 workaround enabled\n"); ath10k_dbg(ATH10K_DBG_PCI, "QCA988X_1.0 workaround enabled\n");
break; break;
case ATH10K_PCI_FEATURE_SOC_POWER_SAVE:
ath10k_dbg(ATH10K_DBG_PCI, "QCA98XX SoC power save enabled\n");
break;
} }
} }
} }
@ -2274,6 +2310,9 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
goto err_ar_pci; goto err_ar_pci;
} }
if (ath10k_target_ps)
set_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features);
ath10k_pci_dump_features(ar_pci); ath10k_pci_dump_features(ar_pci);
ar = ath10k_core_create(ar_pci, ar_pci->dev, &ath10k_pci_hif_ops); ar = ath10k_core_create(ar_pci, ar_pci->dev, &ath10k_pci_hif_ops);
@ -2358,22 +2397,14 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
ar_pci->cacheline_sz = dma_get_cache_alignment(); ar_pci->cacheline_sz = dma_get_cache_alignment();
ret = ath10k_pci_start_intr(ar);
if (ret) {
ath10k_err("could not start interrupt handling (%d)\n", ret);
goto err_iomap;
}
ret = ath10k_core_register(ar); ret = ath10k_core_register(ar);
if (ret) { if (ret) {
ath10k_err("could not register driver core (%d)\n", ret); ath10k_err("could not register driver core (%d)\n", ret);
goto err_intr; goto err_iomap;
} }
return 0; return 0;
err_intr:
ath10k_pci_stop_intr(ar);
err_iomap: err_iomap:
pci_iounmap(pdev, mem); pci_iounmap(pdev, mem);
err_master: err_master:
@ -2410,7 +2441,6 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
tasklet_kill(&ar_pci->msi_fw_err); tasklet_kill(&ar_pci->msi_fw_err);
ath10k_core_unregister(ar); ath10k_core_unregister(ar);
ath10k_pci_stop_intr(ar);
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);
pci_iounmap(pdev, ar_pci->mem); pci_iounmap(pdev, ar_pci->mem);

View File

@ -153,6 +153,7 @@ struct service_to_pipe {
enum ath10k_pci_features { enum ath10k_pci_features {
ATH10K_PCI_FEATURE_MSI_X = 0, ATH10K_PCI_FEATURE_MSI_X = 0,
ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND = 1, ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND = 1,
ATH10K_PCI_FEATURE_SOC_POWER_SAVE = 2,
/* keep last */ /* keep last */
ATH10K_PCI_FEATURE_COUNT ATH10K_PCI_FEATURE_COUNT
@ -335,20 +336,22 @@ static inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
return ioread32(ar_pci->mem + offset); return ioread32(ar_pci->mem + offset);
} }
extern unsigned int ath10k_target_ps;
void ath10k_do_pci_wake(struct ath10k *ar); void ath10k_do_pci_wake(struct ath10k *ar);
void ath10k_do_pci_sleep(struct ath10k *ar); void ath10k_do_pci_sleep(struct ath10k *ar);
static inline void ath10k_pci_wake(struct ath10k *ar) static inline void ath10k_pci_wake(struct ath10k *ar)
{ {
if (ath10k_target_ps) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
ath10k_do_pci_wake(ar); ath10k_do_pci_wake(ar);
} }
static inline void ath10k_pci_sleep(struct ath10k *ar) static inline void ath10k_pci_sleep(struct ath10k *ar)
{ {
if (ath10k_target_ps) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
ath10k_do_pci_sleep(ar); ath10k_do_pci_sleep(ar);
} }

View File

@ -390,9 +390,82 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
return 0; return 0;
} }
static int freq_to_idx(struct ath10k *ar, int freq)
{
struct ieee80211_supported_band *sband;
int band, ch, idx = 0;
for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) {
sband = ar->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;
}
static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
{ {
ath10k_dbg(ATH10K_DBG_WMI, "WMI_CHAN_INFO_EVENTID\n"); struct wmi_chan_info_event *ev;
struct survey_info *survey;
u32 err_code, freq, cmd_flags, noise_floor, rx_clear_count, cycle_count;
int idx;
ev = (struct wmi_chan_info_event *)skb->data;
err_code = __le32_to_cpu(ev->err_code);
freq = __le32_to_cpu(ev->freq);
cmd_flags = __le32_to_cpu(ev->cmd_flags);
noise_floor = __le32_to_cpu(ev->noise_floor);
rx_clear_count = __le32_to_cpu(ev->rx_clear_count);
cycle_count = __le32_to_cpu(ev->cycle_count);
ath10k_dbg(ATH10K_DBG_WMI,
"chan info err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d\n",
err_code, freq, cmd_flags, noise_floor, rx_clear_count,
cycle_count);
spin_lock_bh(&ar->data_lock);
if (!ar->scan.in_progress) {
ath10k_warn("chan info event without a scan request?\n");
goto exit;
}
idx = freq_to_idx(ar, freq);
if (idx >= ARRAY_SIZE(ar->survey)) {
ath10k_warn("chan info: invalid frequency %d (idx %d out of bounds)\n",
freq, idx);
goto exit;
}
if (cmd_flags & WMI_CHAN_INFO_FLAG_COMPLETE) {
/* During scanning chan info is reported twice for each
* visited channel. The reported cycle count is global
* and per-channel cycle count must be calculated */
cycle_count -= ar->survey_last_cycle_count;
rx_clear_count -= ar->survey_last_rx_clear_count;
survey = &ar->survey[idx];
survey->channel_time = WMI_CHAN_INFO_MSEC(cycle_count);
survey->channel_time_rx = WMI_CHAN_INFO_MSEC(rx_clear_count);
survey->noise = noise_floor;
survey->filled = SURVEY_INFO_CHANNEL_TIME |
SURVEY_INFO_CHANNEL_TIME_RX |
SURVEY_INFO_NOISE_DBM;
}
ar->survey_last_rx_clear_count = rx_clear_count;
ar->survey_last_cycle_count = cycle_count;
exit:
spin_unlock_bh(&ar->data_lock);
} }
static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb) static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb)
@ -868,6 +941,13 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
(__le32_to_cpu(ev->sw_version_1) & 0xffff0000) >> 16; (__le32_to_cpu(ev->sw_version_1) & 0xffff0000) >> 16;
ar->fw_version_build = (__le32_to_cpu(ev->sw_version_1) & 0x0000ffff); ar->fw_version_build = (__le32_to_cpu(ev->sw_version_1) & 0x0000ffff);
ar->phy_capability = __le32_to_cpu(ev->phy_capability); ar->phy_capability = __le32_to_cpu(ev->phy_capability);
ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains);
if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {
ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n",
ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM);
ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM;
}
ar->ath_common.regulatory.current_rd = ar->ath_common.regulatory.current_rd =
__le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd); __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd);
@ -892,7 +972,7 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
} }
ath10k_dbg(ATH10K_DBG_WMI, ath10k_dbg(ATH10K_DBG_WMI,
"wmi event service ready sw_ver 0x%08x sw_ver1 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u\n", "wmi event service ready sw_ver 0x%08x sw_ver1 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n",
__le32_to_cpu(ev->sw_version), __le32_to_cpu(ev->sw_version),
__le32_to_cpu(ev->sw_version_1), __le32_to_cpu(ev->sw_version_1),
__le32_to_cpu(ev->abi_version), __le32_to_cpu(ev->abi_version),
@ -901,7 +981,8 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
__le32_to_cpu(ev->vht_cap_info), __le32_to_cpu(ev->vht_cap_info),
__le32_to_cpu(ev->vht_supp_mcs), __le32_to_cpu(ev->vht_supp_mcs),
__le32_to_cpu(ev->sys_cap_info), __le32_to_cpu(ev->sys_cap_info),
__le32_to_cpu(ev->num_mem_reqs)); __le32_to_cpu(ev->num_mem_reqs),
__le32_to_cpu(ev->num_rf_chains));
complete(&ar->wmi.service_ready); complete(&ar->wmi.service_ready);
} }

View File

@ -2931,6 +2931,11 @@ struct wmi_chan_info_event {
__le32 cycle_count; __le32 cycle_count;
} __packed; } __packed;
#define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0)
/* FIXME: empirically extrapolated */
#define WMI_CHAN_INFO_MSEC(x) ((x) / 76595)
/* Beacon filter wmi command info */ /* Beacon filter wmi command info */
#define BCN_FLT_MAX_SUPPORTED_IES 256 #define BCN_FLT_MAX_SUPPORTED_IES 256
#define BCN_FLT_MAX_ELEMS_IE_LIST (BCN_FLT_MAX_SUPPORTED_IES / 32) #define BCN_FLT_MAX_ELEMS_IE_LIST (BCN_FLT_MAX_SUPPORTED_IES / 32)

View File

@ -1836,6 +1836,9 @@ void ath6kl_stop_txrx(struct ath6kl *ar)
clear_bit(WMI_READY, &ar->flag); clear_bit(WMI_READY, &ar->flag);
if (ar->fw_recovery.enable)
del_timer_sync(&ar->fw_recovery.hb_timer);
/* /*
* After wmi_shudown all WMI events will be dropped. We * After wmi_shudown all WMI events will be dropped. We
* need to cleanup the buffers allocated in AP mode and * need to cleanup the buffers allocated in AP mode and

View File

@ -29,6 +29,9 @@ struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 *node_addr)
struct ath6kl_sta *conn = NULL; struct ath6kl_sta *conn = NULL;
u8 i, max_conn; u8 i, max_conn;
if (is_zero_ether_addr(node_addr))
return NULL;
max_conn = (vif->nw_type == AP_NETWORK) ? AP_MAX_NUM_STA : 0; max_conn = (vif->nw_type == AP_NETWORK) ? AP_MAX_NUM_STA : 0;
for (i = 0; i < max_conn; i++) { for (i = 0; i < max_conn; i++) {