Commit 42774986 authored by John W. Linville's avatar John W. Linville
parents 9077f218 b622d992
...@@ -1328,10 +1328,9 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, ...@@ -1328,10 +1328,9 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
/* get data from A-MPDU parameters field */ /* get data from A-MPDU parameters field */
acx->ampdu_max_length = ht_cap->ampdu_factor; acx->ampdu_max_length = ht_cap->ampdu_factor;
acx->ampdu_min_spacing = ht_cap->ampdu_density; acx->ampdu_min_spacing = ht_cap->ampdu_density;
memcpy(acx->mac_address, mac_address, ETH_ALEN);
} }
memcpy(acx->mac_address, mac_address, ETH_ALEN);
acx->ht_capabilites = cpu_to_le32(ht_capabilites); acx->ht_capabilites = cpu_to_le32(ht_capabilites);
ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx));
...@@ -1542,3 +1541,28 @@ int wl1271_acx_config_ps(struct wl1271 *wl) ...@@ -1542,3 +1541,28 @@ int wl1271_acx_config_ps(struct wl1271 *wl)
kfree(config_ps); kfree(config_ps);
return ret; return ret;
} }
int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr)
{
struct wl1271_acx_inconnection_sta *acx = NULL;
int ret;
wl1271_debug(DEBUG_ACX, "acx set inconnaction sta %pM", addr);
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx)
return -ENOMEM;
memcpy(acx->addr, addr, ETH_ALEN);
ret = wl1271_cmd_configure(wl, ACX_UPDATE_INCONNECTION_STA_LIST,
acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx set inconnaction sta failed: %d", ret);
goto out;
}
out:
kfree(acx);
return ret;
}
...@@ -1155,6 +1155,13 @@ struct wl1271_acx_config_ps { ...@@ -1155,6 +1155,13 @@ struct wl1271_acx_config_ps {
__le32 null_data_rate; __le32 null_data_rate;
} __packed; } __packed;
struct wl1271_acx_inconnection_sta {
struct acx_header header;
u8 addr[ETH_ALEN];
u8 padding1[2];
} __packed;
enum { enum {
ACX_WAKE_UP_CONDITIONS = 0x0002, ACX_WAKE_UP_CONDITIONS = 0x0002,
ACX_MEM_CFG = 0x0003, ACX_MEM_CFG = 0x0003,
...@@ -1215,6 +1222,7 @@ enum { ...@@ -1215,6 +1222,7 @@ enum {
ACX_GEN_FW_CMD = 0x0070, ACX_GEN_FW_CMD = 0x0070,
ACX_HOST_IF_CFG_BITMAP = 0x0071, ACX_HOST_IF_CFG_BITMAP = 0x0071,
ACX_MAX_TX_FAILURE = 0x0072, ACX_MAX_TX_FAILURE = 0x0072,
ACX_UPDATE_INCONNECTION_STA_LIST = 0x0073,
DOT11_RX_MSDU_LIFE_TIME = 0x1004, DOT11_RX_MSDU_LIFE_TIME = 0x1004,
DOT11_CUR_TX_PWR = 0x100D, DOT11_CUR_TX_PWR = 0x100D,
DOT11_RX_DOT11_MODE = 0x1012, DOT11_RX_DOT11_MODE = 0x1012,
...@@ -1290,5 +1298,6 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, ...@@ -1290,5 +1298,6 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
int wl1271_acx_max_tx_retry(struct wl1271 *wl); int wl1271_acx_max_tx_retry(struct wl1271 *wl);
int wl1271_acx_config_ps(struct wl1271 *wl); int wl1271_acx_config_ps(struct wl1271 *wl);
int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
#endif /* __WL1271_ACX_H__ */ #endif /* __WL1271_ACX_H__ */
...@@ -483,7 +483,7 @@ static void wl1271_check_ba_support(struct wl1271 *wl) ...@@ -483,7 +483,7 @@ static void wl1271_check_ba_support(struct wl1271 *wl)
static int wl1271_set_ba_policies(struct wl1271 *wl) static int wl1271_set_ba_policies(struct wl1271 *wl)
{ {
u8 tid_index; u8 tid_index;
u8 ret = 0; int ret = 0;
/* Reset the BA RX indicators */ /* Reset the BA RX indicators */
wl->ba_rx_bitmap = 0; wl->ba_rx_bitmap = 0;
......
...@@ -482,6 +482,10 @@ static int wl1271_plt_init(struct wl1271 *wl) ...@@ -482,6 +482,10 @@ static int wl1271_plt_init(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
goto out_free_memmap; goto out_free_memmap;
ret = wl1271_acx_sta_mem_cfg(wl);
if (ret < 0)
goto out_free_memmap;
/* Default fragmentation threshold */ /* Default fragmentation threshold */
ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold); ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
if (ret < 0) if (ret < 0)
...@@ -533,6 +537,57 @@ static int wl1271_plt_init(struct wl1271 *wl) ...@@ -533,6 +537,57 @@ static int wl1271_plt_init(struct wl1271 *wl)
return ret; return ret;
} }
static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
{
bool fw_ps;
/* only regulate station links */
if (hlid < WL1271_AP_STA_HLID_START)
return;
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
/*
* Wake up from high level PS if the STA is asleep with too little
* blocks in FW or if the STA is awake.
*/
if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
wl1271_ps_link_end(wl, hlid);
/* Start high-level PS if the STA is asleep with enough blocks in FW */
else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
wl1271_ps_link_start(wl, hlid, true);
}
static void wl1271_irq_update_links_status(struct wl1271 *wl,
struct wl1271_fw_ap_status *status)
{
u32 cur_fw_ps_map;
u8 hlid;
cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
if (wl->ap_fw_ps_map != cur_fw_ps_map) {
wl1271_debug(DEBUG_PSM,
"link ps prev 0x%x cur 0x%x changed 0x%x",
wl->ap_fw_ps_map, cur_fw_ps_map,
wl->ap_fw_ps_map ^ cur_fw_ps_map);
wl->ap_fw_ps_map = cur_fw_ps_map;
}
for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
u8 cnt = status->tx_lnk_free_blks[hlid] -
wl->links[hlid].prev_freed_blks;
wl->links[hlid].prev_freed_blks =
status->tx_lnk_free_blks[hlid];
wl->links[hlid].allocated_blks -= cnt;
wl1271_irq_ps_regulate_link(wl, hlid,
wl->links[hlid].allocated_blks);
}
}
static void wl1271_fw_status(struct wl1271 *wl, static void wl1271_fw_status(struct wl1271 *wl,
struct wl1271_fw_full_status *full_status) struct wl1271_fw_full_status *full_status)
{ {
...@@ -570,6 +625,10 @@ static void wl1271_fw_status(struct wl1271 *wl, ...@@ -570,6 +625,10 @@ static void wl1271_fw_status(struct wl1271 *wl,
if (total) if (total)
clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
/* for AP update num of allocated TX blocks per link and ps status */
if (wl->bss_type == BSS_TYPE_AP_BSS)
wl1271_irq_update_links_status(wl, &full_status->ap);
/* update the host-chipset time offset */ /* update the host-chipset time offset */
getnstimeofday(&ts); getnstimeofday(&ts);
wl->time_offset = (timespec_to_ns(&ts) >> 10) - wl->time_offset = (timespec_to_ns(&ts) >> 10) -
...@@ -980,14 +1039,32 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ...@@ -980,14 +1039,32 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
struct wl1271 *wl = hw->priv; struct wl1271 *wl = hw->priv;
unsigned long flags; unsigned long flags;
int q; int q;
u8 hlid = 0;
spin_lock_irqsave(&wl->wl_lock, flags); spin_lock_irqsave(&wl->wl_lock, flags);
wl->tx_queue_count++; wl->tx_queue_count++;
/*
* The workqueue is slow to process the tx_queue and we need stop
* the queue here, otherwise the queue will get too long.
*/
if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
ieee80211_stop_queues(wl->hw);
set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
}
spin_unlock_irqrestore(&wl->wl_lock, flags); spin_unlock_irqrestore(&wl->wl_lock, flags);
/* queue the packet */ /* queue the packet */
q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
skb_queue_tail(&wl->tx_queue[q], skb); if (wl->bss_type == BSS_TYPE_AP_BSS) {
hlid = wl1271_tx_get_hlid(skb);
wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
} else {
skb_queue_tail(&wl->tx_queue[q], skb);
}
/* /*
* The chip specific setup must run before the first TX packet - * The chip specific setup must run before the first TX packet -
...@@ -997,19 +1074,6 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ...@@ -997,19 +1074,6 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
ieee80211_queue_work(wl->hw, &wl->tx_work); ieee80211_queue_work(wl->hw, &wl->tx_work);
/*
* The workqueue is slow to process the tx_queue and we need stop
* the queue here, otherwise the queue will get too long.
*/
if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
spin_lock_irqsave(&wl->wl_lock, flags);
ieee80211_stop_queues(wl->hw);
set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
...@@ -1221,6 +1285,8 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) ...@@ -1221,6 +1285,8 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl)
wl->filters = 0; wl->filters = 0;
wl1271_free_ap_keys(wl); wl1271_free_ap_keys(wl);
memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map)); memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
wl->ap_fw_ps_map = 0;
wl->ap_ps_map = 0;
for (i = 0; i < NUM_TX_QUEUES; i++) for (i = 0; i < NUM_TX_QUEUES; i++)
wl->tx_blocks_freed[i] = 0; wl->tx_blocks_freed[i] = 0;
...@@ -2218,6 +2284,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, ...@@ -2218,6 +2284,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
u32 sta_rate_set = 0; u32 sta_rate_set = 0;
int ret; int ret;
struct ieee80211_sta *sta; struct ieee80211_sta *sta;
bool sta_exists = false;
struct ieee80211_sta_ht_cap sta_ht_cap;
if (is_ibss) { if (is_ibss) {
ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
...@@ -2289,16 +2357,20 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, ...@@ -2289,16 +2357,20 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
if (sta->ht_cap.ht_supported) if (sta->ht_cap.ht_supported)
sta_rate_set |= sta_rate_set |=
(sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET); (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
sta_ht_cap = sta->ht_cap;
sta_exists = true;
}
rcu_read_unlock();
if (sta_exists) {
/* handle new association with HT and HT information change */ /* handle new association with HT and HT information change */
if ((changed & BSS_CHANGED_HT) && if ((changed & BSS_CHANGED_HT) &&
(bss_conf->channel_type != NL80211_CHAN_NO_HT)) { (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
true); true);
if (ret < 0) { if (ret < 0) {
wl1271_warning("Set ht cap true failed %d", wl1271_warning("Set ht cap true failed %d",
ret); ret);
rcu_read_unlock();
goto out; goto out;
} }
ret = wl1271_acx_set_ht_information(wl, ret = wl1271_acx_set_ht_information(wl,
...@@ -2306,23 +2378,20 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, ...@@ -2306,23 +2378,20 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
if (ret < 0) { if (ret < 0) {
wl1271_warning("Set ht information failed %d", wl1271_warning("Set ht information failed %d",
ret); ret);
rcu_read_unlock();
goto out; goto out;
} }
} }
/* handle new association without HT and disassociation */ /* handle new association without HT and disassociation */
else if (changed & BSS_CHANGED_ASSOC) { else if (changed & BSS_CHANGED_ASSOC) {
ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
false); false);
if (ret < 0) { if (ret < 0) {
wl1271_warning("Set ht cap false failed %d", wl1271_warning("Set ht cap false failed %d",
ret); ret);
rcu_read_unlock();
goto out; goto out;
} }
} }
} }
rcu_read_unlock();
if ((changed & BSS_CHANGED_ASSOC)) { if ((changed & BSS_CHANGED_ASSOC)) {
if (bss_conf->assoc) { if (bss_conf->assoc) {
...@@ -2612,7 +2681,7 @@ static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx, ...@@ -2612,7 +2681,7 @@ static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
return 0; return 0;
} }
static int wl1271_allocate_hlid(struct wl1271 *wl, static int wl1271_allocate_sta(struct wl1271 *wl,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
u8 *hlid) u8 *hlid)
{ {
...@@ -2626,18 +2695,25 @@ static int wl1271_allocate_hlid(struct wl1271 *wl, ...@@ -2626,18 +2695,25 @@ static int wl1271_allocate_hlid(struct wl1271 *wl,
} }
wl_sta = (struct wl1271_station *)sta->drv_priv; wl_sta = (struct wl1271_station *)sta->drv_priv;
__set_bit(id, wl->ap_hlid_map); __set_bit(id, wl->ap_hlid_map);
wl_sta->hlid = WL1271_AP_STA_HLID_START + id; wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
*hlid = wl_sta->hlid; *hlid = wl_sta->hlid;
memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
return 0; return 0;
} }
static void wl1271_free_hlid(struct wl1271 *wl, u8 hlid) static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
{ {
int id = hlid - WL1271_AP_STA_HLID_START; int id = hlid - WL1271_AP_STA_HLID_START;
if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
return;
__clear_bit(id, wl->ap_hlid_map); __clear_bit(id, wl->ap_hlid_map);
memset(wl->links[hlid].addr, 0, ETH_ALEN);
wl1271_tx_reset_link_queues(wl, hlid);
__clear_bit(hlid, &wl->ap_ps_map);
__clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
} }
static int wl1271_op_sta_add(struct ieee80211_hw *hw, static int wl1271_op_sta_add(struct ieee80211_hw *hw,
...@@ -2658,13 +2734,13 @@ static int wl1271_op_sta_add(struct ieee80211_hw *hw, ...@@ -2658,13 +2734,13 @@ static int wl1271_op_sta_add(struct ieee80211_hw *hw,
wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid); wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
ret = wl1271_allocate_hlid(wl, sta, &hlid); ret = wl1271_allocate_sta(wl, sta, &hlid);
if (ret < 0) if (ret < 0)
goto out; goto out;
ret = wl1271_ps_elp_wakeup(wl, false); ret = wl1271_ps_elp_wakeup(wl, false);
if (ret < 0) if (ret < 0)
goto out; goto out_free_sta;
ret = wl1271_cmd_add_sta(wl, sta, hlid); ret = wl1271_cmd_add_sta(wl, sta, hlid);
if (ret < 0) if (ret < 0)
...@@ -2673,6 +2749,10 @@ static int wl1271_op_sta_add(struct ieee80211_hw *hw, ...@@ -2673,6 +2749,10 @@ static int wl1271_op_sta_add(struct ieee80211_hw *hw,
out_sleep: out_sleep:
wl1271_ps_elp_sleep(wl); wl1271_ps_elp_sleep(wl);
out_free_sta:
if (ret < 0)
wl1271_free_sta(wl, hlid);
out: out:
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
return ret; return ret;
...@@ -2709,7 +2789,7 @@ static int wl1271_op_sta_remove(struct ieee80211_hw *hw, ...@@ -2709,7 +2789,7 @@ static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
if (ret < 0) if (ret < 0)
goto out_sleep; goto out_sleep;
wl1271_free_hlid(wl, wl_sta->hlid); wl1271_free_sta(wl, wl_sta->hlid);
out_sleep: out_sleep:
wl1271_ps_elp_sleep(wl); wl1271_ps_elp_sleep(wl);
...@@ -3212,7 +3292,9 @@ int wl1271_init_ieee80211(struct wl1271 *wl) ...@@ -3212,7 +3292,9 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
IEEE80211_HW_SUPPORTS_UAPSD | IEEE80211_HW_SUPPORTS_UAPSD |
IEEE80211_HW_HAS_RATE_CONTROL | IEEE80211_HW_HAS_RATE_CONTROL |
IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_CONNECTION_MONITOR |
IEEE80211_HW_SUPPORTS_CQM_RSSI; IEEE80211_HW_SUPPORTS_CQM_RSSI |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_AP_LINK_PS;
wl->hw->wiphy->cipher_suites = cipher_suites; wl->hw->wiphy->cipher_suites = cipher_suites;
wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
...@@ -3264,7 +3346,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) ...@@ -3264,7 +3346,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
struct platform_device *plat_dev = NULL; struct platform_device *plat_dev = NULL;
struct wl1271 *wl; struct wl1271 *wl;
int i, ret; int i, j, ret;
unsigned int order; unsigned int order;
hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
...@@ -3292,6 +3374,10 @@ struct ieee80211_hw *wl1271_alloc_hw(void) ...@@ -3292,6 +3374,10 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
for (i = 0; i < NUM_TX_QUEUES; i++) for (i = 0; i < NUM_TX_QUEUES; i++)
skb_queue_head_init(&wl->tx_queue[i]); skb_queue_head_init(&wl->tx_queue[i]);
for (i = 0; i < NUM_TX_QUEUES; i++)
for (j = 0; j < AP_MAX_LINKS; j++)
skb_queue_head_init(&wl->links[j].tx_queue[i]);
INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work); INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
INIT_WORK(&wl->irq_work, wl1271_irq_work); INIT_WORK(&wl->irq_work, wl1271_irq_work);
...@@ -3317,6 +3403,9 @@ struct ieee80211_hw *wl1271_alloc_hw(void) ...@@ -3317,6 +3403,9 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl->bss_type = MAX_BSS_TYPE; wl->bss_type = MAX_BSS_TYPE;
wl->set_bss_type = MAX_BSS_TYPE; wl->set_bss_type = MAX_BSS_TYPE;
wl->fw_bss_type = MAX_BSS_TYPE; wl->fw_bss_type = MAX_BSS_TYPE;
wl->last_tx_hlid = 0;
wl->ap_ps_map = 0;
wl->ap_fw_ps_map = 0;
memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
for (i = 0; i < ACX_TX_DESCRIPTORS; i++) for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
...@@ -3412,5 +3501,5 @@ module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR); ...@@ -3412,5 +3501,5 @@ module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
MODULE_PARM_DESC(debug_level, "wl12xx debugging level"); MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "reg.h" #include "reg.h"
#include "ps.h" #include "ps.h"
#include "io.h" #include "io.h"
#include "tx.h"
#define WL1271_WAKEUP_TIMEOUT 500 #define WL1271_WAKEUP_TIMEOUT 500
...@@ -173,4 +174,81 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, ...@@ -173,4 +174,81 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
return ret; return ret;
} }
static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)
{
int i, filtered = 0;
struct sk_buff *skb;
struct ieee80211_tx_info *info;
unsigned long flags;
/* filter all frames currently the low level queus for this hlid */
for (i = 0; i < NUM_TX_QUEUES; i++) {
while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
info = IEEE80211_SKB_CB(skb);
info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
info->status.rates[0].idx = -1;
ieee80211_tx_status(wl->hw, skb);
filtered++;
}
}
spin_lock_irqsave(&wl->wl_lock, flags);
wl->tx_queue_count -= filtered;
spin_unlock_irqrestore(&wl->wl_lock, flags);
wl1271_handle_tx_low_watermark(wl);
}
void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues)
{
struct ieee80211_sta *sta;
if (test_bit(hlid, &wl->ap_ps_map))
return;
wl1271_debug(DEBUG_PSM, "start mac80211 PSM on hlid %d blks %d "
"clean_queues %d", hlid, wl->links[hlid].allocated_blks,
clean_queues);
rcu_read_lock();
sta = ieee80211_find_sta(wl->vif, wl->links[hlid].addr);
if (!sta) {
wl1271_error("could not find sta %pM for starting ps",
wl->links[hlid].addr);
rcu_read_unlock();
return;
}
ieee80211_sta_ps_transition_ni(sta, true);
rcu_read_unlock();
/* do we want to filter all frames from this link's queues? */
if (clean_queues)
wl1271_ps_filter_frames(wl, hlid);
__set_bit(hlid, &wl->ap_ps_map);
}
void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid)
{
struct ieee80211_sta *sta;
if (!test_bit(hlid, &wl->ap_ps_map))
return;
wl1271_debug(DEBUG_PSM, "end mac80211 PSM on hlid %d", hlid);
__clear_bit(hlid, &wl->ap_ps_map);
rcu_read_lock();
sta = ieee80211_find_sta(wl->vif, wl->links[hlid].addr);
if (!sta) {
wl1271_error("could not find sta %pM for ending ps",
wl->links[hlid].addr);
goto end;
}
ieee80211_sta_ps_transition_ni(sta, false);
end:
rcu_read_unlock();
}
...@@ -32,5 +32,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, ...@@ -32,5 +32,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
void wl1271_ps_elp_sleep(struct wl1271 *wl); void wl1271_ps_elp_sleep(struct wl1271 *wl);
int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake); int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake);
void wl1271_elp_work(struct work_struct *work); void wl1271_elp_work(struct work_struct *work);
void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues);
void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid);
#endif /* __WL1271_PS_H__ */ #endif /* __WL1271_PS_H__ */
...@@ -92,7 +92,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) ...@@ -92,7 +92,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
{ {
struct wl1271_rx_descriptor *desc; struct wl1271_rx_descriptor *desc;
struct sk_buff *skb; struct sk_buff *skb;
u16 *fc; struct ieee80211_hdr *hdr;
u8 *buf; u8 *buf;
u8 beacon = 0; u8 beacon = 0;
...@@ -118,8 +118,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) ...@@ -118,8 +118,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
/* now we pull the descriptor out of the buffer */ /* now we pull the descriptor out of the buffer */
skb_pull(skb, sizeof(*desc)); skb_pull(skb, sizeof(*desc));
fc = (u16 *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) if (ieee80211_is_beacon(hdr->frame_control))
beacon = 1; beacon = 1;
wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon);
......
...@@ -30,10 +30,6 @@ ...@@ -30,10 +30,6 @@
#define WL1271_RX_MAX_RSSI -30 #define WL1271_RX_MAX_RSSI -30
#define WL1271_RX_MIN_RSSI -95 #define WL1271_RX_MIN_RSSI -95
#define WL1271_RX_ALIGN_TO 4
#define WL1271_RX_ALIGN(len) (((len) + WL1271_RX_ALIGN_TO - 1) & \
~(WL1271_RX_ALIGN_TO - 1))
#define SHORT_PREAMBLE_BIT BIT(0) #define SHORT_PREAMBLE_BIT BIT(0)
#define OFDM_RATE_BIT BIT(6) #define OFDM_RATE_BIT BIT(6)
#define PBCC_RATE_BIT BIT(7) #define PBCC_RATE_BIT BIT(7)
......
This diff is collapsed.
...@@ -53,8 +53,6 @@ ...@@ -53,8 +53,6 @@
#define TX_HW_RESULT_QUEUE_LEN_MASK 0xf #define TX_HW_RESULT_QUEUE_LEN_MASK 0xf
#define WL1271_TX_ALIGN_TO 4 #define WL1271_TX_ALIGN_TO 4
#define WL1271_TX_ALIGN(len) (((len) + WL1271_TX_ALIGN_TO - 1) & \
~(WL1271_TX_ALIGN_TO - 1))
#define WL1271_TKIP_IV_SPACE 4 #define WL1271_TKIP_IV_SPACE 4
struct wl1271_tx_hw_descr { struct wl1271_tx_hw_descr {
...@@ -152,5 +150,8 @@ void wl1271_tx_flush(struct wl1271 *wl); ...@@ -152,5 +150,8 @@ void wl1271_tx_flush(struct wl1271 *wl);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set);
u32 wl1271_tx_min_rate_get(struct wl1271 *wl); u32 wl1271_tx_min_rate_get(struct wl1271 *wl);
u8 wl1271_tx_get_hlid(struct sk_buff *skb);
void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid);
void wl1271_handle_tx_low_watermark(struct wl1271 *wl);
#endif #endif
...@@ -153,6 +153,17 @@ extern u32 wl12xx_debug_level; ...@@ -153,6 +153,17 @@ extern u32 wl12xx_debug_level;
#define WL1271_AP_BROADCAST_HLID 1 #define WL1271_AP_BROADCAST_HLID 1
#define WL1271_AP_STA_HLID_START 2 #define WL1271_AP_STA_HLID_START 2
/*
* When in AP-mode, we allow (at least) this number of mem-blocks
* to be transmitted to FW for a STA in PS-mode. Only when packets are
* present in the FW buffers it will wake the sleeping STA. We want to put
* enough packets for the driver to transmit all of its buffered data before
* the STA goes to sleep again. But we don't want to take too much mem-blocks
* as it might hurt the throughput of active STAs.
* The number of blocks (18) is enough for 2 large packets.
*/
#define WL1271_PS_STA_MAX_BLOCKS (2 * 9)
#define WL1271_AP_BSS_INDEX 0 #define WL1271_AP_BSS_INDEX 0
#define WL1271_AP_DEF_INACTIV_SEC 300 #define WL1271_AP_DEF_INACTIV_SEC 300
#define WL1271_AP_DEF_BEACON_EXP 20 #define WL1271_AP_DEF_BEACON_EXP 20
...@@ -319,6 +330,17 @@ enum wl12xx_flags { ...@@ -319,6 +330,17 @@ enum wl12xx_flags {
WL1271_FLAG_AP_STARTED WL1271_FLAG_AP_STARTED
}; };
struct wl1271_link {
/* AP-mode - TX queue per AC in link */
struct sk_buff_head tx_queue[NUM_TX_QUEUES];
/* accounting for allocated / available TX blocks in FW */
u8 allocated_blks;
u8 prev_freed_blks;
u8 addr[ETH_ALEN];
};
struct wl1271 { struct wl1271 {
struct platform_device *plat_dev; struct platform_device *plat_dev;
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
...@@ -498,6 +520,21 @@ struct wl1271 { ...@@ -498,6 +520,21 @@ struct wl1271 {
/* RX BA constraint value */ /* RX BA constraint value */
bool ba_support; bool ba_support;
u8 ba_rx_bitmap; u8 ba_rx_bitmap;
/*
* AP-mode - links indexed by HLID. The global and broadcast links
* are always active.
*/
struct wl1271_link links[AP_MAX_LINKS];
/* the hlid of the link where the last transmitted skb came from */
int last_tx_hlid;
/* AP-mode - a bitmap of links currently in PS mode according to FW */
u32 ap_fw_ps_map;
/* AP-mode - a bitmap of links currently in PS mode in mac80211 */
unsigned long ap_ps_map;
}; };
struct wl1271_station { struct wl1271_station {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment