Commit c21a7d66 authored by John W. Linville's avatar John W. Linville
parents d819c6cf f2cede49
......@@ -623,6 +623,18 @@ static const int wl18xx_rtable[REG_TABLE_LEN] = {
[REG_RAW_FW_STATUS_ADDR] = WL18XX_FW_STATUS_ADDR,
};
static const struct wl18xx_clk_cfg wl18xx_clk_table_coex[NUM_CLOCK_CONFIGS] = {
[CLOCK_CONFIG_16_2_M] = { 8, 121, 0, 0, false },
[CLOCK_CONFIG_16_368_M] = { 8, 120, 0, 0, false },
[CLOCK_CONFIG_16_8_M] = { 8, 117, 0, 0, false },
[CLOCK_CONFIG_19_2_M] = { 10, 128, 0, 0, false },
[CLOCK_CONFIG_26_M] = { 11, 104, 0, 0, false },
[CLOCK_CONFIG_32_736_M] = { 8, 120, 0, 0, false },
[CLOCK_CONFIG_33_6_M] = { 8, 117, 0, 0, false },
[CLOCK_CONFIG_38_468_M] = { 10, 128, 0, 0, false },
[CLOCK_CONFIG_52_M] = { 11, 104, 0, 0, false },
};
static const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = {
[CLOCK_CONFIG_16_2_M] = { 7, 104, 801, 4, true },
[CLOCK_CONFIG_16_368_M] = { 9, 132, 3751, 4, true },
......@@ -704,6 +716,23 @@ static int wl18xx_set_clk(struct wl1271 *wl)
wl18xx_clk_table[clk_freq].p, wl18xx_clk_table[clk_freq].q,
wl18xx_clk_table[clk_freq].swallow ? "swallow" : "spit");
/* coex PLL configuration */
ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_N,
wl18xx_clk_table_coex[clk_freq].n);
if (ret < 0)
goto out;
ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_M,
wl18xx_clk_table_coex[clk_freq].m);
if (ret < 0)
goto out;
/* bypass the swallowing logic */
ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_SWALLOW_EN,
PLLSH_COEX_PLL_SWALLOW_EN_VAL1);
if (ret < 0)
goto out;
ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_N,
wl18xx_clk_table[clk_freq].n);
if (ret < 0)
......@@ -745,6 +774,30 @@ static int wl18xx_set_clk(struct wl1271 *wl)
PLLSH_WCS_PLL_SWALLOW_EN_VAL2);
}
/* choose WCS PLL */
ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_SEL,
PLLSH_WL_PLL_SEL_WCS_PLL);
if (ret < 0)
goto out;
/* enable both PLLs */
ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_EN, PLLSH_WL_PLL_EN_VAL1);
if (ret < 0)
goto out;
udelay(1000);
/* disable coex PLL */
ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_EN, PLLSH_WL_PLL_EN_VAL2);
if (ret < 0)
goto out;
/* reset the swallowing logic */
ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_SWALLOW_EN,
PLLSH_COEX_PLL_SWALLOW_EN_VAL2);
if (ret < 0)
goto out;
out:
return ret;
}
......@@ -1175,16 +1228,48 @@ static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl,
}
}
static const char *wl18xx_rdl_name(enum wl18xx_rdl_num rdl_num)
{
switch (rdl_num) {
case RDL_1_HP:
return "183xH";
case RDL_2_SP:
return "183x or 180x";
case RDL_3_HP:
return "187xH";
case RDL_4_SP:
return "187x";
case RDL_5_SP:
return "RDL11 - Not Supported";
case RDL_6_SP:
return "180xD";
case RDL_7_SP:
return "RDL13 - Not Supported (1893Q)";
case RDL_8_SP:
return "18xxQ";
case RDL_NONE:
return "UNTRIMMED";
default:
return "UNKNOWN";
}
}
static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
{
u32 fuse;
s8 rom = 0, metal = 0, pg_ver = 0, rdl_ver = 0;
s8 rom = 0, metal = 0, pg_ver = 0, rdl_ver = 0, package_type = 0;
int ret;
ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
if (ret < 0)
goto out;
ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_2_3, &fuse);
if (ret < 0)
goto out;
package_type = (fuse >> WL18XX_PACKAGE_TYPE_OFFSET) & 1;
ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_1_3, &fuse);
if (ret < 0)
goto out;
......@@ -1192,7 +1277,7 @@ static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
pg_ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET;
rom = (fuse & WL18XX_ROM_VER_MASK) >> WL18XX_ROM_VER_OFFSET;
if (rom <= 0xE)
if ((rom <= 0xE) && (package_type == WL18XX_PACKAGE_TYPE_WSP))
metal = (fuse & WL18XX_METAL_VER_MASK) >>
WL18XX_METAL_VER_OFFSET;
else
......@@ -1204,11 +1289,9 @@ static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
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);
wl1271_info("wl18xx HW: %s, PG %d.%d (ROM 0x%x)",
wl18xx_rdl_name(rdl_ver), pg_ver, metal, rom);
if (ver)
*ver = pg_ver;
......
......@@ -114,6 +114,11 @@
#define PLATFORM_DETECTION 0xA0E3E0
#define OCS_EN 0xA02080
#define PRIMARY_CLK_DETECT 0xA020A6
#define PLLSH_COEX_PLL_N 0xA02384
#define PLLSH_COEX_PLL_M 0xA02382
#define PLLSH_COEX_PLL_SWALLOW_EN 0xA0238E
#define PLLSH_WL_PLL_SEL 0xA02398
#define PLLSH_WCS_PLL_N 0xA02362
#define PLLSH_WCS_PLL_M 0xA02360
#define PLLSH_WCS_PLL_Q_FACTOR_CFG_1 0xA02364
......@@ -128,19 +133,30 @@
#define PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK 0xFFFF
#define PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK 0x000F
#define PLLSH_WL_PLL_EN_VAL1 0x7
#define PLLSH_WL_PLL_EN_VAL2 0x2
#define PLLSH_COEX_PLL_SWALLOW_EN_VAL1 0x2
#define PLLSH_COEX_PLL_SWALLOW_EN_VAL2 0x11
#define PLLSH_WCS_PLL_SWALLOW_EN_VAL1 0x1
#define PLLSH_WCS_PLL_SWALLOW_EN_VAL2 0x12
#define PLLSH_WL_PLL_SEL_WCS_PLL 0x0
#define PLLSH_WL_PLL_SEL_COEX_PLL 0x1
#define WL18XX_REG_FUSE_DATA_1_3 0xA0260C
#define WL18XX_PG_VER_MASK 0x70
#define WL18XX_PG_VER_OFFSET 4
#define WL18XX_ROM_VER_MASK 0x3
#define WL18XX_ROM_VER_OFFSET 0
#define WL18XX_ROM_VER_MASK 0x3e00
#define WL18XX_ROM_VER_OFFSET 9
#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_PACKAGE_TYPE_OFFSET 13
#define WL18XX_PACKAGE_TYPE_WSP 0
#define WL18XX_REG_FUSE_DATA_2_3 0xA02614
#define WL18XX_RDL_VER_MASK 0x1f00
#define WL18XX_RDL_VER_OFFSET 8
......@@ -201,24 +217,21 @@ enum {
NUM_BOARD_TYPES,
};
enum {
enum wl18xx_rdl_num {
RDL_NONE = 0,
RDL_1_HP = 1,
RDL_2_SP = 2,
RDL_3_HP = 3,
RDL_4_SP = 4,
RDL_5_SP = 0x11,
RDL_6_SP = 0x12,
RDL_7_SP = 0x13,
RDL_8_SP = 0x14,
_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",
};
/* FPGA_SPARE_1 register - used to change the PHY ATPG clock at boot time */
#define WL18XX_PHY_FPGA_SPARE_1 0x8093CA40
......
......@@ -1126,6 +1126,8 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u16 template_id_2_4 = wl->scan_templ_id_2_4;
u16 template_id_5 = wl->scan_templ_id_5;
wl1271_debug(DEBUG_SCAN, "build probe request band %d", band);
skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len,
ie_len);
if (!skb) {
......@@ -1135,8 +1137,6 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (ie_len)
memcpy(skb_put(skb, ie_len), ie, ie_len);
wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len);
if (sched_scan &&
(wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) {
template_id_2_4 = wl->sched_scan_templ_id_2_4;
......@@ -1172,7 +1172,7 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
if (!skb)
goto out;
wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len);
wl1271_debug(DEBUG_SCAN, "set ap probe request template");
rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]);
if (wlvif->band == IEEE80211_BAND_2GHZ)
......@@ -1607,33 +1607,43 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
static int wlcore_get_reg_conf_ch_idx(enum ieee80211_band band, u16 ch)
{
int idx = -1;
/*
* map the given band/channel to the respective predefined
* bit expected by the fw
*/
switch (band) {
case IEEE80211_BAND_5GHZ:
if (ch >= 8 && ch <= 16)
idx = ((ch-8)/4 + 18);
else if (ch >= 34 && ch <= 64)
idx = ((ch-34)/2 + 3 + 18);
else if (ch >= 100 && ch <= 140)
idx = ((ch-100)/4 + 15 + 18);
else if (ch >= 149 && ch <= 165)
idx = ((ch-149)/4 + 26 + 18);
else
idx = -1;
break;
case IEEE80211_BAND_2GHZ:
/* channels 1..14 are mapped to 0..13 */
if (ch >= 1 && ch <= 14)
idx = ch - 1;
else
idx = -1;
return ch - 1;
break;
case IEEE80211_BAND_5GHZ:
switch (ch) {
case 8 ... 16:
/* channels 8,12,16 are mapped to 18,19,20 */
return 18 + (ch-8)/4;
case 34 ... 48:
/* channels 34,36..48 are mapped to 21..28 */
return 21 + (ch-34)/2;
case 52 ... 64:
/* channels 52,56..64 are mapped to 29..32 */
return 29 + (ch-52)/4;
case 100 ... 140:
/* channels 100,104..140 are mapped to 33..43 */
return 33 + (ch-100)/4;
case 149 ... 165:
/* channels 149,153..165 are mapped to 44..48 */
return 44 + (ch-149)/4;
default:
wl1271_error("get reg conf ch idx - unknown band: %d",
(int)band);
break;
}
break;
default:
break;
}
return idx;
wl1271_error("%s: unknown band/channel: %d/%d", __func__, band, ch);
return -1;
}
void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel,
......@@ -1646,7 +1656,7 @@ void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel,
ch_bit_idx = wlcore_get_reg_conf_ch_idx(band, channel);
if (ch_bit_idx > 0 && ch_bit_idx <= WL1271_MAX_CHANNELS)
if (ch_bit_idx >= 0 && ch_bit_idx <= WL1271_MAX_CHANNELS)
set_bit(ch_bit_idx, (long *)wl->reg_ch_conf_pending);
}
......
......@@ -1062,7 +1062,8 @@ int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode)
static const char* const PLT_MODE[] = {
"PLT_OFF",
"PLT_ON",
"PLT_FEM_DETECT"
"PLT_FEM_DETECT",
"PLT_CHIP_AWAKE"
};
int ret;
......@@ -1088,9 +1089,11 @@ int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode)
if (ret < 0)
goto power_off;
if (plt_mode != PLT_CHIP_AWAKE) {
ret = wl->ops->plt_init(wl);
if (ret < 0)
goto power_off;
}
wl->state = WLCORE_STATE_ON;
wl1271_notice("firmware booted in PLT mode %s (%s)",
......@@ -2008,6 +2011,47 @@ static void wlcore_connection_loss_work(struct work_struct *work)
mutex_unlock(&wl->mutex);
}
static void wlcore_pending_auth_complete_work(struct work_struct *work)
{
struct delayed_work *dwork;
struct wl1271 *wl;
struct wl12xx_vif *wlvif;
unsigned long time_spare;
int ret;
dwork = container_of(work, struct delayed_work, work);
wlvif = container_of(dwork, struct wl12xx_vif,
pending_auth_complete_work);
wl = wlvif->wl;
mutex_lock(&wl->mutex);
if (unlikely(wl->state != WLCORE_STATE_ON))
goto out;
/*
* Make sure a second really passed since the last auth reply. Maybe
* a second auth reply arrived while we were stuck on the mutex.
* Check for a little less than the timeout to protect from scheduler
* irregularities.
*/
time_spare = jiffies +
msecs_to_jiffies(WLCORE_PEND_AUTH_ROC_TIMEOUT - 50);
if (!time_after(time_spare, wlvif->pending_auth_reply_time))
goto out;
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
/* cancel the ROC if active */
wlcore_update_inconn_sta(wl, wlvif, NULL, false);
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
}
static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
{
u8 policy = find_first_zero_bit(wl->rate_policies_map,
......@@ -2159,6 +2203,8 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
wlcore_channel_switch_work);
INIT_DELAYED_WORK(&wlvif->connection_loss_work,
wlcore_connection_loss_work);
INIT_DELAYED_WORK(&wlvif->pending_auth_complete_work,
wlcore_pending_auth_complete_work);
INIT_LIST_HEAD(&wlvif->list);
setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
......@@ -2376,6 +2422,11 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
int ret = 0;
u8 role_type;
if (wl->plt) {
wl1271_error("Adding Interface not allowed while in PLT mode");
return -EBUSY;
}
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
IEEE80211_VIF_SUPPORTS_CQM_RSSI;
......@@ -2590,6 +2641,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
cancel_work_sync(&wlvif->rx_streaming_disable_work);
cancel_delayed_work_sync(&wlvif->connection_loss_work);
cancel_delayed_work_sync(&wlvif->channel_switch_work);
cancel_delayed_work_sync(&wlvif->pending_auth_complete_work);
mutex_lock(&wl->mutex);
}
......@@ -2875,6 +2927,25 @@ static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
wlvif->rate_set = wlvif->basic_rate_set;
}
static void wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
bool idle)
{
bool cur_idle = !test_bit(WLVIF_FLAG_ACTIVE, &wlvif->flags);
if (idle == cur_idle)
return;
if (idle) {
clear_bit(WLVIF_FLAG_ACTIVE, &wlvif->flags);
} else {
/* The current firmware only supports sched_scan in idle */
if (wl->sched_vif == wlvif)
wl->ops->sched_scan_stop(wl, wlvif);
set_bit(WLVIF_FLAG_ACTIVE, &wlvif->flags);
}
}
static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct ieee80211_conf *conf, u32 changed)
{
......@@ -3969,6 +4040,13 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
}
} else {
if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
/*
* AP might be in ROC in case we have just
* sent auth reply. handle it.
*/
if (test_bit(wlvif->role_id, wl->roc_map))
wl12xx_croc(wl, wlvif->role_id);
ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
if (ret < 0)
goto out;
......@@ -4120,6 +4198,9 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
do_join = true;
}
if (changed & BSS_CHANGED_IDLE && !is_ibss)
wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
if (changed & BSS_CHANGED_CQM) {
bool enable = false;
if (bss_conf->cqm_rssi_thold)
......@@ -4656,28 +4737,48 @@ static void wlcore_roc_if_possible(struct wl1271 *wl,
wl12xx_roc(wl, wlvif, wlvif->role_id, wlvif->band, wlvif->channel);
}
static void wlcore_update_inconn_sta(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct wl1271_station *wl_sta,
bool in_connection)
/*
* when wl_sta is NULL, we treat this call as if coming from a
* pending auth reply.
* wl->mutex must be taken and the FW must be awake when the call
* takes place.
*/
void wlcore_update_inconn_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct wl1271_station *wl_sta, bool in_conn)
{
if (in_connection) {
if (WARN_ON(wl_sta->in_connection))
if (in_conn) {
if (WARN_ON(wl_sta && wl_sta->in_connection))
return;
wl_sta->in_connection = true;
if (!wlvif->inconn_count++)
if (!wlvif->ap_pending_auth_reply &&
!wlvif->inconn_count)
wlcore_roc_if_possible(wl, wlvif);
if (wl_sta) {
wl_sta->in_connection = true;
wlvif->inconn_count++;
} else {
wlvif->ap_pending_auth_reply = true;
}
} else {
if (!wl_sta->in_connection)
if (wl_sta && !wl_sta->in_connection)
return;
if (WARN_ON(!wl_sta && !wlvif->ap_pending_auth_reply))
return;
if (WARN_ON(wl_sta && !wlvif->inconn_count))
return;
if (wl_sta) {
wl_sta->in_connection = false;
wlvif->inconn_count--;
if (WARN_ON(wlvif->inconn_count < 0))
return;
} else {
wlvif->ap_pending_auth_reply = false;
}
if (!wlvif->inconn_count)
if (test_bit(wlvif->role_id, wl->roc_map))
if (!wlvif->inconn_count && !wlvif->ap_pending_auth_reply &&
test_bit(wlvif->role_id, wl->roc_map))
wl12xx_croc(wl, wlvif->role_id);
}
}
......@@ -5313,10 +5414,7 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = {
/* 5 GHz band channels for WL1273 */
static struct ieee80211_channel wl1271_channels_5ghz[] = {
{ .hw_value = 7, .center_freq = 5035, .max_power = WLCORE_MAX_TXPWR },
{ .hw_value = 8, .center_freq = 5040, .max_power = WLCORE_MAX_TXPWR },
{ .hw_value = 9, .center_freq = 5045, .max_power = WLCORE_MAX_TXPWR },
{ .hw_value = 11, .center_freq = 5055, .max_power = WLCORE_MAX_TXPWR },
{ .hw_value = 12, .center_freq = 5060, .max_power = WLCORE_MAX_TXPWR },
{ .hw_value = 16, .center_freq = 5080, .max_power = WLCORE_MAX_TXPWR },
{ .hw_value = 34, .center_freq = 5170, .max_power = WLCORE_MAX_TXPWR },
......@@ -5896,6 +5994,11 @@ static const struct wiphy_wowlan_support wlcore_wowlan_support = {
};
#endif
static irqreturn_t wlcore_hardirq(int irq, void *cookie)
{
return IRQ_WAKE_THREAD;
}
static void wlcore_nvs_cb(const struct firmware *fw, void *context)
{
struct wl1271 *wl = context;
......@@ -5904,6 +6007,7 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
struct wl12xx_platform_data *pdata = pdev_data->pdata;
unsigned long irqflags;
int ret;
irq_handler_t hardirq_fn = NULL;
if (fw) {
wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
......@@ -5932,12 +6036,14 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
wl->platform_quirks = pdata->platform_quirks;
wl->if_ops = pdev_data->if_ops;
if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) {
irqflags = IRQF_TRIGGER_RISING;
else
hardirq_fn = wlcore_hardirq;
} else {
irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
}
ret = request_threaded_irq(wl->irq, NULL, wlcore_irq,
ret = request_threaded_irq(wl->irq, hardirq_fn, wlcore_irq,
irqflags, pdev->name, wl);
if (ret < 0) {
wl1271_error("request_irq() failed: %d", ret);
......
......@@ -83,6 +83,10 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
struct wl12xx_vif *wlvif;
u32 timeout;
/* We do not enter elp sleep in PLT mode */
if (wl->plt)
return;
if (wl->sleep_auth != WL1271_PSM_ELP)
return;
......
......@@ -174,17 +174,7 @@ wlcore_scan_get_channels(struct wl1271 *wl,
/* if radar is set, we ignore the passive flag */
(radar ||
!!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) {
wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
req_channels[i]->band,
req_channels[i]->center_freq);
wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X",
req_channels[i]->hw_value,
req_channels[i]->flags);
wl1271_debug(DEBUG_SCAN, "max_power %d",
req_channels[i]->max_power);
wl1271_debug(DEBUG_SCAN, "min_dwell_time %d max dwell time %d",
min_dwell_time_active,
max_dwell_time_active);
if (flags & IEEE80211_CHAN_RADAR) {
channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS;
......@@ -222,6 +212,17 @@ wlcore_scan_get_channels(struct wl1271 *wl,
*n_pactive_ch);
}
wl1271_debug(DEBUG_SCAN, "freq %d, ch. %d, flags 0x%x, power %d, min/max_dwell %d/%d%s%s",
req_channels[i]->center_freq,
req_channels[i]->hw_value,
req_channels[i]->flags,
req_channels[i]->max_power,
min_dwell_time_active,
max_dwell_time_active,
flags & IEEE80211_CHAN_RADAR ?
", DFS" : "",
flags & IEEE80211_CHAN_PASSIVE_SCAN ?
", PASSIVE" : "");
j++;
}
}
......@@ -364,7 +365,7 @@ wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl,
struct cfg80211_ssid *ssids = req->ssids;
int ret = 0, type, i, j, n_match_ssids = 0;
wl1271_debug(DEBUG_CMD, "cmd sched scan ssid list");
wl1271_debug((DEBUG_CMD | DEBUG_SCAN), "cmd sched scan ssid list");
/* count the match sets that contain SSIDs */
for (i = 0; i < req->n_match_sets; i++)
......@@ -442,8 +443,6 @@ wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl,
}
}
wl1271_dump(DEBUG_SCAN, "SSID_LIST: ", cmd, sizeof(*cmd));
ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_SSID_CFG, cmd,
sizeof(*cmd), 0);
if (ret < 0) {
......
......@@ -297,7 +297,8 @@ static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[])
ret = wl1271_plt_stop(wl);
break;
case PLT_ON:
ret = wl1271_plt_start(wl, PLT_ON);
case PLT_CHIP_AWAKE:
ret = wl1271_plt_start(wl, val);
break;
case PLT_FEM_DETECT:
ret = wl1271_tm_detect_fem(wl, tb);
......@@ -361,6 +362,7 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
{
struct wl1271 *wl = hw->priv;
struct nlattr *tb[WL1271_TM_ATTR_MAX + 1];
u32 nla_cmd;
int err;
err = nla_parse(tb, WL1271_TM_ATTR_MAX, data, len, wl1271_tm_policy);
......@@ -370,7 +372,14 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (!tb[WL1271_TM_ATTR_CMD_ID])
return -EINVAL;
switch (nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID])) {
nla_cmd = nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID]);
/* Only SET_PLT_MODE is allowed in case of mode PLT_CHIP_AWAKE */
if (wl->plt_mode == PLT_CHIP_AWAKE &&
nla_cmd != WL1271_TM_CMD_SET_PLT_MODE)
return -EOPNOTSUPP;
switch (nla_cmd) {
case WL1271_TM_CMD_TEST:
return wl1271_tm_cmd_test(wl, tb);
case WL1271_TM_CMD_INTERROGATE:
......
......@@ -86,19 +86,34 @@ void wl1271_free_tx_id(struct wl1271 *wl, int id)
EXPORT_SYMBOL(wl1271_free_tx_id);
static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
hdr = (struct ieee80211_hdr *)(skb->data +
sizeof(struct wl1271_tx_hw_descr));
if (!ieee80211_is_auth(hdr->frame_control))
return;
/*
* add the station to the known list before transmitting the
* authentication response. this way it won't get de-authed by FW
* when transmitting too soon.
*/
hdr = (struct ieee80211_hdr *)(skb->data +
sizeof(struct wl1271_tx_hw_descr));
if (ieee80211_is_auth(hdr->frame_control))
wl1271_acx_set_inconnection_sta(wl, hdr->addr1);
/*
* ROC for 1 second on the AP channel for completing the connection.
* Note the ROC will be continued by the update_sta_state callbacks
* once the station reaches the associated state.
*/
wlcore_update_inconn_sta(wl, wlvif, NULL, true);
wlvif->pending_auth_reply_time = jiffies;
cancel_delayed_work(&wlvif->pending_auth_complete_work);
ieee80211_queue_delayed_work(wl->hw,
&wlvif->pending_auth_complete_work,
msecs_to_jiffies(WLCORE_PEND_AUTH_ROC_TIMEOUT));
}
static void wl1271_tx_regulate_link(struct wl1271 *wl,
......@@ -386,7 +401,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) ||
(cipher == WLAN_CIPHER_SUITE_WEP104);
if (WARN_ON(is_wep && wlvif->default_key != idx)) {
if (WARN_ON(is_wep && wlvif && wlvif->default_key != idx)) {
ret = wl1271_set_default_wep_key(wl, wlvif, idx);
if (ret < 0)
return ret;
......@@ -404,7 +419,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
wl1271_tx_fill_hdr(wl, wlvif, skb, extra, info, hlid);
if (!is_dummy && wlvif && wlvif->bss_type == BSS_TYPE_AP_BSS) {
wl1271_tx_ap_update_inconnection_sta(wl, skb);
wl1271_tx_ap_update_inconnection_sta(wl, wlvif, skb);
wl1271_tx_regulate_link(wl, wlvif, hlid);
}
......
......@@ -56,6 +56,9 @@
/* Used for management frames and dummy packets */
#define WL1271_TID_MGMT 7
/* stop a ROC for pending authentication reply after this time (ms) */
#define WLCORE_PEND_AUTH_ROC_TIMEOUT 1000
struct wl127x_tx_mem {
/*
* Number of extra memory blocks to allocate for this packet
......
......@@ -481,6 +481,8 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key_conf);
void wlcore_regdomain_config(struct wl1271 *wl);
void wlcore_update_inconn_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct wl1271_station *wl_sta, bool in_conn);
static inline void
wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band,
......
......@@ -255,6 +255,7 @@ enum wl12xx_vif_flags {
WLVIF_FLAG_CS_PROGRESS,
WLVIF_FLAG_AP_PROBE_RESP_SET,
WLVIF_FLAG_IN_USE,
WLVIF_FLAG_ACTIVE,
};
struct wl12xx_vif;
......@@ -307,6 +308,7 @@ enum plt_mode {
PLT_OFF = 0,
PLT_ON = 1,
PLT_FEM_DETECT = 2,
PLT_CHIP_AWAKE = 3
};
struct wl12xx_rx_filter_field {
......@@ -456,6 +458,15 @@ struct wl12xx_vif {
*/
int hw_queue_base;
/* do we have a pending auth reply? (and ROC) */
bool ap_pending_auth_reply;
/* time when we sent the pending auth reply */
unsigned long pending_auth_reply_time;
/* work for canceling ROC after pending auth reply */
struct delayed_work pending_auth_complete_work;
/*
* This struct must be last!
* data that has to be saved acrossed reconfigs (e.g. recovery)
......
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