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] = { ...@@ -623,6 +623,18 @@ static const int wl18xx_rtable[REG_TABLE_LEN] = {
[REG_RAW_FW_STATUS_ADDR] = WL18XX_FW_STATUS_ADDR, [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] = { 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_2_M] = { 7, 104, 801, 4, true },
[CLOCK_CONFIG_16_368_M] = { 9, 132, 3751, 4, true }, [CLOCK_CONFIG_16_368_M] = { 9, 132, 3751, 4, true },
...@@ -704,6 +716,23 @@ static int wl18xx_set_clk(struct wl1271 *wl) ...@@ -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].p, wl18xx_clk_table[clk_freq].q,
wl18xx_clk_table[clk_freq].swallow ? "swallow" : "spit"); 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, ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_N,
wl18xx_clk_table[clk_freq].n); wl18xx_clk_table[clk_freq].n);
if (ret < 0) if (ret < 0)
...@@ -745,6 +774,30 @@ static int wl18xx_set_clk(struct wl1271 *wl) ...@@ -745,6 +774,30 @@ static int wl18xx_set_clk(struct wl1271 *wl)
PLLSH_WCS_PLL_SWALLOW_EN_VAL2); 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: out:
return ret; return ret;
} }
...@@ -1175,16 +1228,48 @@ static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl, ...@@ -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) 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; s8 rom = 0, metal = 0, pg_ver = 0, rdl_ver = 0, package_type = 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]);
if (ret < 0) if (ret < 0)
goto out; 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); ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_1_3, &fuse);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -1192,7 +1277,7 @@ static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver) ...@@ -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; pg_ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET;
rom = (fuse & WL18XX_ROM_VER_MASK) >> WL18XX_ROM_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) >> metal = (fuse & WL18XX_METAL_VER_MASK) >>
WL18XX_METAL_VER_OFFSET; WL18XX_METAL_VER_OFFSET;
else else
...@@ -1204,11 +1289,9 @@ static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver) ...@@ -1204,11 +1289,9 @@ static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
goto out; goto out;
rdl_ver = (fuse & WL18XX_RDL_VER_MASK) >> WL18XX_RDL_VER_OFFSET; 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)", wl1271_info("wl18xx HW: %s, PG %d.%d (ROM 0x%x)",
rdl_ver, rdl_names[rdl_ver], pg_ver, metal, rom); wl18xx_rdl_name(rdl_ver), pg_ver, metal, rom);
if (ver) if (ver)
*ver = pg_ver; *ver = pg_ver;
......
...@@ -114,6 +114,11 @@ ...@@ -114,6 +114,11 @@
#define PLATFORM_DETECTION 0xA0E3E0 #define PLATFORM_DETECTION 0xA0E3E0
#define OCS_EN 0xA02080 #define OCS_EN 0xA02080
#define PRIMARY_CLK_DETECT 0xA020A6 #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_N 0xA02362
#define PLLSH_WCS_PLL_M 0xA02360 #define PLLSH_WCS_PLL_M 0xA02360
#define PLLSH_WCS_PLL_Q_FACTOR_CFG_1 0xA02364 #define PLLSH_WCS_PLL_Q_FACTOR_CFG_1 0xA02364
...@@ -128,19 +133,30 @@ ...@@ -128,19 +133,30 @@
#define PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK 0xFFFF #define PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK 0xFFFF
#define PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK 0x000F #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_VAL1 0x1
#define PLLSH_WCS_PLL_SWALLOW_EN_VAL2 0x12 #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_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_MASK 0x3e00
#define WL18XX_ROM_VER_OFFSET 0 #define WL18XX_ROM_VER_OFFSET 9
#define WL18XX_METAL_VER_MASK 0xC #define WL18XX_METAL_VER_MASK 0xC
#define WL18XX_METAL_VER_OFFSET 2 #define WL18XX_METAL_VER_OFFSET 2
#define WL18XX_NEW_METAL_VER_MASK 0x180 #define WL18XX_NEW_METAL_VER_MASK 0x180
#define WL18XX_NEW_METAL_VER_OFFSET 7 #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_REG_FUSE_DATA_2_3 0xA02614
#define WL18XX_RDL_VER_MASK 0x1f00 #define WL18XX_RDL_VER_MASK 0x1f00
#define WL18XX_RDL_VER_OFFSET 8 #define WL18XX_RDL_VER_OFFSET 8
...@@ -201,24 +217,21 @@ enum { ...@@ -201,24 +217,21 @@ enum {
NUM_BOARD_TYPES, NUM_BOARD_TYPES,
}; };
enum { enum wl18xx_rdl_num {
RDL_NONE = 0, RDL_NONE = 0,
RDL_1_HP = 1, RDL_1_HP = 1,
RDL_2_SP = 2, RDL_2_SP = 2,
RDL_3_HP = 3, RDL_3_HP = 3,
RDL_4_SP = 4, RDL_4_SP = 4,
RDL_5_SP = 0x11,
RDL_6_SP = 0x12,
RDL_7_SP = 0x13,
RDL_8_SP = 0x14,
_RDL_LAST, _RDL_LAST,
RDL_MAX = _RDL_LAST - 1, 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 */ /* FPGA_SPARE_1 register - used to change the PHY ATPG clock at boot time */
#define WL18XX_PHY_FPGA_SPARE_1 0x8093CA40 #define WL18XX_PHY_FPGA_SPARE_1 0x8093CA40
......
...@@ -1126,6 +1126,8 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -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_2_4 = wl->scan_templ_id_2_4;
u16 template_id_5 = wl->scan_templ_id_5; 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, skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len,
ie_len); ie_len);
if (!skb) { if (!skb) {
...@@ -1135,8 +1137,6 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -1135,8 +1137,6 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (ie_len) if (ie_len)
memcpy(skb_put(skb, ie_len), ie, ie_len); memcpy(skb_put(skb, ie_len), ie, ie_len);
wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len);
if (sched_scan && if (sched_scan &&
(wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) { (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) {
template_id_2_4 = wl->sched_scan_templ_id_2_4; 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, ...@@ -1172,7 +1172,7 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
if (!skb) if (!skb)
goto out; 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]); rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]);
if (wlvif->band == IEEE80211_BAND_2GHZ) if (wlvif->band == IEEE80211_BAND_2GHZ)
...@@ -1607,33 +1607,43 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid) ...@@ -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) 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) { 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: case IEEE80211_BAND_2GHZ:
/* channels 1..14 are mapped to 0..13 */
if (ch >= 1 && ch <= 14) if (ch >= 1 && ch <= 14)
idx = ch - 1; return ch - 1;
else break;
idx = -1; 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:
break;
}
break; break;
default: default:
wl1271_error("get reg conf ch idx - unknown band: %d", break;
(int)band);
} }
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, 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, ...@@ -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); 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); 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) ...@@ -1062,7 +1062,8 @@ int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode)
static const char* const PLT_MODE[] = { static const char* const PLT_MODE[] = {
"PLT_OFF", "PLT_OFF",
"PLT_ON", "PLT_ON",
"PLT_FEM_DETECT" "PLT_FEM_DETECT",
"PLT_CHIP_AWAKE"
}; };
int ret; int ret;
...@@ -1088,9 +1089,11 @@ int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode) ...@@ -1088,9 +1089,11 @@ int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode)
if (ret < 0) if (ret < 0)
goto power_off; goto power_off;
ret = wl->ops->plt_init(wl); if (plt_mode != PLT_CHIP_AWAKE) {
if (ret < 0) ret = wl->ops->plt_init(wl);
goto power_off; if (ret < 0)
goto power_off;
}
wl->state = WLCORE_STATE_ON; wl->state = WLCORE_STATE_ON;
wl1271_notice("firmware booted in PLT mode %s (%s)", wl1271_notice("firmware booted in PLT mode %s (%s)",
...@@ -2008,6 +2011,47 @@ static void wlcore_connection_loss_work(struct work_struct *work) ...@@ -2008,6 +2011,47 @@ static void wlcore_connection_loss_work(struct work_struct *work)
mutex_unlock(&wl->mutex); 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) static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
{ {
u8 policy = find_first_zero_bit(wl->rate_policies_map, 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) ...@@ -2159,6 +2203,8 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
wlcore_channel_switch_work); wlcore_channel_switch_work);
INIT_DELAYED_WORK(&wlvif->connection_loss_work, INIT_DELAYED_WORK(&wlvif->connection_loss_work,
wlcore_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); INIT_LIST_HEAD(&wlvif->list);
setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer, setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
...@@ -2376,6 +2422,11 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, ...@@ -2376,6 +2422,11 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
int ret = 0; int ret = 0;
u8 role_type; 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 | vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
IEEE80211_VIF_SUPPORTS_CQM_RSSI; IEEE80211_VIF_SUPPORTS_CQM_RSSI;
...@@ -2590,6 +2641,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, ...@@ -2590,6 +2641,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
cancel_work_sync(&wlvif->rx_streaming_disable_work); cancel_work_sync(&wlvif->rx_streaming_disable_work);
cancel_delayed_work_sync(&wlvif->connection_loss_work); cancel_delayed_work_sync(&wlvif->connection_loss_work);
cancel_delayed_work_sync(&wlvif->channel_switch_work); cancel_delayed_work_sync(&wlvif->channel_switch_work);
cancel_delayed_work_sync(&wlvif->pending_auth_complete_work);
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
} }
...@@ -2875,6 +2927,25 @@ static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif) ...@@ -2875,6 +2927,25 @@ static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
wlvif->rate_set = wlvif->basic_rate_set; 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, static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct ieee80211_conf *conf, u32 changed) struct ieee80211_conf *conf, u32 changed)
{ {
...@@ -3969,6 +4040,13 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, ...@@ -3969,6 +4040,13 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
} }
} else { } else {
if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { 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); ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -4120,6 +4198,9 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, ...@@ -4120,6 +4198,9 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
do_join = true; do_join = true;
} }
if (changed & BSS_CHANGED_IDLE && !is_ibss)
wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
if (changed & BSS_CHANGED_CQM) { if (changed & BSS_CHANGED_CQM) {
bool enable = false; bool enable = false;
if (bss_conf->cqm_rssi_thold) if (bss_conf->cqm_rssi_thold)
...@@ -4656,29 +4737,49 @@ static void wlcore_roc_if_possible(struct wl1271 *wl, ...@@ -4656,29 +4737,49 @@ static void wlcore_roc_if_possible(struct wl1271 *wl,
wl12xx_roc(wl, wlvif, wlvif->role_id, wlvif->band, wlvif->channel); wl12xx_roc(wl, wlvif, wlvif->role_id, wlvif->band, wlvif->channel);
} }
static void wlcore_update_inconn_sta(struct wl1271 *wl, /*
struct wl12xx_vif *wlvif, * when wl_sta is NULL, we treat this call as if coming from a
struct wl1271_station *wl_sta, * pending auth reply.
bool in_connection) * 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 (in_conn) {
if (WARN_ON(wl_sta->in_connection)) if (WARN_ON(wl_sta && wl_sta->in_connection))
return; 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); 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 { } 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; return;
wl_sta->in_connection = false; if (WARN_ON(wl_sta && !wlvif->inconn_count))
wlvif->inconn_count--;
if (WARN_ON(wlvif->inconn_count < 0))
return; return;
if (!wlvif->inconn_count) if (wl_sta) {
if (test_bit(wlvif->role_id, wl->roc_map)) wl_sta->in_connection = false;
wl12xx_croc(wl, wlvif->role_id); wlvif->inconn_count--;
} else {
wlvif->ap_pending_auth_reply = false;
}
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[] = { ...@@ -5313,10 +5414,7 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = {
/* 5 GHz band channels for WL1273 */ /* 5 GHz band channels for WL1273 */
static struct ieee80211_channel wl1271_channels_5ghz[] = { 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 = 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 = 12, .center_freq = 5060, .max_power = WLCORE_MAX_TXPWR },
{ .hw_value = 16, .center_freq = 5080, .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 }, { .hw_value = 34, .center_freq = 5170, .max_power = WLCORE_MAX_TXPWR },
...@@ -5896,6 +5994,11 @@ static const struct wiphy_wowlan_support wlcore_wowlan_support = { ...@@ -5896,6 +5994,11 @@ static const struct wiphy_wowlan_support wlcore_wowlan_support = {
}; };
#endif #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) static void wlcore_nvs_cb(const struct firmware *fw, void *context)
{ {
struct wl1271 *wl = context; struct wl1271 *wl = context;
...@@ -5904,6 +6007,7 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context) ...@@ -5904,6 +6007,7 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
struct wl12xx_platform_data *pdata = pdev_data->pdata; struct wl12xx_platform_data *pdata = pdev_data->pdata;
unsigned long irqflags; unsigned long irqflags;
int ret; int ret;
irq_handler_t hardirq_fn = NULL;
if (fw) { if (fw) {
wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
...@@ -5932,12 +6036,14 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context) ...@@ -5932,12 +6036,14 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
wl->platform_quirks = pdata->platform_quirks; wl->platform_quirks = pdata->platform_quirks;
wl->if_ops = pdev_data->if_ops; 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; irqflags = IRQF_TRIGGER_RISING;
else hardirq_fn = wlcore_hardirq;
} else {
irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; 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); irqflags, pdev->name, wl);
if (ret < 0) { if (ret < 0) {
wl1271_error("request_irq() failed: %d", ret); wl1271_error("request_irq() failed: %d", ret);
......
...@@ -83,6 +83,10 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) ...@@ -83,6 +83,10 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
struct wl12xx_vif *wlvif; struct wl12xx_vif *wlvif;
u32 timeout; u32 timeout;
/* We do not enter elp sleep in PLT mode */
if (wl->plt)
return;
if (wl->sleep_auth != WL1271_PSM_ELP) if (wl->sleep_auth != WL1271_PSM_ELP)
return; return;
......
...@@ -174,17 +174,7 @@ wlcore_scan_get_channels(struct wl1271 *wl, ...@@ -174,17 +174,7 @@ wlcore_scan_get_channels(struct wl1271 *wl,
/* if radar is set, we ignore the passive flag */ /* if radar is set, we ignore the passive flag */
(radar || (radar ||
!!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) { !!(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) { if (flags & IEEE80211_CHAN_RADAR) {
channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS; channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS;
...@@ -222,6 +212,17 @@ wlcore_scan_get_channels(struct wl1271 *wl, ...@@ -222,6 +212,17 @@ wlcore_scan_get_channels(struct wl1271 *wl,
*n_pactive_ch); *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++; j++;
} }
} }
...@@ -364,7 +365,7 @@ wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl, ...@@ -364,7 +365,7 @@ wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl,
struct cfg80211_ssid *ssids = req->ssids; struct cfg80211_ssid *ssids = req->ssids;
int ret = 0, type, i, j, n_match_ssids = 0; 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 */ /* count the match sets that contain SSIDs */
for (i = 0; i < req->n_match_sets; i++) for (i = 0; i < req->n_match_sets; i++)
...@@ -442,8 +443,6 @@ wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl, ...@@ -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, ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_SSID_CFG, cmd,
sizeof(*cmd), 0); sizeof(*cmd), 0);
if (ret < 0) { if (ret < 0) {
......
...@@ -297,7 +297,8 @@ static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[]) ...@@ -297,7 +297,8 @@ static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[])
ret = wl1271_plt_stop(wl); ret = wl1271_plt_stop(wl);
break; break;
case PLT_ON: case PLT_ON:
ret = wl1271_plt_start(wl, PLT_ON); case PLT_CHIP_AWAKE:
ret = wl1271_plt_start(wl, val);
break; break;
case PLT_FEM_DETECT: case PLT_FEM_DETECT:
ret = wl1271_tm_detect_fem(wl, tb); ret = wl1271_tm_detect_fem(wl, tb);
...@@ -361,6 +362,7 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ...@@ -361,6 +362,7 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
{ {
struct wl1271 *wl = hw->priv; struct wl1271 *wl = hw->priv;
struct nlattr *tb[WL1271_TM_ATTR_MAX + 1]; struct nlattr *tb[WL1271_TM_ATTR_MAX + 1];
u32 nla_cmd;
int err; int err;
err = nla_parse(tb, WL1271_TM_ATTR_MAX, data, len, wl1271_tm_policy); 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, ...@@ -370,7 +372,14 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (!tb[WL1271_TM_ATTR_CMD_ID]) if (!tb[WL1271_TM_ATTR_CMD_ID])
return -EINVAL; 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: case WL1271_TM_CMD_TEST:
return wl1271_tm_cmd_test(wl, tb); return wl1271_tm_cmd_test(wl, tb);
case WL1271_TM_CMD_INTERROGATE: case WL1271_TM_CMD_INTERROGATE:
......
...@@ -86,19 +86,34 @@ void wl1271_free_tx_id(struct wl1271 *wl, int id) ...@@ -86,19 +86,34 @@ void wl1271_free_tx_id(struct wl1271 *wl, int id)
EXPORT_SYMBOL(wl1271_free_tx_id); EXPORT_SYMBOL(wl1271_free_tx_id);
static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct ieee80211_hdr *hdr; 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 * add the station to the known list before transmitting the
* authentication response. this way it won't get de-authed by FW * authentication response. this way it won't get de-authed by FW
* when transmitting too soon. * when transmitting too soon.
*/ */
hdr = (struct ieee80211_hdr *)(skb->data + wl1271_acx_set_inconnection_sta(wl, hdr->addr1);
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, 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, ...@@ -386,7 +401,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) || is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) ||
(cipher == WLAN_CIPHER_SUITE_WEP104); (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); ret = wl1271_set_default_wep_key(wl, wlvif, idx);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -404,7 +419,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, ...@@ -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); wl1271_tx_fill_hdr(wl, wlvif, skb, extra, info, hlid);
if (!is_dummy && wlvif && wlvif->bss_type == BSS_TYPE_AP_BSS) { 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); wl1271_tx_regulate_link(wl, wlvif, hlid);
} }
......
...@@ -56,6 +56,9 @@ ...@@ -56,6 +56,9 @@
/* Used for management frames and dummy packets */ /* Used for management frames and dummy packets */
#define WL1271_TID_MGMT 7 #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 { struct wl127x_tx_mem {
/* /*
* Number of extra memory blocks to allocate for this packet * 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, ...@@ -481,6 +481,8 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key_conf); struct ieee80211_key_conf *key_conf);
void wlcore_regdomain_config(struct wl1271 *wl); 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 static inline void
wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band, wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band,
......
...@@ -255,6 +255,7 @@ enum wl12xx_vif_flags { ...@@ -255,6 +255,7 @@ enum wl12xx_vif_flags {
WLVIF_FLAG_CS_PROGRESS, WLVIF_FLAG_CS_PROGRESS,
WLVIF_FLAG_AP_PROBE_RESP_SET, WLVIF_FLAG_AP_PROBE_RESP_SET,
WLVIF_FLAG_IN_USE, WLVIF_FLAG_IN_USE,
WLVIF_FLAG_ACTIVE,
}; };
struct wl12xx_vif; struct wl12xx_vif;
...@@ -307,6 +308,7 @@ enum plt_mode { ...@@ -307,6 +308,7 @@ enum plt_mode {
PLT_OFF = 0, PLT_OFF = 0,
PLT_ON = 1, PLT_ON = 1,
PLT_FEM_DETECT = 2, PLT_FEM_DETECT = 2,
PLT_CHIP_AWAKE = 3
}; };
struct wl12xx_rx_filter_field { struct wl12xx_rx_filter_field {
...@@ -456,6 +458,15 @@ struct wl12xx_vif { ...@@ -456,6 +458,15 @@ struct wl12xx_vif {
*/ */
int hw_queue_base; 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! * This struct must be last!
* data that has to be saved acrossed reconfigs (e.g. recovery) * 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