Commit e441a5ea authored by John W. Linville's avatar John W. Linville
parents 5f0dd296 f1a46384
...@@ -90,7 +90,7 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power) ...@@ -90,7 +90,7 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power)
struct acx_current_tx_power *acx; struct acx_current_tx_power *acx;
int ret; int ret;
wl1271_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); wl1271_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr %d", power);
if (power < 0 || power > 25) if (power < 0 || power > 25)
return -EINVAL; return -EINVAL;
...@@ -1624,22 +1624,22 @@ int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable) ...@@ -1624,22 +1624,22 @@ int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable)
return ret; return ret;
} }
int wl1271_acx_max_tx_retry(struct wl1271 *wl) int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl)
{ {
struct wl1271_acx_max_tx_retry *acx = NULL; struct wl1271_acx_ap_max_tx_retry *acx = NULL;
int ret; int ret;
wl1271_debug(DEBUG_ACX, "acx max tx retry"); wl1271_debug(DEBUG_ACX, "acx ap max tx retry");
acx = kzalloc(sizeof(*acx), GFP_KERNEL); acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) if (!acx)
return -ENOMEM; return -ENOMEM;
acx->max_tx_retry = cpu_to_le16(wl->conf.tx.ap_max_tx_retries); acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries);
ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx)); ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx));
if (ret < 0) { if (ret < 0) {
wl1271_warning("acx max tx retry failed: %d", ret); wl1271_warning("acx ap max tx retry failed: %d", ret);
goto out; goto out;
} }
......
...@@ -1168,7 +1168,7 @@ struct wl1271_acx_ps_rx_streaming { ...@@ -1168,7 +1168,7 @@ struct wl1271_acx_ps_rx_streaming {
u8 timeout; u8 timeout;
} __packed; } __packed;
struct wl1271_acx_max_tx_retry { struct wl1271_acx_ap_max_tx_retry {
struct acx_header header; struct acx_header header;
/* /*
...@@ -1400,7 +1400,7 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, ...@@ -1400,7 +1400,7 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
bool enable); bool enable);
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable); int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable);
int wl1271_acx_max_tx_retry(struct wl1271 *wl); int wl1271_acx_ap_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); int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable); int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable);
......
...@@ -513,7 +513,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) ...@@ -513,7 +513,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
PERIODIC_SCAN_COMPLETE_EVENT_ID; PERIODIC_SCAN_COMPLETE_EVENT_ID;
if (wl->bss_type == BSS_TYPE_AP_BSS) if (wl->bss_type == BSS_TYPE_AP_BSS)
wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID; wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID |
INACTIVE_STA_EVENT_ID |
MAX_TX_RETRY_EVENT_ID;
else else
wl->event_mask |= DUMMY_PACKET_EVENT_ID | wl->event_mask |= DUMMY_PACKET_EVENT_ID |
BA_SESSION_RX_CONSTRAINT_EVENT_ID; BA_SESSION_RX_CONSTRAINT_EVENT_ID;
......
...@@ -400,10 +400,6 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type) ...@@ -400,10 +400,6 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET; join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
/* reset TX security counters */
wl->tx_security_last_seq = 0;
wl->tx_security_seq = 0;
wl1271_debug(DEBUG_CMD, "cmd join: basic_rate_set=0x%x, rate_set=0x%x", wl1271_debug(DEBUG_CMD, "cmd join: basic_rate_set=0x%x, rate_set=0x%x",
join->basic_rate_set, join->supported_rate_set); join->basic_rate_set, join->supported_rate_set);
...@@ -1084,7 +1080,7 @@ int wl1271_cmd_start_bss(struct wl1271 *wl) ...@@ -1084,7 +1080,7 @@ int wl1271_cmd_start_bss(struct wl1271 *wl)
memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN); memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN);
cmd->aging_period = cpu_to_le16(WL1271_AP_DEF_INACTIV_SEC); cmd->aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
cmd->bss_index = WL1271_AP_BSS_INDEX; cmd->bss_index = WL1271_AP_BSS_INDEX;
cmd->global_hlid = WL1271_AP_GLOBAL_HLID; cmd->global_hlid = WL1271_AP_GLOBAL_HLID;
cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID; cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID;
......
...@@ -713,8 +713,16 @@ struct conf_tx_settings { ...@@ -713,8 +713,16 @@ struct conf_tx_settings {
/* /*
* AP-mode - allow this number of TX retries to a station before an * AP-mode - allow this number of TX retries to a station before an
* event is triggered from FW. * event is triggered from FW.
* In AP-mode the hlids of unreachable stations are given in the
* "sta_tx_retry_exceeded" member in the event mailbox.
*/ */
u16 ap_max_tx_retries; u8 max_tx_retries;
/*
* AP-mode - after this number of seconds a connected station is
* considered inactive.
*/
u16 ap_aging_period;
/* /*
* Configuration for TID parameters. * Configuration for TID parameters.
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "acx.h" #include "acx.h"
#include "ps.h" #include "ps.h"
#include "io.h" #include "io.h"
#include "tx.h"
/* ms */ /* ms */
#define WL1271_DEBUGFS_STATS_LIFETIME 1000 #define WL1271_DEBUGFS_STATS_LIFETIME 1000
...@@ -233,7 +234,7 @@ static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, ...@@ -233,7 +234,7 @@ static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,
char buf[20]; char buf[20];
int res; int res;
queue_len = wl->tx_queue_count; queue_len = wl1271_tx_total_queue_count(wl);
res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); res = scnprintf(buf, sizeof(buf), "%u\n", queue_len);
return simple_read_from_buffer(userbuf, count, ppos, buf, res); return simple_read_from_buffer(userbuf, count, ppos, buf, res);
...@@ -338,10 +339,16 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, ...@@ -338,10 +339,16 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
#define DRIVER_STATE_PRINT_HEX(x) DRIVER_STATE_PRINT(x, "0x%x") #define DRIVER_STATE_PRINT_HEX(x) DRIVER_STATE_PRINT(x, "0x%x")
DRIVER_STATE_PRINT_INT(tx_blocks_available); DRIVER_STATE_PRINT_INT(tx_blocks_available);
DRIVER_STATE_PRINT_INT(tx_allocated_blocks); DRIVER_STATE_PRINT_INT(tx_allocated_blocks[0]);
DRIVER_STATE_PRINT_INT(tx_allocated_blocks[1]);
DRIVER_STATE_PRINT_INT(tx_allocated_blocks[2]);
DRIVER_STATE_PRINT_INT(tx_allocated_blocks[3]);
DRIVER_STATE_PRINT_INT(tx_frames_cnt); DRIVER_STATE_PRINT_INT(tx_frames_cnt);
DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]); DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]);
DRIVER_STATE_PRINT_INT(tx_queue_count); DRIVER_STATE_PRINT_INT(tx_queue_count[0]);
DRIVER_STATE_PRINT_INT(tx_queue_count[1]);
DRIVER_STATE_PRINT_INT(tx_queue_count[2]);
DRIVER_STATE_PRINT_INT(tx_queue_count[3]);
DRIVER_STATE_PRINT_INT(tx_packets_count); DRIVER_STATE_PRINT_INT(tx_packets_count);
DRIVER_STATE_PRINT_INT(tx_results_count); DRIVER_STATE_PRINT_INT(tx_results_count);
DRIVER_STATE_PRINT_LHEX(flags); DRIVER_STATE_PRINT_LHEX(flags);
...@@ -349,7 +356,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, ...@@ -349,7 +356,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
DRIVER_STATE_PRINT_INT(tx_blocks_freed[1]); DRIVER_STATE_PRINT_INT(tx_blocks_freed[1]);
DRIVER_STATE_PRINT_INT(tx_blocks_freed[2]); DRIVER_STATE_PRINT_INT(tx_blocks_freed[2]);
DRIVER_STATE_PRINT_INT(tx_blocks_freed[3]); DRIVER_STATE_PRINT_INT(tx_blocks_freed[3]);
DRIVER_STATE_PRINT_INT(tx_security_last_seq); DRIVER_STATE_PRINT_INT(tx_security_last_seq_lsb);
DRIVER_STATE_PRINT_INT(rx_counter); DRIVER_STATE_PRINT_INT(rx_counter);
DRIVER_STATE_PRINT_INT(session_counter); DRIVER_STATE_PRINT_INT(session_counter);
DRIVER_STATE_PRINT_INT(state); DRIVER_STATE_PRINT_INT(state);
......
...@@ -214,6 +214,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) ...@@ -214,6 +214,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
u32 vector; u32 vector;
bool beacon_loss = false; bool beacon_loss = false;
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
bool disconnect_sta = false;
unsigned long sta_bitmap = 0;
wl1271_event_mbox_dump(mbox); wl1271_event_mbox_dump(mbox);
...@@ -295,6 +297,46 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) ...@@ -295,6 +297,46 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
wl1271_tx_dummy_packet(wl); wl1271_tx_dummy_packet(wl);
} }
/*
* "TX retries exceeded" has a different meaning according to mode.
* In AP mode the offending station is disconnected.
*/
if ((vector & MAX_TX_RETRY_EVENT_ID) && is_ap) {
wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID");
sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded);
disconnect_sta = true;
}
if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) {
wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID");
sta_bitmap |= le16_to_cpu(mbox->sta_aging_status);
disconnect_sta = true;
}
if (is_ap && disconnect_sta) {
u32 num_packets = wl->conf.tx.max_tx_retries;
struct ieee80211_sta *sta;
const u8 *addr;
int h;
for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS);
h < AP_MAX_LINKS;
h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) {
if (!wl1271_is_active_sta(wl, h))
continue;
addr = wl->links[h].addr;
rcu_read_lock();
sta = ieee80211_find_sta(wl->vif, addr);
if (sta) {
wl1271_debug(DEBUG_EVENT, "remove sta %d", h);
ieee80211_report_low_ack(sta, num_packets);
}
rcu_read_unlock();
}
}
if (wl->vif && beacon_loss) if (wl->vif && beacon_loss)
ieee80211_connection_loss(wl->vif); ieee80211_connection_loss(wl->vif);
......
...@@ -58,13 +58,16 @@ enum { ...@@ -58,13 +58,16 @@ enum {
CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17),
BSS_LOSE_EVENT_ID = BIT(18), BSS_LOSE_EVENT_ID = BIT(18),
REGAINED_BSS_EVENT_ID = BIT(19), REGAINED_BSS_EVENT_ID = BIT(19),
ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20), MAX_TX_RETRY_EVENT_ID = BIT(20),
/* STA: dummy paket for dynamic mem blocks */ /* STA: dummy paket for dynamic mem blocks */
DUMMY_PACKET_EVENT_ID = BIT(21), DUMMY_PACKET_EVENT_ID = BIT(21),
/* AP: STA remove complete */ /* AP: STA remove complete */
STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), STA_REMOVE_COMPLETE_EVENT_ID = BIT(21),
SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), SOFT_GEMINI_SENSE_EVENT_ID = BIT(22),
/* STA: SG prediction */
SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23),
/* AP: Inactive STA */
INACTIVE_STA_EVENT_ID = BIT(23),
SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24),
PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25), PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25),
DBG_EVENT_ID = BIT(26), DBG_EVENT_ID = BIT(26),
...@@ -119,7 +122,11 @@ struct event_mailbox { ...@@ -119,7 +122,11 @@ struct event_mailbox {
/* AP FW only */ /* AP FW only */
u8 hlid_removed; u8 hlid_removed;
/* a bitmap of hlids for stations that have been inactive too long */
__le16 sta_aging_status; __le16 sta_aging_status;
/* a bitmap of hlids for stations which didn't respond to TX */
__le16 sta_tx_retry_exceeded; __le16 sta_tx_retry_exceeded;
/* /*
...@@ -143,4 +150,7 @@ void wl1271_event_mbox_config(struct wl1271 *wl); ...@@ -143,4 +150,7 @@ void wl1271_event_mbox_config(struct wl1271 *wl);
int wl1271_event_handle(struct wl1271 *wl, u8 mbox); int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
void wl1271_pspoll_work(struct work_struct *work); void wl1271_pspoll_work(struct work_struct *work);
/* Functions from main.c */
bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid);
#endif #endif
...@@ -447,7 +447,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl) ...@@ -447,7 +447,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = wl1271_acx_max_tx_retry(wl); ret = wl1271_acx_ap_max_tx_retry(wl);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -455,6 +455,11 @@ static int wl1271_ap_hw_init(struct wl1271 *wl) ...@@ -455,6 +455,11 @@ static int wl1271_ap_hw_init(struct wl1271 *wl)
if (ret < 0) if (ret < 0)
return ret; return ret;
/* initialize Tx power */
ret = wl1271_acx_tx_power(wl, wl->power_level);
if (ret < 0)
return ret;
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -193,24 +193,27 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, ...@@ -193,24 +193,27 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid) static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)
{ {
int i, filtered = 0; int i;
struct sk_buff *skb; struct sk_buff *skb;
struct ieee80211_tx_info *info; struct ieee80211_tx_info *info;
unsigned long flags; unsigned long flags;
int filtered[NUM_TX_QUEUES];
/* filter all frames currently the low level queus for this hlid */ /* filter all frames currently the low level queus for this hlid */
for (i = 0; i < NUM_TX_QUEUES; i++) { for (i = 0; i < NUM_TX_QUEUES; i++) {
filtered[i] = 0;
while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
info = IEEE80211_SKB_CB(skb); info = IEEE80211_SKB_CB(skb);
info->flags |= IEEE80211_TX_STAT_TX_FILTERED; info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
info->status.rates[0].idx = -1; info->status.rates[0].idx = -1;
ieee80211_tx_status_ni(wl->hw, skb); ieee80211_tx_status_ni(wl->hw, skb);
filtered++; filtered[i]++;
} }
} }
spin_lock_irqsave(&wl->wl_lock, flags); spin_lock_irqsave(&wl->wl_lock, flags);
wl->tx_queue_count -= filtered; for (i = 0; i < NUM_TX_QUEUES; i++)
wl->tx_queue_count[i] -= filtered[i];
spin_unlock_irqrestore(&wl->wl_lock, flags); spin_unlock_irqrestore(&wl->wl_lock, flags);
wl1271_handle_tx_low_watermark(wl); wl1271_handle_tx_low_watermark(wl);
......
...@@ -321,6 +321,33 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, ...@@ -321,6 +321,33 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
return 0; return 0;
} }
int wl1271_scan_stop(struct wl1271 *wl)
{
struct wl1271_cmd_header *cmd = NULL;
int ret = 0;
if (WARN_ON(wl->scan.state == WL1271_SCAN_STATE_IDLE))
return -EINVAL;
wl1271_debug(DEBUG_CMD, "cmd scan stop");
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, cmd,
sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("cmd stop_scan failed");
goto out;
}
out:
kfree(cmd);
return ret;
}
static int static int
wl1271_scan_get_sched_scan_channels(struct wl1271 *wl, wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
struct cfg80211_sched_scan_request *req, struct cfg80211_sched_scan_request *req,
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
struct cfg80211_scan_request *req); struct cfg80211_scan_request *req);
int wl1271_scan_stop(struct wl1271 *wl);
int wl1271_scan_build_probe_req(struct wl1271 *wl, int wl1271_scan_build_probe_req(struct wl1271 *wl,
const u8 *ssid, size_t ssid_len, const u8 *ssid, size_t ssid_len,
const u8 *ie, size_t ie_len, u8 band); const u8 *ie, size_t ie_len, u8 band);
......
...@@ -166,12 +166,12 @@ static int wl1271_sdio_power_on(struct wl1271 *wl) ...@@ -166,12 +166,12 @@ static int wl1271_sdio_power_on(struct wl1271 *wl)
ret = pm_runtime_get_sync(&func->dev); ret = pm_runtime_get_sync(&func->dev);
if (ret) if (ret)
goto out; goto out;
} } else {
/* Runtime PM is disabled: power up the card manually */
/* Runtime PM might be disabled, so power up the card manually */
ret = mmc_power_restore_host(func->card->host); ret = mmc_power_restore_host(func->card->host);
if (ret < 0) if (ret < 0)
goto out; goto out;
}
sdio_claim_host(func); sdio_claim_host(func);
sdio_enable_func(func); sdio_enable_func(func);
...@@ -188,7 +188,7 @@ static int wl1271_sdio_power_off(struct wl1271 *wl) ...@@ -188,7 +188,7 @@ static int wl1271_sdio_power_off(struct wl1271 *wl)
sdio_disable_func(func); sdio_disable_func(func);
sdio_release_host(func); sdio_release_host(func);
/* Runtime PM might be disabled, so power off the card manually */ /* Power off the card manually, even if runtime PM is enabled. */
ret = mmc_power_save_host(func->card->host); ret = mmc_power_save_host(func->card->host);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -168,7 +168,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, ...@@ -168,7 +168,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
u32 len; u32 len;
u32 total_blocks; u32 total_blocks;
int id, ret = -EBUSY; int id, ret = -EBUSY, ac;
u32 spare_blocks; u32 spare_blocks;
if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS)) if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS))
...@@ -206,7 +206,9 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, ...@@ -206,7 +206,9 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
desc->id = id; desc->id = id;
wl->tx_blocks_available -= total_blocks; wl->tx_blocks_available -= total_blocks;
wl->tx_allocated_blocks += total_blocks;
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
wl->tx_allocated_blocks[ac] += total_blocks;
if (wl->bss_type == BSS_TYPE_AP_BSS) if (wl->bss_type == BSS_TYPE_AP_BSS)
wl->links[hlid].allocated_blks += total_blocks; wl->links[hlid].allocated_blks += total_blocks;
...@@ -383,6 +385,8 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, ...@@ -383,6 +385,8 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
if (ret < 0) if (ret < 0)
return ret; return ret;
wl1271_tx_fill_hdr(wl, skb, extra, info, hlid);
if (wl->bss_type == BSS_TYPE_AP_BSS) { if (wl->bss_type == BSS_TYPE_AP_BSS) {
wl1271_tx_ap_update_inconnection_sta(wl, skb); wl1271_tx_ap_update_inconnection_sta(wl, skb);
wl1271_tx_regulate_link(wl, hlid); wl1271_tx_regulate_link(wl, hlid);
...@@ -390,8 +394,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, ...@@ -390,8 +394,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
wl1271_tx_update_filters(wl, skb); wl1271_tx_update_filters(wl, skb);
} }
wl1271_tx_fill_hdr(wl, skb, extra, info, hlid);
/* /*
* The length of each packet is stored in terms of * The length of each packet is stored in terms of
* words. Thus, we must pad the skb data to make sure its * words. Thus, we must pad the skb data to make sure its
...@@ -442,37 +444,62 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) ...@@ -442,37 +444,62 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
void wl1271_handle_tx_low_watermark(struct wl1271 *wl) void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
{ {
unsigned long flags; unsigned long flags;
int i;
if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) && for (i = 0; i < NUM_TX_QUEUES; i++) {
wl->tx_queue_count <= WL1271_TX_QUEUE_LOW_WATERMARK) { if (test_bit(i, &wl->stopped_queues_map) &&
wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) {
/* firmware buffer has space, restart queues */ /* firmware buffer has space, restart queues */
spin_lock_irqsave(&wl->wl_lock, flags); spin_lock_irqsave(&wl->wl_lock, flags);
ieee80211_wake_queues(wl->hw); ieee80211_wake_queue(wl->hw,
clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); wl1271_tx_get_mac80211_queue(i));
clear_bit(i, &wl->stopped_queues_map);
spin_unlock_irqrestore(&wl->wl_lock, flags); spin_unlock_irqrestore(&wl->wl_lock, flags);
} }
}
}
static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl,
struct sk_buff_head *queues)
{
int i, q = -1;
u32 min_blks = 0xffffffff;
/*
* Find a non-empty ac where:
* 1. There are packets to transmit
* 2. The FW has the least allocated blocks
*/
for (i = 0; i < NUM_TX_QUEUES; i++)
if (!skb_queue_empty(&queues[i]) &&
(wl->tx_allocated_blocks[i] < min_blks)) {
q = i;
min_blks = wl->tx_allocated_blocks[q];
}
if (q == -1)
return NULL;
return &queues[q];
} }
static struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl) static struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl)
{ {
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
unsigned long flags; unsigned long flags;
struct sk_buff_head *queue;
skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VO]); queue = wl1271_select_queue(wl, wl->tx_queue);
if (skb) if (!queue)
goto out;
skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VI]);
if (skb)
goto out; goto out;
skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BE]);
if (skb) skb = skb_dequeue(queue);
goto out;
skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BK]);
out: out:
if (skb) { if (skb) {
int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
spin_lock_irqsave(&wl->wl_lock, flags); spin_lock_irqsave(&wl->wl_lock, flags);
wl->tx_queue_count--; wl->tx_queue_count[q]--;
spin_unlock_irqrestore(&wl->wl_lock, flags); spin_unlock_irqrestore(&wl->wl_lock, flags);
} }
...@@ -484,6 +511,7 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl) ...@@ -484,6 +511,7 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl)
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
unsigned long flags; unsigned long flags;
int i, h, start_hlid; int i, h, start_hlid;
struct sk_buff_head *queue;
/* start from the link after the last one */ /* start from the link after the last one */
start_hlid = (wl->last_tx_hlid + 1) % AP_MAX_LINKS; start_hlid = (wl->last_tx_hlid + 1) % AP_MAX_LINKS;
...@@ -492,25 +520,25 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl) ...@@ -492,25 +520,25 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl)
for (i = 0; i < AP_MAX_LINKS; i++) { for (i = 0; i < AP_MAX_LINKS; i++) {
h = (start_hlid + i) % AP_MAX_LINKS; h = (start_hlid + i) % AP_MAX_LINKS;
skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VO]); /* only consider connected stations */
if (skb) if (h >= WL1271_AP_STA_HLID_START &&
goto out; !test_bit(h - WL1271_AP_STA_HLID_START, wl->ap_hlid_map))
skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VI]); continue;
if (skb)
goto out; queue = wl1271_select_queue(wl, wl->links[h].tx_queue);
skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BE]); if (!queue)
if (skb) continue;
goto out;
skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BK]); skb = skb_dequeue(queue);
if (skb) if (skb)
goto out; break;
} }
out:
if (skb) { if (skb) {
int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
wl->last_tx_hlid = h; wl->last_tx_hlid = h;
spin_lock_irqsave(&wl->wl_lock, flags); spin_lock_irqsave(&wl->wl_lock, flags);
wl->tx_queue_count--; wl->tx_queue_count[q]--;
spin_unlock_irqrestore(&wl->wl_lock, flags); spin_unlock_irqrestore(&wl->wl_lock, flags);
} else { } else {
wl->last_tx_hlid = 0; wl->last_tx_hlid = 0;
...@@ -531,9 +559,12 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) ...@@ -531,9 +559,12 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
if (!skb && if (!skb &&
test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
int q;
skb = wl->dummy_packet; skb = wl->dummy_packet;
q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
spin_lock_irqsave(&wl->wl_lock, flags); spin_lock_irqsave(&wl->wl_lock, flags);
wl->tx_queue_count--; wl->tx_queue_count[q]--;
spin_unlock_irqrestore(&wl->wl_lock, flags); spin_unlock_irqrestore(&wl->wl_lock, flags);
} }
...@@ -558,7 +589,7 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) ...@@ -558,7 +589,7 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
} }
spin_lock_irqsave(&wl->wl_lock, flags); spin_lock_irqsave(&wl->wl_lock, flags);
wl->tx_queue_count++; wl->tx_queue_count[q]++;
spin_unlock_irqrestore(&wl->wl_lock, flags); spin_unlock_irqrestore(&wl->wl_lock, flags);
} }
...@@ -704,10 +735,24 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, ...@@ -704,10 +735,24 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
wl->stats.retry_count += result->ack_failures; wl->stats.retry_count += result->ack_failures;
/* update security sequence number */ /*
wl->tx_security_seq += (result->lsb_security_sequence_number - * update sequence number only when relevant, i.e. only in
wl->tx_security_last_seq); * sessions of TKIP, AES and GEM (not in open or WEP sessions)
wl->tx_security_last_seq = result->lsb_security_sequence_number; */
if (info->control.hw_key &&
(info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP ||
info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP ||
info->control.hw_key->cipher == WL1271_CIPHER_SUITE_GEM)) {
u8 fw_lsb = result->tx_security_sequence_number_lsb;
u8 cur_lsb = wl->tx_security_last_seq_lsb;
/*
* update security sequence number, taking care of potential
* wrap-around
*/
wl->tx_security_seq += (fw_lsb - cur_lsb + 256) % 256;
wl->tx_security_last_seq_lsb = fw_lsb;
}
/* remove private header from packet */ /* remove private header from packet */
skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
...@@ -772,23 +817,26 @@ void wl1271_tx_complete(struct wl1271 *wl) ...@@ -772,23 +817,26 @@ void wl1271_tx_complete(struct wl1271 *wl)
void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
{ {
struct sk_buff *skb; struct sk_buff *skb;
int i, total = 0; int i;
unsigned long flags; unsigned long flags;
struct ieee80211_tx_info *info; struct ieee80211_tx_info *info;
int total[NUM_TX_QUEUES];
for (i = 0; i < NUM_TX_QUEUES; i++) { for (i = 0; i < NUM_TX_QUEUES; i++) {
total[i] = 0;
while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb); wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb);
info = IEEE80211_SKB_CB(skb); info = IEEE80211_SKB_CB(skb);
info->status.rates[0].idx = -1; info->status.rates[0].idx = -1;
info->status.rates[0].count = 0; info->status.rates[0].count = 0;
ieee80211_tx_status_ni(wl->hw, skb); ieee80211_tx_status_ni(wl->hw, skb);
total++; total[i]++;
} }
} }
spin_lock_irqsave(&wl->wl_lock, flags); spin_lock_irqsave(&wl->wl_lock, flags);
wl->tx_queue_count -= total; for (i = 0; i < NUM_TX_QUEUES; i++)
wl->tx_queue_count[i] -= total[i];
spin_unlock_irqrestore(&wl->wl_lock, flags); spin_unlock_irqrestore(&wl->wl_lock, flags);
wl1271_handle_tx_low_watermark(wl); wl1271_handle_tx_low_watermark(wl);
...@@ -823,10 +871,11 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues) ...@@ -823,10 +871,11 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
ieee80211_tx_status_ni(wl->hw, skb); ieee80211_tx_status_ni(wl->hw, skb);
} }
} }
wl->tx_queue_count[i] = 0;
} }
} }
wl->tx_queue_count = 0; wl->stopped_queues_map = 0;
/* /*
* Make sure the driver is at a consistent state, in case this * Make sure the driver is at a consistent state, in case this
...@@ -879,8 +928,10 @@ void wl1271_tx_flush(struct wl1271 *wl) ...@@ -879,8 +928,10 @@ void wl1271_tx_flush(struct wl1271 *wl)
while (!time_after(jiffies, timeout)) { while (!time_after(jiffies, timeout)) {
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d", wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d",
wl->tx_frames_cnt, wl->tx_queue_count); wl->tx_frames_cnt,
if ((wl->tx_frames_cnt == 0) && (wl->tx_queue_count == 0)) { wl1271_tx_total_queue_count(wl));
if ((wl->tx_frames_cnt == 0) &&
(wl1271_tx_total_queue_count(wl) == 0)) {
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
return; return;
} }
......
...@@ -150,7 +150,7 @@ struct wl1271_tx_hw_res_descr { ...@@ -150,7 +150,7 @@ struct wl1271_tx_hw_res_descr {
(from 1st EDCA AIFS counter until TX Complete). */ (from 1st EDCA AIFS counter until TX Complete). */
__le32 medium_delay; __le32 medium_delay;
/* LS-byte of last TKIP seq-num (saved per AC for recovery). */ /* LS-byte of last TKIP seq-num (saved per AC for recovery). */
u8 lsb_security_sequence_number; u8 tx_security_sequence_number_lsb;
/* Retry count - number of transmissions without successful ACK.*/ /* Retry count - number of transmissions without successful ACK.*/
u8 ack_failures; u8 ack_failures;
/* The rate that succeeded getting ACK /* The rate that succeeded getting ACK
...@@ -182,6 +182,32 @@ static inline int wl1271_tx_get_queue(int queue) ...@@ -182,6 +182,32 @@ static inline int wl1271_tx_get_queue(int queue)
} }
} }
static inline int wl1271_tx_get_mac80211_queue(int queue)
{
switch (queue) {
case CONF_TX_AC_VO:
return 0;
case CONF_TX_AC_VI:
return 1;
case CONF_TX_AC_BE:
return 2;
case CONF_TX_AC_BK:
return 3;
default:
return 2;
}
}
static inline int wl1271_tx_total_queue_count(struct wl1271 *wl)
{
int i, count = 0;
for (i = 0; i < NUM_TX_QUEUES; i++)
count += wl->tx_queue_count[i];
return count;
}
void wl1271_tx_work(struct work_struct *work); void wl1271_tx_work(struct work_struct *work);
void wl1271_tx_work_locked(struct wl1271 *wl); void wl1271_tx_work_locked(struct wl1271 *wl);
void wl1271_tx_complete(struct wl1271 *wl); void wl1271_tx_complete(struct wl1271 *wl);
......
...@@ -144,6 +144,7 @@ extern u32 wl12xx_debug_level; ...@@ -144,6 +144,7 @@ extern u32 wl12xx_debug_level;
#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff)) #define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
#define WL1271_TX_SQN_POST_RECOVERY_PADDING 0xff
#define WL1271_CIPHER_SUITE_GEM 0x00147201 #define WL1271_CIPHER_SUITE_GEM 0x00147201
...@@ -172,7 +173,6 @@ extern u32 wl12xx_debug_level; ...@@ -172,7 +173,6 @@ extern u32 wl12xx_debug_level;
#define WL1271_PS_STA_MAX_BLOCKS (2 * 9) #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_BEACON_EXP 20 #define WL1271_AP_DEF_BEACON_EXP 20
#define ACX_TX_DESCRIPTORS 32 #define ACX_TX_DESCRIPTORS 32
...@@ -424,7 +424,7 @@ struct wl1271 { ...@@ -424,7 +424,7 @@ struct wl1271 {
/* Accounting for allocated / available TX blocks on HW */ /* Accounting for allocated / available TX blocks on HW */
u32 tx_blocks_freed[NUM_TX_QUEUES]; u32 tx_blocks_freed[NUM_TX_QUEUES];
u32 tx_blocks_available; u32 tx_blocks_available;
u32 tx_allocated_blocks; u32 tx_allocated_blocks[NUM_TX_QUEUES];
u32 tx_results_count; u32 tx_results_count;
/* Transmitted TX packets counter for chipset interface */ /* Transmitted TX packets counter for chipset interface */
...@@ -438,7 +438,8 @@ struct wl1271 { ...@@ -438,7 +438,8 @@ struct wl1271 {
/* Frames scheduled for transmission, not handled yet */ /* Frames scheduled for transmission, not handled yet */
struct sk_buff_head tx_queue[NUM_TX_QUEUES]; struct sk_buff_head tx_queue[NUM_TX_QUEUES];
int tx_queue_count; int tx_queue_count[NUM_TX_QUEUES];
long stopped_queues_map;
/* Frames received, not handled yet by mac80211 */ /* Frames received, not handled yet by mac80211 */
struct sk_buff_head deferred_rx_queue; struct sk_buff_head deferred_rx_queue;
...@@ -454,9 +455,16 @@ struct wl1271 { ...@@ -454,9 +455,16 @@ struct wl1271 {
struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS]; struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS];
int tx_frames_cnt; int tx_frames_cnt;
/* Security sequence number counters */ /*
u8 tx_security_last_seq; * Security sequence number
s64 tx_security_seq; * bits 0-15: lower 16 bits part of sequence number
* bits 16-47: higher 32 bits part of sequence number
* bits 48-63: not in use
*/
u64 tx_security_seq;
/* 8 bits of the last sequence number in use */
u8 tx_security_last_seq_lsb;
/* FW Rx counter */ /* FW Rx counter */
u32 rx_counter; u32 rx_counter;
...@@ -632,8 +640,8 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen); ...@@ -632,8 +640,8 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
#define WL1271_DEFAULT_POWER_LEVEL 0 #define WL1271_DEFAULT_POWER_LEVEL 0
#define WL1271_TX_QUEUE_LOW_WATERMARK 10 #define WL1271_TX_QUEUE_LOW_WATERMARK 32
#define WL1271_TX_QUEUE_HIGH_WATERMARK 25 #define WL1271_TX_QUEUE_HIGH_WATERMARK 256
#define WL1271_DEFERRED_QUEUE_LIMIT 64 #define WL1271_DEFERRED_QUEUE_LIMIT 64
......
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