Commit a373c3ce authored by Luciano Coelho's avatar Luciano Coelho

Merge branch 'wl12xx-next' into for-linville

parents 0d4e6717 97236a06
...@@ -186,8 +186,10 @@ static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable) ...@@ -186,8 +186,10 @@ static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable)
wl->set_power(true); wl->set_power(true);
ret = pm_runtime_get_sync(&func->dev); ret = pm_runtime_get_sync(&func->dev);
if (ret < 0) if (ret < 0) {
pm_runtime_put_sync(&func->dev);
goto out; goto out;
}
sdio_claim_host(func); sdio_claim_host(func);
sdio_enable_func(func); sdio_enable_func(func);
......
...@@ -723,6 +723,7 @@ static int wl12xx_identify_chip(struct wl1271 *wl) ...@@ -723,6 +723,7 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
wl->sched_scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4; wl->sched_scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4;
wl->sched_scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5; wl->sched_scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5;
wl->max_channels_5 = WL12XX_MAX_CHANNELS_5GHZ; wl->max_channels_5 = WL12XX_MAX_CHANNELS_5GHZ;
wl->ba_rx_session_count_max = WL12XX_RX_BA_MAX_SESSIONS;
out: out:
return ret; return ret;
} }
......
...@@ -63,6 +63,8 @@ ...@@ -63,6 +63,8 @@
#define WL12XX_NUM_MAC_ADDRESSES 2 #define WL12XX_NUM_MAC_ADDRESSES 2
#define WL12XX_RX_BA_MAX_SESSIONS 3
struct wl127x_rx_mem_pool_addr { struct wl127x_rx_mem_pool_addr {
u32 addr; u32 addr;
u32 addr_extra; u32 addr_extra;
......
...@@ -678,6 +678,7 @@ static int wl18xx_identify_chip(struct wl1271 *wl) ...@@ -678,6 +678,7 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
wl->sched_scan_templ_id_2_4 = CMD_TEMPL_PROBE_REQ_2_4_PERIODIC; wl->sched_scan_templ_id_2_4 = CMD_TEMPL_PROBE_REQ_2_4_PERIODIC;
wl->sched_scan_templ_id_5 = CMD_TEMPL_PROBE_REQ_5_PERIODIC; wl->sched_scan_templ_id_5 = CMD_TEMPL_PROBE_REQ_5_PERIODIC;
wl->max_channels_5 = WL18XX_MAX_CHANNELS_5GHZ; wl->max_channels_5 = WL18XX_MAX_CHANNELS_5GHZ;
wl->ba_rx_session_count_max = WL18XX_RX_BA_MAX_SESSIONS;
out: out:
return ret; return ret;
} }
...@@ -1144,6 +1145,7 @@ static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl, ...@@ -1144,6 +1145,7 @@ static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl,
static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver) static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
{ {
u32 fuse; u32 fuse;
s8 rom = 0, metal = 0, pg_ver = 0, rdl_ver = 0;
int ret; int ret;
ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]); ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
...@@ -1154,8 +1156,29 @@ static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver) ...@@ -1154,8 +1156,29 @@ static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
if (ret < 0) if (ret < 0)
goto out; goto out;
pg_ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET;
rom = (fuse & WL18XX_ROM_VER_MASK) >> WL18XX_ROM_VER_OFFSET;
if (rom <= 0xE)
metal = (fuse & WL18XX_METAL_VER_MASK) >>
WL18XX_METAL_VER_OFFSET;
else
metal = (fuse & WL18XX_NEW_METAL_VER_MASK) >>
WL18XX_NEW_METAL_VER_OFFSET;
ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_2_3, &fuse);
if (ret < 0)
goto out;
rdl_ver = (fuse & WL18XX_RDL_VER_MASK) >> WL18XX_RDL_VER_OFFSET;
if (rdl_ver > RDL_MAX)
rdl_ver = RDL_NONE;
wl1271_info("wl18xx HW: RDL %d, %s, PG %x.%x (ROM %x)",
rdl_ver, rdl_names[rdl_ver], pg_ver, metal, rom);
if (ver) if (ver)
*ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET; *ver = pg_ver;
ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
......
...@@ -131,6 +131,16 @@ ...@@ -131,6 +131,16 @@
#define WL18XX_REG_FUSE_DATA_1_3 0xA0260C #define WL18XX_REG_FUSE_DATA_1_3 0xA0260C
#define WL18XX_PG_VER_MASK 0x70 #define WL18XX_PG_VER_MASK 0x70
#define WL18XX_PG_VER_OFFSET 4 #define WL18XX_PG_VER_OFFSET 4
#define WL18XX_ROM_VER_MASK 0x3
#define WL18XX_ROM_VER_OFFSET 0
#define WL18XX_METAL_VER_MASK 0xC
#define WL18XX_METAL_VER_OFFSET 2
#define WL18XX_NEW_METAL_VER_MASK 0x180
#define WL18XX_NEW_METAL_VER_OFFSET 7
#define WL18XX_REG_FUSE_DATA_2_3 0xA02614
#define WL18XX_RDL_VER_MASK 0x1f00
#define WL18XX_RDL_VER_OFFSET 8
#define WL18XX_REG_FUSE_BD_ADDR_1 0xA02602 #define WL18XX_REG_FUSE_BD_ADDR_1 0xA02602
#define WL18XX_REG_FUSE_BD_ADDR_2 0xA02606 #define WL18XX_REG_FUSE_BD_ADDR_2 0xA02606
...@@ -188,4 +198,23 @@ enum { ...@@ -188,4 +198,23 @@ enum {
NUM_BOARD_TYPES, NUM_BOARD_TYPES,
}; };
enum {
RDL_NONE = 0,
RDL_1_HP = 1,
RDL_2_SP = 2,
RDL_3_HP = 3,
RDL_4_SP = 4,
_RDL_LAST,
RDL_MAX = _RDL_LAST - 1,
};
static const char * const rdl_names[] = {
[RDL_NONE] = "",
[RDL_1_HP] = "1853 SISO",
[RDL_2_SP] = "1857 MIMO",
[RDL_3_HP] = "1893 SISO",
[RDL_4_SP] = "1897 MIMO",
};
#endif /* __REG_H__ */ #endif /* __REG_H__ */
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#define WL18XX_IFTYPE_VER 5 #define WL18XX_IFTYPE_VER 5
#define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE #define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE
#define WL18XX_SUBTYPE_VER WLCORE_FW_VER_IGNORE #define WL18XX_SUBTYPE_VER WLCORE_FW_VER_IGNORE
#define WL18XX_MINOR_VER 28 #define WL18XX_MINOR_VER 39
#define WL18XX_CMD_MAX_SIZE 740 #define WL18XX_CMD_MAX_SIZE 740
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
#define WL18XX_NUM_MAC_ADDRESSES 3 #define WL18XX_NUM_MAC_ADDRESSES 3
#define WL18XX_RX_BA_MAX_SESSIONS 5
struct wl18xx_priv { struct wl18xx_priv {
/* buffer for sending commands to FW */ /* buffer for sending commands to FW */
u8 cmd_buf[WL18XX_CMD_MAX_SIZE]; u8 cmd_buf[WL18XX_CMD_MAX_SIZE];
......
...@@ -1736,6 +1736,35 @@ int wl12xx_acx_config_hangover(struct wl1271 *wl) ...@@ -1736,6 +1736,35 @@ int wl12xx_acx_config_hangover(struct wl1271 *wl)
} }
int wlcore_acx_average_rssi(struct wl1271 *wl, struct wl12xx_vif *wlvif,
s8 *avg_rssi)
{
struct acx_roaming_stats *acx;
int ret = 0;
wl1271_debug(DEBUG_ACX, "acx roaming statistics");
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}
acx->role_id = wlvif->role_id;
ret = wl1271_cmd_interrogate(wl, ACX_ROAMING_STATISTICS_TBL,
acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx roaming statistics failed: %d", ret);
ret = -ENOMEM;
goto out;
}
*avg_rssi = acx->rssi_beacon;
out:
kfree(acx);
return ret;
}
#ifdef CONFIG_PM #ifdef CONFIG_PM
/* Set the global behaviour of RX filters - On/Off + default action */ /* Set the global behaviour of RX filters - On/Off + default action */
int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable, int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable,
......
...@@ -728,8 +728,6 @@ struct wl1271_acx_ht_information { ...@@ -728,8 +728,6 @@ struct wl1271_acx_ht_information {
u8 padding[2]; u8 padding[2];
} __packed; } __packed;
#define RX_BA_MAX_SESSIONS 3
struct wl1271_acx_ba_initiator_policy { struct wl1271_acx_ba_initiator_policy {
struct acx_header header; struct acx_header header;
...@@ -955,6 +953,18 @@ struct acx_rx_filter_cfg { ...@@ -955,6 +953,18 @@ struct acx_rx_filter_cfg {
u8 fields[0]; u8 fields[0];
} __packed; } __packed;
struct acx_roaming_stats {
struct acx_header header;
u8 role_id;
u8 pad[3];
u32 missed_beacons;
u8 snr_data;
u8 snr_bacon;
s8 rssi_data;
s8 rssi_beacon;
} __packed;
enum { enum {
ACX_WAKE_UP_CONDITIONS = 0x0000, ACX_WAKE_UP_CONDITIONS = 0x0000,
ACX_MEM_CFG = 0x0001, ACX_MEM_CFG = 0x0001,
...@@ -1112,6 +1122,8 @@ int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); ...@@ -1112,6 +1122,8 @@ int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
int wl1271_acx_fm_coex(struct wl1271 *wl); int wl1271_acx_fm_coex(struct wl1271 *wl);
int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl); int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl);
int wl12xx_acx_config_hangover(struct wl1271 *wl); int wl12xx_acx_config_hangover(struct wl1271 *wl);
int wlcore_acx_average_rssi(struct wl1271 *wl, struct wl12xx_vif *wlvif,
s8 *avg_rssi);
#ifdef CONFIG_PM #ifdef CONFIG_PM
int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable, int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable,
......
...@@ -327,6 +327,14 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) ...@@ -327,6 +327,14 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
wl->links[link].prev_freed_pkts = wl->links[link].prev_freed_pkts =
wl->fw_status_2->counters.tx_lnk_free_pkts[link]; wl->fw_status_2->counters.tx_lnk_free_pkts[link];
wl->links[link].wlvif = wlvif; wl->links[link].wlvif = wlvif;
/*
* Take saved value for total freed packets from wlvif, in case this is
* recovery/resume
*/
if (wlvif->bss_type != BSS_TYPE_AP_BSS)
wl->links[link].total_freed_pkts = wlvif->total_freed_pkts;
*hlid = link; *hlid = link;
wl->active_link_count++; wl->active_link_count++;
...@@ -358,6 +366,26 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) ...@@ -358,6 +366,26 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
wl1271_tx_reset_link_queues(wl, *hlid); wl1271_tx_reset_link_queues(wl, *hlid);
wl->links[*hlid].wlvif = NULL; wl->links[*hlid].wlvif = NULL;
if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
(wlvif->bss_type == BSS_TYPE_AP_BSS &&
*hlid == wlvif->ap.bcast_hlid)) {
/*
* save the total freed packets in the wlvif, in case this is
* recovery or suspend
*/
wlvif->total_freed_pkts = wl->links[*hlid].total_freed_pkts;
/*
* increment the initial seq number on recovery to account for
* transmitted packets that we haven't yet got in the FW status
*/
if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
wlvif->total_freed_pkts +=
WL1271_TX_SQN_POST_RECOVERY_PADDING;
}
wl->links[*hlid].total_freed_pkts = 0;
*hlid = WL12XX_INVALID_LINK_ID; *hlid = WL12XX_INVALID_LINK_ID;
wl->active_link_count--; wl->active_link_count--;
WARN_ON_ONCE(wl->active_link_count < 0); WARN_ON_ONCE(wl->active_link_count < 0);
...@@ -609,6 +637,10 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) ...@@ -609,6 +637,10 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
if (ret < 0) if (ret < 0)
goto out_free_global; goto out_free_global;
/* use the previous security seq, if this is a recovery/resume */
wl->links[wlvif->ap.bcast_hlid].total_freed_pkts =
wlvif->total_freed_pkts;
cmd->role_id = wlvif->role_id; cmd->role_id = wlvif->role_id;
cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
cmd->ap.bss_index = WL1271_AP_BSS_INDEX; cmd->ap.bss_index = WL1271_AP_BSS_INDEX;
......
...@@ -89,25 +89,24 @@ extern u32 wl12xx_debug_level; ...@@ -89,25 +89,24 @@ extern u32 wl12xx_debug_level;
} while (0) } while (0)
#endif #endif
/* TODO: use pr_debug_hex_dump when it becomes available */ #define wl1271_dump(level, prefix, buf, len) \
#define wl1271_dump(level, prefix, buf, len) \ do { \
do { \ if (level & wl12xx_debug_level) \
if (level & wl12xx_debug_level) \ print_hex_dump_debug(DRIVER_PREFIX prefix, \
print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ DUMP_PREFIX_OFFSET, 16, 1, \
DUMP_PREFIX_OFFSET, 16, 1, \ buf, \
buf, \ min_t(size_t, len, DEBUG_DUMP_LIMIT), \
min_t(size_t, len, DEBUG_DUMP_LIMIT), \ 0); \
0); \
} while (0) } while (0)
#define wl1271_dump_ascii(level, prefix, buf, len) \ #define wl1271_dump_ascii(level, prefix, buf, len) \
do { \ do { \
if (level & wl12xx_debug_level) \ if (level & wl12xx_debug_level) \
print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ print_hex_dump_debug(DRIVER_PREFIX prefix, \
DUMP_PREFIX_OFFSET, 16, 1, \ DUMP_PREFIX_OFFSET, 16, 1, \
buf, \ buf, \
min_t(size_t, len, DEBUG_DUMP_LIMIT), \ min_t(size_t, len, DEBUG_DUMP_LIMIT), \
true); \ true); \
} while (0) } while (0)
#endif /* __DEBUG_H__ */ #endif /* __DEBUG_H__ */
...@@ -598,8 +598,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf, ...@@ -598,8 +598,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
VIF_STATE_PRINT_INT(last_rssi_event); VIF_STATE_PRINT_INT(last_rssi_event);
VIF_STATE_PRINT_INT(ba_support); VIF_STATE_PRINT_INT(ba_support);
VIF_STATE_PRINT_INT(ba_allowed); VIF_STATE_PRINT_INT(ba_allowed);
VIF_STATE_PRINT_LLHEX(tx_security_seq); VIF_STATE_PRINT_LLHEX(total_freed_pkts);
VIF_STATE_PRINT_INT(tx_security_last_seq_lsb);
} }
#undef VIF_STATE_PRINT_INT #undef VIF_STATE_PRINT_INT
......
...@@ -237,6 +237,14 @@ void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap) ...@@ -237,6 +237,14 @@ void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap)
!test_bit(wlvif->role_id , &roles_bitmap)) !test_bit(wlvif->role_id , &roles_bitmap))
continue; continue;
vif = wl12xx_wlvif_to_vif(wlvif);
/* don't attempt roaming in case of p2p */
if (wlvif->p2p) {
ieee80211_connection_loss(vif);
continue;
}
/* /*
* if the work is already queued, it should take place. * if the work is already queued, it should take place.
* We don't want to delay the connection loss * We don't want to delay the connection loss
...@@ -246,7 +254,6 @@ void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap) ...@@ -246,7 +254,6 @@ void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap)
&wlvif->connection_loss_work, &wlvif->connection_loss_work,
msecs_to_jiffies(delay)); msecs_to_jiffies(delay));
vif = wl12xx_wlvif_to_vif(wlvif);
ieee80211_cqm_rssi_notify( ieee80211_cqm_rssi_notify(
vif, vif,
NL80211_CQM_RSSI_BEACON_LOSS_EVENT, NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
......
This diff is collapsed.
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#define WL1271_WAKEUP_TIMEOUT 500 #define WL1271_WAKEUP_TIMEOUT 500
#define ELP_ENTRY_DELAY 30 #define ELP_ENTRY_DELAY 30
#define ELP_ENTRY_DELAY_FORCE_PS 5
void wl1271_elp_work(struct work_struct *work) void wl1271_elp_work(struct work_struct *work)
{ {
...@@ -98,7 +99,8 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) ...@@ -98,7 +99,8 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
return; return;
} }
timeout = ELP_ENTRY_DELAY; timeout = wl->conf.conn.forced_ps ?
ELP_ENTRY_DELAY_FORCE_PS : ELP_ENTRY_DELAY;
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
msecs_to_jiffies(timeout)); msecs_to_jiffies(timeout));
} }
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/spinlock.h>
#include "wlcore.h" #include "wlcore.h"
#include "debug.h" #include "debug.h"
...@@ -104,7 +105,7 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, ...@@ -104,7 +105,7 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl,
struct wl12xx_vif *wlvif, struct wl12xx_vif *wlvif,
u8 hlid) u8 hlid)
{ {
bool fw_ps, single_link; bool fw_ps;
u8 tx_pkts; u8 tx_pkts;
if (WARN_ON(!test_bit(hlid, wlvif->links_map))) if (WARN_ON(!test_bit(hlid, wlvif->links_map)))
...@@ -112,15 +113,19 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, ...@@ -112,15 +113,19 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl,
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
tx_pkts = wl->links[hlid].allocated_pkts; tx_pkts = wl->links[hlid].allocated_pkts;
single_link = (wl->active_link_count == 1);
/* /*
* if in FW PS and there is enough data in FW we can put the link * if in FW PS and there is enough data in FW we can put the link
* into high-level PS and clean out its TX queues. * into high-level PS and clean out its TX queues.
* Make an exception if this is the only connected link. In this * Make an exception if this is the only connected link. In this
* case FW-memory congestion is less of a problem. * case FW-memory congestion is less of a problem.
* Note that a single connected STA means 3 active links, since we must
* account for the global and broadcast AP links. The "fw_ps" check
* assures us the third link is a STA connected to the AP. Otherwise
* the FW would not set the PSM bit.
*/ */
if (!single_link && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) if (wl->active_link_count > 3 && fw_ps &&
tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl12xx_ps_link_start(wl, wlvif, hlid, true); wl12xx_ps_link_start(wl, wlvif, hlid, true);
} }
...@@ -639,6 +644,7 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl, u8 *hlid) ...@@ -639,6 +644,7 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl, u8 *hlid)
} }
out:
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; int q;
...@@ -652,7 +658,6 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl, u8 *hlid) ...@@ -652,7 +658,6 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl, u8 *hlid)
spin_unlock_irqrestore(&wl->wl_lock, flags); spin_unlock_irqrestore(&wl->wl_lock, flags);
} }
out:
return skb; return skb;
} }
...@@ -928,25 +933,6 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, ...@@ -928,25 +933,6 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
wl->stats.retry_count += result->ack_failures; wl->stats.retry_count += result->ack_failures;
/*
* update sequence number only when relevant, i.e. only in
* sessions of TKIP, AES and GEM (not in open or WEP sessions)
*/
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 = wlvif->tx_security_last_seq_lsb;
/*
* update security sequence number, taking care of potential
* wrap-around
*/
wlvif->tx_security_seq += (fw_lsb - cur_lsb) & 0xff;
wlvif->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));
...@@ -1061,7 +1047,8 @@ void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif) ...@@ -1061,7 +1047,8 @@ void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif)
/* TX failure */ /* TX failure */
for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) { for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) {
if (wlvif->bss_type == BSS_TYPE_AP_BSS) { if (wlvif->bss_type == BSS_TYPE_AP_BSS &&
i != wlvif->ap.bcast_hlid && i != wlvif->ap.global_hlid) {
/* this calls wl12xx_free_link */ /* this calls wl12xx_free_link */
wl1271_free_sta(wl, wlvif, i); wl1271_free_sta(wl, wlvif, i);
} else { } else {
...@@ -1304,7 +1291,7 @@ bool wlcore_is_queue_stopped_by_reason_locked(struct wl1271 *wl, ...@@ -1304,7 +1291,7 @@ bool wlcore_is_queue_stopped_by_reason_locked(struct wl1271 *wl,
{ {
int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue); int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock)); assert_spin_locked(&wl->wl_lock);
return test_bit(reason, &wl->queue_stop_reasons[hwq]); return test_bit(reason, &wl->queue_stop_reasons[hwq]);
} }
...@@ -1313,6 +1300,6 @@ bool wlcore_is_queue_stopped_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -1313,6 +1300,6 @@ bool wlcore_is_queue_stopped_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif,
{ {
int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue); int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock)); assert_spin_locked(&wl->wl_lock);
return !!wl->queue_stop_reasons[hwq]; return !!wl->queue_stop_reasons[hwq];
} }
...@@ -390,6 +390,9 @@ struct wl1271 { ...@@ -390,6 +390,9 @@ struct wl1271 {
/* number of currently active RX BA sessions */ /* number of currently active RX BA sessions */
int ba_rx_session_count; int ba_rx_session_count;
/* Maximum number of supported RX BA sessions */
int ba_rx_session_count_max;
/* AP-mode - number of currently connected stations */ /* AP-mode - number of currently connected stations */
int active_sta_count; int active_sta_count;
......
...@@ -274,6 +274,13 @@ struct wl1271_link { ...@@ -274,6 +274,13 @@ struct wl1271_link {
/* The wlvif this link belongs to. Might be null for global links */ /* The wlvif this link belongs to. Might be null for global links */
struct wl12xx_vif *wlvif; struct wl12xx_vif *wlvif;
/*
* total freed FW packets on the link - used for tracking the
* AES/TKIP PN across recoveries. Re-initialized each time
* from the wl1271_station structure.
*/
u64 total_freed_pkts;
}; };
#define WL1271_MAX_RX_FILTERS 5 #define WL1271_MAX_RX_FILTERS 5
...@@ -318,6 +325,13 @@ struct wl12xx_rx_filter { ...@@ -318,6 +325,13 @@ struct wl12xx_rx_filter {
struct wl1271_station { struct wl1271_station {
u8 hlid; u8 hlid;
bool in_connection; bool in_connection;
/*
* total freed FW packets on the link to the STA - used for tracking the
* AES/TKIP PN across recoveries. Re-initialized each time from the
* wl1271_station structure.
*/
u64 total_freed_pkts;
}; };
struct wl12xx_vif { struct wl12xx_vif {
...@@ -449,16 +463,15 @@ struct wl12xx_vif { ...@@ -449,16 +463,15 @@ struct wl12xx_vif {
*/ */
struct { struct {
u8 persistent[0]; u8 persistent[0];
/* /*
* Security sequence number * total freed FW packets on the link - used for
* bits 0-15: lower 16 bits part of sequence number * storing the AES/TKIP PN during recovery, as this
* bits 16-47: higher 32 bits part of sequence number * structure is not zeroed out.
* bits 48-63: not in use * For STA this holds the PN of the link to the AP.
* For AP this holds the PN of the broadcast link.
*/ */
u64 tx_security_seq; u64 total_freed_pkts;
/* 8 bits of the last sequence number in use */
u8 tx_security_last_seq_lsb;
}; };
}; };
......
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