mirror of https://gitee.com/openkylin/linux.git
Merge branch 'wl12xx-next' into for-linville
Conflicts: drivers/net/wireless/ti/wl18xx/main.c
This commit is contained in:
commit
da0b1baa94
|
@ -174,7 +174,7 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
|
||||||
struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs;
|
struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs;
|
||||||
struct wl1271_radio_parms_cmd *radio_parms;
|
struct wl1271_radio_parms_cmd *radio_parms;
|
||||||
struct wl1271_ini_general_params *gp = &nvs->general_params;
|
struct wl1271_ini_general_params *gp = &nvs->general_params;
|
||||||
int ret;
|
int ret, fem_idx;
|
||||||
|
|
||||||
if (!wl->nvs)
|
if (!wl->nvs)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
@ -185,11 +185,13 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
|
||||||
|
|
||||||
radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
|
radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
|
||||||
|
|
||||||
|
fem_idx = WL12XX_FEM_TO_NVS_ENTRY(gp->tx_bip_fem_manufacturer);
|
||||||
|
|
||||||
/* 2.4GHz parameters */
|
/* 2.4GHz parameters */
|
||||||
memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
|
memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
|
||||||
sizeof(struct wl1271_ini_band_params_2));
|
sizeof(struct wl1271_ini_band_params_2));
|
||||||
memcpy(&radio_parms->dyn_params_2,
|
memcpy(&radio_parms->dyn_params_2,
|
||||||
&nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
|
&nvs->dyn_radio_params_2[fem_idx].params,
|
||||||
sizeof(struct wl1271_ini_fem_params_2));
|
sizeof(struct wl1271_ini_fem_params_2));
|
||||||
|
|
||||||
/* 5GHz parameters */
|
/* 5GHz parameters */
|
||||||
|
@ -197,7 +199,7 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
|
||||||
&nvs->stat_radio_params_5,
|
&nvs->stat_radio_params_5,
|
||||||
sizeof(struct wl1271_ini_band_params_5));
|
sizeof(struct wl1271_ini_band_params_5));
|
||||||
memcpy(&radio_parms->dyn_params_5,
|
memcpy(&radio_parms->dyn_params_5,
|
||||||
&nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
|
&nvs->dyn_radio_params_5[fem_idx].params,
|
||||||
sizeof(struct wl1271_ini_fem_params_5));
|
sizeof(struct wl1271_ini_fem_params_5));
|
||||||
|
|
||||||
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
|
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
|
||||||
|
@ -216,7 +218,7 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl)
|
||||||
struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;
|
struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;
|
||||||
struct wl128x_radio_parms_cmd *radio_parms;
|
struct wl128x_radio_parms_cmd *radio_parms;
|
||||||
struct wl128x_ini_general_params *gp = &nvs->general_params;
|
struct wl128x_ini_general_params *gp = &nvs->general_params;
|
||||||
int ret;
|
int ret, fem_idx;
|
||||||
|
|
||||||
if (!wl->nvs)
|
if (!wl->nvs)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
@ -227,11 +229,13 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl)
|
||||||
|
|
||||||
radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
|
radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
|
||||||
|
|
||||||
|
fem_idx = WL12XX_FEM_TO_NVS_ENTRY(gp->tx_bip_fem_manufacturer);
|
||||||
|
|
||||||
/* 2.4GHz parameters */
|
/* 2.4GHz parameters */
|
||||||
memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
|
memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
|
||||||
sizeof(struct wl128x_ini_band_params_2));
|
sizeof(struct wl128x_ini_band_params_2));
|
||||||
memcpy(&radio_parms->dyn_params_2,
|
memcpy(&radio_parms->dyn_params_2,
|
||||||
&nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
|
&nvs->dyn_radio_params_2[fem_idx].params,
|
||||||
sizeof(struct wl128x_ini_fem_params_2));
|
sizeof(struct wl128x_ini_fem_params_2));
|
||||||
|
|
||||||
/* 5GHz parameters */
|
/* 5GHz parameters */
|
||||||
|
@ -239,7 +243,7 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl)
|
||||||
&nvs->stat_radio_params_5,
|
&nvs->stat_radio_params_5,
|
||||||
sizeof(struct wl128x_ini_band_params_5));
|
sizeof(struct wl128x_ini_band_params_5));
|
||||||
memcpy(&radio_parms->dyn_params_5,
|
memcpy(&radio_parms->dyn_params_5,
|
||||||
&nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
|
&nvs->dyn_radio_params_5[fem_idx].params,
|
||||||
sizeof(struct wl128x_ini_fem_params_5));
|
sizeof(struct wl128x_ini_fem_params_5));
|
||||||
|
|
||||||
radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options;
|
radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options;
|
||||||
|
|
|
@ -246,6 +246,7 @@ static struct wlcore_conf wl12xx_conf = {
|
||||||
.forced_ps = false,
|
.forced_ps = false,
|
||||||
.keep_alive_interval = 55000,
|
.keep_alive_interval = 55000,
|
||||||
.max_listen_interval = 20,
|
.max_listen_interval = 20,
|
||||||
|
.sta_sleep_auth = WL1271_PSM_ILLEGAL,
|
||||||
},
|
},
|
||||||
.itrim = {
|
.itrim = {
|
||||||
.enable = false,
|
.enable = false,
|
||||||
|
@ -1448,10 +1449,8 @@ static int __devinit wl12xx_probe(struct platform_device *pdev)
|
||||||
wl->hw_min_ht_rate = WL12XX_CONF_HW_RXTX_RATE_MCS0;
|
wl->hw_min_ht_rate = WL12XX_CONF_HW_RXTX_RATE_MCS0;
|
||||||
wl->fw_status_priv_len = 0;
|
wl->fw_status_priv_len = 0;
|
||||||
wl->stats.fw_stats_len = sizeof(struct wl12xx_acx_statistics);
|
wl->stats.fw_stats_len = sizeof(struct wl12xx_acx_statistics);
|
||||||
memcpy(&wl->ht_cap[IEEE80211_BAND_2GHZ], &wl12xx_ht_cap,
|
wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ, &wl12xx_ht_cap);
|
||||||
sizeof(wl12xx_ht_cap));
|
wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ, &wl12xx_ht_cap);
|
||||||
memcpy(&wl->ht_cap[IEEE80211_BAND_5GHZ], &wl12xx_ht_cap,
|
|
||||||
sizeof(wl12xx_ht_cap));
|
|
||||||
wl12xx_conf_init(wl);
|
wl12xx_conf_init(wl);
|
||||||
|
|
||||||
if (!fref_param) {
|
if (!fref_param) {
|
||||||
|
|
|
@ -43,10 +43,11 @@
|
||||||
|
|
||||||
#define WL18XX_RX_CHECKSUM_MASK 0x40
|
#define WL18XX_RX_CHECKSUM_MASK 0x40
|
||||||
|
|
||||||
static char *ht_mode_param = "wide";
|
static char *ht_mode_param = "default";
|
||||||
static char *board_type_param = "hdk";
|
static char *board_type_param = "hdk";
|
||||||
static bool checksum_param = false;
|
static bool checksum_param = false;
|
||||||
static bool enable_11a_param = true;
|
static bool enable_11a_param = true;
|
||||||
|
static int num_rx_desc_param = -1;
|
||||||
|
|
||||||
/* phy paramters */
|
/* phy paramters */
|
||||||
static int dc2dc_param = -1;
|
static int dc2dc_param = -1;
|
||||||
|
@ -372,6 +373,7 @@ static struct wlcore_conf wl18xx_conf = {
|
||||||
.forced_ps = false,
|
.forced_ps = false,
|
||||||
.keep_alive_interval = 55000,
|
.keep_alive_interval = 55000,
|
||||||
.max_listen_interval = 20,
|
.max_listen_interval = 20,
|
||||||
|
.sta_sleep_auth = WL1271_PSM_ILLEGAL,
|
||||||
},
|
},
|
||||||
.itrim = {
|
.itrim = {
|
||||||
.enable = false,
|
.enable = false,
|
||||||
|
@ -606,8 +608,8 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
|
||||||
wl->plt_fw_name = WL18XX_FW_NAME;
|
wl->plt_fw_name = WL18XX_FW_NAME;
|
||||||
wl->quirks |= WLCORE_QUIRK_NO_ELP |
|
wl->quirks |= WLCORE_QUIRK_NO_ELP |
|
||||||
WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN |
|
WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN |
|
||||||
|
WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
|
||||||
WLCORE_QUIRK_TX_PAD_LAST_FRAME;
|
WLCORE_QUIRK_TX_PAD_LAST_FRAME;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case CHIP_ID_185x_PG10:
|
case CHIP_ID_185x_PG10:
|
||||||
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (185x PG10)",
|
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (185x PG10)",
|
||||||
|
@ -1021,8 +1023,7 @@ static int wl18xx_conf_init(struct wl1271 *wl, struct device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fw->size != WL18XX_CONF_SIZE) {
|
if (fw->size != WL18XX_CONF_SIZE) {
|
||||||
wl1271_error("configuration binary file size is wrong, "
|
wl1271_error("configuration binary file size is wrong, expected %zu got %zu",
|
||||||
"expected %ld got %zd",
|
|
||||||
WL18XX_CONF_SIZE, fw->size);
|
WL18XX_CONF_SIZE, fw->size);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1214,8 +1215,8 @@ static struct wlcore_ops wl18xx_ops = {
|
||||||
.pre_pkt_send = wl18xx_pre_pkt_send,
|
.pre_pkt_send = wl18xx_pre_pkt_send,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* HT cap appropriate for wide channels */
|
/* HT cap appropriate for wide channels in 2Ghz */
|
||||||
static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap = {
|
static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_2ghz = {
|
||||||
.cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
|
.cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
|
||||||
IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40,
|
IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40,
|
||||||
.ht_supported = true,
|
.ht_supported = true,
|
||||||
|
@ -1228,6 +1229,20 @@ static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* HT cap appropriate for wide channels in 5Ghz */
|
||||||
|
static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_5ghz = {
|
||||||
|
.cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
|
||||||
|
IEEE80211_HT_CAP_SUP_WIDTH_20_40,
|
||||||
|
.ht_supported = true,
|
||||||
|
.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
|
||||||
|
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
|
||||||
|
.mcs = {
|
||||||
|
.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
|
||||||
|
.rx_highest = cpu_to_le16(150),
|
||||||
|
.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/* HT cap appropriate for SISO 20 */
|
/* HT cap appropriate for SISO 20 */
|
||||||
static struct ieee80211_sta_ht_cap wl18xx_siso20_ht_cap = {
|
static struct ieee80211_sta_ht_cap wl18xx_siso20_ht_cap = {
|
||||||
.cap = IEEE80211_HT_CAP_SGI_20,
|
.cap = IEEE80211_HT_CAP_SGI_20,
|
||||||
|
@ -1254,18 +1269,6 @@ static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_5ghz = {
|
|
||||||
.cap = IEEE80211_HT_CAP_SGI_20,
|
|
||||||
.ht_supported = true,
|
|
||||||
.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
|
|
||||||
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
|
|
||||||
.mcs = {
|
|
||||||
.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
|
|
||||||
.rx_highest = cpu_to_le16(72),
|
|
||||||
.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static int __devinit wl18xx_probe(struct platform_device *pdev)
|
static int __devinit wl18xx_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct wl1271 *wl;
|
struct wl1271 *wl;
|
||||||
|
@ -1286,7 +1289,7 @@ static int __devinit wl18xx_probe(struct platform_device *pdev)
|
||||||
wl->ptable = wl18xx_ptable;
|
wl->ptable = wl18xx_ptable;
|
||||||
wl->rtable = wl18xx_rtable;
|
wl->rtable = wl18xx_rtable;
|
||||||
wl->num_tx_desc = 32;
|
wl->num_tx_desc = 32;
|
||||||
wl->num_rx_desc = 16;
|
wl->num_rx_desc = 32;
|
||||||
wl->band_rate_to_idx = wl18xx_band_rate_to_idx;
|
wl->band_rate_to_idx = wl18xx_band_rate_to_idx;
|
||||||
wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX;
|
wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX;
|
||||||
wl->hw_min_ht_rate = WL18XX_CONF_HW_RXTX_RATE_MCS0;
|
wl->hw_min_ht_rate = WL18XX_CONF_HW_RXTX_RATE_MCS0;
|
||||||
|
@ -1294,32 +1297,8 @@ static int __devinit wl18xx_probe(struct platform_device *pdev)
|
||||||
wl->stats.fw_stats_len = sizeof(struct wl18xx_acx_statistics);
|
wl->stats.fw_stats_len = sizeof(struct wl18xx_acx_statistics);
|
||||||
wl->static_data_priv_len = sizeof(struct wl18xx_static_data_priv);
|
wl->static_data_priv_len = sizeof(struct wl18xx_static_data_priv);
|
||||||
|
|
||||||
if (!strcmp(ht_mode_param, "wide")) {
|
if (num_rx_desc_param != -1)
|
||||||
memcpy(&wl->ht_cap[IEEE80211_BAND_2GHZ],
|
wl->num_rx_desc = num_rx_desc_param;
|
||||||
&wl18xx_siso40_ht_cap,
|
|
||||||
sizeof(wl18xx_siso40_ht_cap));
|
|
||||||
memcpy(&wl->ht_cap[IEEE80211_BAND_5GHZ],
|
|
||||||
&wl18xx_siso40_ht_cap,
|
|
||||||
sizeof(wl18xx_siso40_ht_cap));
|
|
||||||
} else if (!strcmp(ht_mode_param, "mimo")) {
|
|
||||||
memcpy(&wl->ht_cap[IEEE80211_BAND_2GHZ],
|
|
||||||
&wl18xx_mimo_ht_cap_2ghz,
|
|
||||||
sizeof(wl18xx_mimo_ht_cap_2ghz));
|
|
||||||
memcpy(&wl->ht_cap[IEEE80211_BAND_5GHZ],
|
|
||||||
&wl18xx_mimo_ht_cap_5ghz,
|
|
||||||
sizeof(wl18xx_mimo_ht_cap_5ghz));
|
|
||||||
} else if (!strcmp(ht_mode_param, "siso20")) {
|
|
||||||
memcpy(&wl->ht_cap[IEEE80211_BAND_2GHZ],
|
|
||||||
&wl18xx_siso20_ht_cap,
|
|
||||||
sizeof(wl18xx_siso20_ht_cap));
|
|
||||||
memcpy(&wl->ht_cap[IEEE80211_BAND_5GHZ],
|
|
||||||
&wl18xx_siso20_ht_cap,
|
|
||||||
sizeof(wl18xx_siso20_ht_cap));
|
|
||||||
} else {
|
|
||||||
wl1271_error("invalid ht_mode '%s'", ht_mode_param);
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto out_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = wl18xx_conf_init(wl, &pdev->dev);
|
ret = wl18xx_conf_init(wl, &pdev->dev);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -1366,6 +1345,37 @@ static int __devinit wl18xx_probe(struct platform_device *pdev)
|
||||||
if (dc2dc_param != -1)
|
if (dc2dc_param != -1)
|
||||||
priv->conf.phy.external_pa_dc2dc = dc2dc_param;
|
priv->conf.phy.external_pa_dc2dc = dc2dc_param;
|
||||||
|
|
||||||
|
if (!strcmp(ht_mode_param, "default")) {
|
||||||
|
/*
|
||||||
|
* Only support mimo with multiple antennas. Fall back to
|
||||||
|
* siso20.
|
||||||
|
*/
|
||||||
|
if (priv->conf.phy.number_of_assembled_ant2_4 >= 2)
|
||||||
|
wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
|
||||||
|
&wl18xx_mimo_ht_cap_2ghz);
|
||||||
|
else
|
||||||
|
wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
|
||||||
|
&wl18xx_siso20_ht_cap);
|
||||||
|
|
||||||
|
/* 5Ghz is always wide */
|
||||||
|
wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ,
|
||||||
|
&wl18xx_siso40_ht_cap_5ghz);
|
||||||
|
} else if (!strcmp(ht_mode_param, "wide")) {
|
||||||
|
wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
|
||||||
|
&wl18xx_siso40_ht_cap_2ghz);
|
||||||
|
wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ,
|
||||||
|
&wl18xx_siso40_ht_cap_5ghz);
|
||||||
|
} else if (!strcmp(ht_mode_param, "siso20")) {
|
||||||
|
wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
|
||||||
|
&wl18xx_siso20_ht_cap);
|
||||||
|
wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ,
|
||||||
|
&wl18xx_siso20_ht_cap);
|
||||||
|
} else {
|
||||||
|
wl1271_error("invalid ht_mode '%s'", ht_mode_param);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
if (!checksum_param) {
|
if (!checksum_param) {
|
||||||
wl18xx_ops.set_rx_csum = NULL;
|
wl18xx_ops.set_rx_csum = NULL;
|
||||||
wl18xx_ops.init_vif = NULL;
|
wl18xx_ops.init_vif = NULL;
|
||||||
|
@ -1410,7 +1420,7 @@ static void __exit wl18xx_exit(void)
|
||||||
module_exit(wl18xx_exit);
|
module_exit(wl18xx_exit);
|
||||||
|
|
||||||
module_param_named(ht_mode, ht_mode_param, charp, S_IRUSR);
|
module_param_named(ht_mode, ht_mode_param, charp, S_IRUSR);
|
||||||
MODULE_PARM_DESC(ht_mode, "Force HT mode: wide (default), mimo or siso20");
|
MODULE_PARM_DESC(ht_mode, "Force HT mode: wide or siso20");
|
||||||
|
|
||||||
module_param_named(board_type, board_type_param, charp, S_IRUSR);
|
module_param_named(board_type, board_type_param, charp, S_IRUSR);
|
||||||
MODULE_PARM_DESC(board_type, "Board type: fpga, hdk (default), evb, com8 or "
|
MODULE_PARM_DESC(board_type, "Board type: fpga, hdk (default), evb, com8 or "
|
||||||
|
@ -1458,6 +1468,11 @@ module_param_named(pwr_limit_reference_11_abg,
|
||||||
MODULE_PARM_DESC(pwr_limit_reference_11_abg, "Power limit reference: u8 "
|
MODULE_PARM_DESC(pwr_limit_reference_11_abg, "Power limit reference: u8 "
|
||||||
"(default is 0xc8)");
|
"(default is 0xc8)");
|
||||||
|
|
||||||
|
module_param_named(num_rx_desc,
|
||||||
|
num_rx_desc_param, int, S_IRUSR);
|
||||||
|
MODULE_PARM_DESC(num_rx_desc_param,
|
||||||
|
"Number of Rx descriptors: u8 (default is 32)");
|
||||||
|
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
|
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
|
||||||
MODULE_FIRMWARE(WL18XX_FW_NAME);
|
MODULE_FIRMWARE(WL18XX_FW_NAME);
|
||||||
|
|
|
@ -70,7 +70,7 @@ int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth)
|
||||||
struct acx_sleep_auth *auth;
|
struct acx_sleep_auth *auth;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
wl1271_debug(DEBUG_ACX, "acx sleep auth");
|
wl1271_debug(DEBUG_ACX, "acx sleep auth %d", sleep_auth);
|
||||||
|
|
||||||
auth = kzalloc(sizeof(*auth), GFP_KERNEL);
|
auth = kzalloc(sizeof(*auth), GFP_KERNEL);
|
||||||
if (!auth) {
|
if (!auth) {
|
||||||
|
@ -81,7 +81,13 @@ int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth)
|
||||||
auth->sleep_auth = sleep_auth;
|
auth->sleep_auth = sleep_auth;
|
||||||
|
|
||||||
ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth));
|
ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth));
|
||||||
|
if (ret < 0) {
|
||||||
|
wl1271_error("could not configure sleep_auth to %d: %d",
|
||||||
|
sleep_auth, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl->sleep_auth = sleep_auth;
|
||||||
out:
|
out:
|
||||||
kfree(auth);
|
kfree(auth);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -118,6 +118,11 @@ enum wl1271_psm_mode {
|
||||||
|
|
||||||
/* Extreme low power */
|
/* Extreme low power */
|
||||||
WL1271_PSM_ELP = 2,
|
WL1271_PSM_ELP = 2,
|
||||||
|
|
||||||
|
WL1271_PSM_MAX = WL1271_PSM_ELP,
|
||||||
|
|
||||||
|
/* illegal out of band value of PSM mode */
|
||||||
|
WL1271_PSM_ILLEGAL = 0xff
|
||||||
};
|
};
|
||||||
|
|
||||||
struct acx_sleep_auth {
|
struct acx_sleep_auth {
|
||||||
|
|
|
@ -652,4 +652,25 @@ struct wl12xx_cmd_stop_channel_switch {
|
||||||
struct wl1271_cmd_header header;
|
struct wl1271_cmd_header header;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
/* Used to check radio status after calibration */
|
||||||
|
#define MAX_TLV_LENGTH 500
|
||||||
|
#define TEST_CMD_P2G_CAL 2 /* TX BiP */
|
||||||
|
|
||||||
|
struct wl1271_cmd_cal_p2g {
|
||||||
|
struct wl1271_cmd_header header;
|
||||||
|
|
||||||
|
struct wl1271_cmd_test_header test;
|
||||||
|
|
||||||
|
__le32 ver;
|
||||||
|
__le16 len;
|
||||||
|
u8 buf[MAX_TLV_LENGTH];
|
||||||
|
u8 type;
|
||||||
|
u8 padding;
|
||||||
|
|
||||||
|
__le16 radio_status;
|
||||||
|
|
||||||
|
u8 sub_band_mask;
|
||||||
|
u8 padding2;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
#endif /* __WL1271_CMD_H__ */
|
#endif /* __WL1271_CMD_H__ */
|
||||||
|
|
|
@ -951,6 +951,12 @@ struct conf_conn_settings {
|
||||||
* Range: u16
|
* Range: u16
|
||||||
*/
|
*/
|
||||||
u8 max_listen_interval;
|
u8 max_listen_interval;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default sleep authorization for a new STA interface. This determines
|
||||||
|
* whether we can go to ELP.
|
||||||
|
*/
|
||||||
|
u8 sta_sleep_auth;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -1276,7 +1282,7 @@ struct conf_hangover_settings {
|
||||||
* version, the two LSB are the lower driver's private conf
|
* version, the two LSB are the lower driver's private conf
|
||||||
* version.
|
* version.
|
||||||
*/
|
*/
|
||||||
#define WLCORE_CONF_VERSION (0x0001 << 16)
|
#define WLCORE_CONF_VERSION (0x0002 << 16)
|
||||||
#define WLCORE_CONF_MASK 0xffff0000
|
#define WLCORE_CONF_MASK 0xffff0000
|
||||||
#define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \
|
#define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \
|
||||||
sizeof(struct wlcore_conf))
|
sizeof(struct wlcore_conf))
|
||||||
|
|
|
@ -963,6 +963,68 @@ static const struct file_operations fw_stats_raw_ops = {
|
||||||
.llseek = default_llseek,
|
.llseek = default_llseek,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static ssize_t sleep_auth_read(struct file *file, char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct wl1271 *wl = file->private_data;
|
||||||
|
|
||||||
|
return wl1271_format_buffer(user_buf, count,
|
||||||
|
ppos, "%d\n",
|
||||||
|
wl->sleep_auth);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t sleep_auth_write(struct file *file,
|
||||||
|
const char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct wl1271 *wl = file->private_data;
|
||||||
|
unsigned long value;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = kstrtoul_from_user(user_buf, count, 0, &value);
|
||||||
|
if (ret < 0) {
|
||||||
|
wl1271_warning("illegal value in sleep_auth");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value < 0 || value > WL1271_PSM_MAX) {
|
||||||
|
wl1271_warning("sleep_auth must be between 0 and %d",
|
||||||
|
WL1271_PSM_MAX);
|
||||||
|
return -ERANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&wl->mutex);
|
||||||
|
|
||||||
|
wl->conf.conn.sta_sleep_auth = value;
|
||||||
|
|
||||||
|
if (wl->state == WL1271_STATE_OFF) {
|
||||||
|
/* this will show up on "read" in case we are off */
|
||||||
|
wl->sleep_auth = value;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = wl1271_ps_elp_wakeup(wl);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = wl1271_acx_sleep_auth(wl, value);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out_sleep;
|
||||||
|
|
||||||
|
out_sleep:
|
||||||
|
wl1271_ps_elp_sleep(wl);
|
||||||
|
out:
|
||||||
|
mutex_unlock(&wl->mutex);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations sleep_auth_ops = {
|
||||||
|
.read = sleep_auth_read,
|
||||||
|
.write = sleep_auth_write,
|
||||||
|
.open = simple_open,
|
||||||
|
.llseek = default_llseek,
|
||||||
|
};
|
||||||
|
|
||||||
static int wl1271_debugfs_add_files(struct wl1271 *wl,
|
static int wl1271_debugfs_add_files(struct wl1271 *wl,
|
||||||
struct dentry *rootdir)
|
struct dentry *rootdir)
|
||||||
{
|
{
|
||||||
|
@ -988,6 +1050,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
|
||||||
DEBUGFS_ADD(irq_blk_threshold, rootdir);
|
DEBUGFS_ADD(irq_blk_threshold, rootdir);
|
||||||
DEBUGFS_ADD(irq_timeout, rootdir);
|
DEBUGFS_ADD(irq_timeout, rootdir);
|
||||||
DEBUGFS_ADD(fw_stats_raw, rootdir);
|
DEBUGFS_ADD(fw_stats_raw, rootdir);
|
||||||
|
DEBUGFS_ADD(sleep_auth, rootdir);
|
||||||
|
|
||||||
streaming = debugfs_create_dir("rx_streaming", rootdir);
|
streaming = debugfs_create_dir("rx_streaming", rootdir);
|
||||||
if (!streaming || IS_ERR(streaming))
|
if (!streaming || IS_ERR(streaming))
|
||||||
|
|
|
@ -172,7 +172,19 @@ struct wl128x_ini_fem_params_5 {
|
||||||
|
|
||||||
/* NVS data structure */
|
/* NVS data structure */
|
||||||
#define WL1271_INI_NVS_SECTION_SIZE 468
|
#define WL1271_INI_NVS_SECTION_SIZE 468
|
||||||
#define WL1271_INI_FEM_MODULE_COUNT 2
|
|
||||||
|
/* We have four FEM module types: 0-RFMD, 1-TQS, 2-SKW, 3-TQS_HP */
|
||||||
|
#define WL1271_INI_FEM_MODULE_COUNT 4
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In NVS we only store two FEM module entries -
|
||||||
|
* FEM modules 0,2,3 are stored in entry 0
|
||||||
|
* FEM module 1 is stored in entry 1
|
||||||
|
*/
|
||||||
|
#define WL12XX_NVS_FEM_MODULE_COUNT 2
|
||||||
|
|
||||||
|
#define WL12XX_FEM_TO_NVS_ENTRY(ini_fem_module) \
|
||||||
|
((ini_fem_module) == 1 ? 1 : 0)
|
||||||
|
|
||||||
#define WL1271_INI_LEGACY_NVS_FILE_SIZE 800
|
#define WL1271_INI_LEGACY_NVS_FILE_SIZE 800
|
||||||
|
|
||||||
|
@ -188,13 +200,13 @@ struct wl1271_nvs_file {
|
||||||
struct {
|
struct {
|
||||||
struct wl1271_ini_fem_params_2 params;
|
struct wl1271_ini_fem_params_2 params;
|
||||||
u8 padding;
|
u8 padding;
|
||||||
} dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT];
|
} dyn_radio_params_2[WL12XX_NVS_FEM_MODULE_COUNT];
|
||||||
struct wl1271_ini_band_params_5 stat_radio_params_5;
|
struct wl1271_ini_band_params_5 stat_radio_params_5;
|
||||||
u8 padding3;
|
u8 padding3;
|
||||||
struct {
|
struct {
|
||||||
struct wl1271_ini_fem_params_5 params;
|
struct wl1271_ini_fem_params_5 params;
|
||||||
u8 padding;
|
u8 padding;
|
||||||
} dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT];
|
} dyn_radio_params_5[WL12XX_NVS_FEM_MODULE_COUNT];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
struct wl128x_nvs_file {
|
struct wl128x_nvs_file {
|
||||||
|
@ -209,12 +221,12 @@ struct wl128x_nvs_file {
|
||||||
struct {
|
struct {
|
||||||
struct wl128x_ini_fem_params_2 params;
|
struct wl128x_ini_fem_params_2 params;
|
||||||
u8 padding;
|
u8 padding;
|
||||||
} dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT];
|
} dyn_radio_params_2[WL12XX_NVS_FEM_MODULE_COUNT];
|
||||||
struct wl128x_ini_band_params_5 stat_radio_params_5;
|
struct wl128x_ini_band_params_5 stat_radio_params_5;
|
||||||
u8 padding3;
|
u8 padding3;
|
||||||
struct {
|
struct {
|
||||||
struct wl128x_ini_fem_params_5 params;
|
struct wl128x_ini_fem_params_5 params;
|
||||||
u8 padding;
|
u8 padding;
|
||||||
} dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT];
|
} dyn_radio_params_5[WL12XX_NVS_FEM_MODULE_COUNT];
|
||||||
} __packed;
|
} __packed;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -554,30 +554,29 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
|
||||||
bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
|
bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
/*
|
/* consider all existing roles before configuring psm. */
|
||||||
* consider all existing roles before configuring psm.
|
|
||||||
* TODO: reconfigure on interface removal.
|
if (wl->ap_count == 0 && is_ap) { /* first AP */
|
||||||
*/
|
|
||||||
if (!wl->ap_count) {
|
|
||||||
if (is_ap) {
|
|
||||||
/* Configure for power always on */
|
/* Configure for power always on */
|
||||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
|
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
} else if (!wl->sta_count) {
|
/* first STA, no APs */
|
||||||
if (wl->quirks & WLCORE_QUIRK_NO_ELP) {
|
} else if (wl->sta_count == 0 && wl->ap_count == 0 && !is_ap) {
|
||||||
|
u8 sta_auth = wl->conf.conn.sta_sleep_auth;
|
||||||
|
/* Configure for power according to debugfs */
|
||||||
|
if (sta_auth != WL1271_PSM_ILLEGAL)
|
||||||
|
ret = wl1271_acx_sleep_auth(wl, sta_auth);
|
||||||
/* Configure for power always on */
|
/* Configure for power always on */
|
||||||
|
else if (wl->quirks & WLCORE_QUIRK_NO_ELP)
|
||||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
|
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
} else {
|
|
||||||
/* Configure for ELP power saving */
|
/* Configure for ELP power saving */
|
||||||
|
else
|
||||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
|
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mode specific init */
|
/* Mode specific init */
|
||||||
if (is_ap) {
|
if (is_ap) {
|
||||||
|
|
|
@ -770,14 +770,16 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define WLCORE_FW_LOG_END 0x2000000
|
||||||
|
|
||||||
static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
|
static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
|
||||||
{
|
{
|
||||||
u32 addr;
|
u32 addr;
|
||||||
u32 first_addr;
|
u32 offset;
|
||||||
|
u32 end_of_log;
|
||||||
u8 *block;
|
u8 *block;
|
||||||
|
|
||||||
if ((wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
|
if ((wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
|
||||||
(wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
|
|
||||||
(wl->conf.fwlog.mem_blocks == 0))
|
(wl->conf.fwlog.mem_blocks == 0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -791,19 +793,26 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
|
||||||
* Make sure the chip is awake and the logger isn't active.
|
* Make sure the chip is awake and the logger isn't active.
|
||||||
* Do not send a stop fwlog command if the fw is hanged.
|
* Do not send a stop fwlog command if the fw is hanged.
|
||||||
*/
|
*/
|
||||||
if (!wl1271_ps_elp_wakeup(wl) && !wl->watchdog_recovery)
|
if (wl1271_ps_elp_wakeup(wl))
|
||||||
wl12xx_cmd_stop_fwlog(wl);
|
|
||||||
else
|
|
||||||
goto out;
|
goto out;
|
||||||
|
if (!wl->watchdog_recovery)
|
||||||
|
wl12xx_cmd_stop_fwlog(wl);
|
||||||
|
|
||||||
/* Read the first memory block address */
|
/* Read the first memory block address */
|
||||||
wl12xx_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
|
wl12xx_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
|
||||||
first_addr = le32_to_cpu(wl->fw_status_2->log_start_addr);
|
addr = le32_to_cpu(wl->fw_status_2->log_start_addr);
|
||||||
if (!first_addr)
|
if (!addr)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (wl->conf.fwlog.mode == WL12XX_FWLOG_CONTINUOUS) {
|
||||||
|
offset = sizeof(addr) + sizeof(struct wl1271_rx_descriptor);
|
||||||
|
end_of_log = WLCORE_FW_LOG_END;
|
||||||
|
} else {
|
||||||
|
offset = sizeof(addr);
|
||||||
|
end_of_log = addr;
|
||||||
|
}
|
||||||
|
|
||||||
/* Traverse the memory blocks linked list */
|
/* Traverse the memory blocks linked list */
|
||||||
addr = first_addr;
|
|
||||||
do {
|
do {
|
||||||
memset(block, 0, WL12XX_HW_BLOCK_SIZE);
|
memset(block, 0, WL12XX_HW_BLOCK_SIZE);
|
||||||
wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
|
wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
|
||||||
|
@ -812,13 +821,14 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
|
||||||
/*
|
/*
|
||||||
* Memory blocks are linked to one another. The first 4 bytes
|
* Memory blocks are linked to one another. The first 4 bytes
|
||||||
* of each memory block hold the hardware address of the next
|
* of each memory block hold the hardware address of the next
|
||||||
* one. The last memory block points to the first one.
|
* one. The last memory block points to the first one in
|
||||||
|
* on demand mode and is equal to 0x2000000 in continuous mode.
|
||||||
*/
|
*/
|
||||||
addr = le32_to_cpup((__le32 *)block);
|
addr = le32_to_cpup((__le32 *)block);
|
||||||
if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
|
if (!wl12xx_copy_fwlog(wl, block + offset,
|
||||||
WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
|
WL12XX_HW_BLOCK_SIZE - offset))
|
||||||
break;
|
break;
|
||||||
} while (addr && (addr != first_addr));
|
} while (addr && (addr != end_of_log));
|
||||||
|
|
||||||
wake_up_interruptible(&wl->fwlog_waitq);
|
wake_up_interruptible(&wl->fwlog_waitq);
|
||||||
|
|
||||||
|
@ -1082,6 +1092,7 @@ int wl1271_plt_stop(struct wl1271 *wl)
|
||||||
mutex_lock(&wl->mutex);
|
mutex_lock(&wl->mutex);
|
||||||
wl1271_power_off(wl);
|
wl1271_power_off(wl);
|
||||||
wl->flags = 0;
|
wl->flags = 0;
|
||||||
|
wl->sleep_auth = WL1271_PSM_ILLEGAL;
|
||||||
wl->state = WL1271_STATE_OFF;
|
wl->state = WL1271_STATE_OFF;
|
||||||
wl->plt = false;
|
wl->plt = false;
|
||||||
wl->rx_counter = 0;
|
wl->rx_counter = 0;
|
||||||
|
@ -1740,6 +1751,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
|
||||||
wl->ap_fw_ps_map = 0;
|
wl->ap_fw_ps_map = 0;
|
||||||
wl->ap_ps_map = 0;
|
wl->ap_ps_map = 0;
|
||||||
wl->sched_scanning = false;
|
wl->sched_scanning = false;
|
||||||
|
wl->sleep_auth = WL1271_PSM_ILLEGAL;
|
||||||
memset(wl->roles_map, 0, sizeof(wl->roles_map));
|
memset(wl->roles_map, 0, sizeof(wl->roles_map));
|
||||||
memset(wl->links_map, 0, sizeof(wl->links_map));
|
memset(wl->links_map, 0, sizeof(wl->links_map));
|
||||||
memset(wl->roc_map, 0, sizeof(wl->roc_map));
|
memset(wl->roc_map, 0, sizeof(wl->roc_map));
|
||||||
|
@ -2146,6 +2158,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
|
||||||
{
|
{
|
||||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
|
||||||
|
|
||||||
wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
|
wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
|
||||||
|
|
||||||
|
@ -2226,11 +2239,25 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
|
||||||
wlvif->role_id = WL12XX_INVALID_ROLE_ID;
|
wlvif->role_id = WL12XX_INVALID_ROLE_ID;
|
||||||
wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
|
wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
|
||||||
|
|
||||||
if (wlvif->bss_type == BSS_TYPE_AP_BSS)
|
if (is_ap)
|
||||||
wl->ap_count--;
|
wl->ap_count--;
|
||||||
else
|
else
|
||||||
wl->sta_count--;
|
wl->sta_count--;
|
||||||
|
|
||||||
|
/* Last AP, have more stations. Configure according to STA. */
|
||||||
|
if (wl->ap_count == 0 && is_ap && wl->sta_count) {
|
||||||
|
u8 sta_auth = wl->conf.conn.sta_sleep_auth;
|
||||||
|
/* Configure for power according to debugfs */
|
||||||
|
if (sta_auth != WL1271_PSM_ILLEGAL)
|
||||||
|
wl1271_acx_sleep_auth(wl, sta_auth);
|
||||||
|
/* Configure for power always on */
|
||||||
|
else if (wl->quirks & WLCORE_QUIRK_NO_ELP)
|
||||||
|
wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
|
||||||
|
/* Configure for ELP power saving */
|
||||||
|
else
|
||||||
|
wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
|
||||||
|
}
|
||||||
|
|
||||||
mutex_unlock(&wl->mutex);
|
mutex_unlock(&wl->mutex);
|
||||||
|
|
||||||
del_timer_sync(&wlvif->rx_streaming_timer);
|
del_timer_sync(&wlvif->rx_streaming_timer);
|
||||||
|
@ -2454,6 +2481,7 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||||
wlvif->channel_type = conf->channel_type;
|
wlvif->channel_type = conf->channel_type;
|
||||||
|
|
||||||
if (is_ap) {
|
if (is_ap) {
|
||||||
|
wl1271_set_band_rate(wl, wlvif);
|
||||||
ret = wl1271_init_ap_rates(wl, wlvif);
|
ret = wl1271_init_ap_rates(wl, wlvif);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
wl1271_error("AP rate policy change failed %d",
|
wl1271_error("AP rate policy change failed %d",
|
||||||
|
@ -4090,16 +4118,13 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
|
||||||
static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
|
static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
|
||||||
struct survey_info *survey)
|
struct survey_info *survey)
|
||||||
{
|
{
|
||||||
struct wl1271 *wl = hw->priv;
|
|
||||||
struct ieee80211_conf *conf = &hw->conf;
|
struct ieee80211_conf *conf = &hw->conf;
|
||||||
|
|
||||||
if (idx != 0)
|
if (idx != 0)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
survey->channel = conf->channel;
|
survey->channel = conf->channel;
|
||||||
survey->filled = SURVEY_INFO_NOISE_DBM;
|
survey->filled = 0;
|
||||||
survey->noise = wl->noise;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4365,9 +4390,14 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
|
||||||
|
|
||||||
case IEEE80211_AMPDU_RX_STOP:
|
case IEEE80211_AMPDU_RX_STOP:
|
||||||
if (!(*ba_bitmap & BIT(tid))) {
|
if (!(*ba_bitmap & BIT(tid))) {
|
||||||
ret = -EINVAL;
|
/*
|
||||||
wl1271_error("no active RX BA session on tid: %d",
|
* this happens on reconfig - so only output a debug
|
||||||
|
* message for now, and don't fail the function.
|
||||||
|
*/
|
||||||
|
wl1271_debug(DEBUG_MAC80211,
|
||||||
|
"no active RX BA session on tid: %d",
|
||||||
tid);
|
tid);
|
||||||
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4976,6 +5006,29 @@ static void wl1271_unregister_hw(struct wl1271 *wl)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct ieee80211_iface_limit wlcore_iface_limits[] = {
|
||||||
|
{
|
||||||
|
.max = 2,
|
||||||
|
.types = BIT(NL80211_IFTYPE_STATION),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.max = 1,
|
||||||
|
.types = BIT(NL80211_IFTYPE_AP) |
|
||||||
|
BIT(NL80211_IFTYPE_P2P_GO) |
|
||||||
|
BIT(NL80211_IFTYPE_P2P_CLIENT),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct ieee80211_iface_combination
|
||||||
|
wlcore_iface_combinations[] = {
|
||||||
|
{
|
||||||
|
.num_different_channels = 1,
|
||||||
|
.max_interfaces = 2,
|
||||||
|
.limits = wlcore_iface_limits,
|
||||||
|
.n_limits = ARRAY_SIZE(wlcore_iface_limits),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static int wl1271_init_ieee80211(struct wl1271 *wl)
|
static int wl1271_init_ieee80211(struct wl1271 *wl)
|
||||||
{
|
{
|
||||||
static const u32 cipher_suites[] = {
|
static const u32 cipher_suites[] = {
|
||||||
|
@ -5069,6 +5122,11 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
|
||||||
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
|
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
|
||||||
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
|
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
|
||||||
|
|
||||||
|
/* allowed interface combinations */
|
||||||
|
wl->hw->wiphy->iface_combinations = wlcore_iface_combinations;
|
||||||
|
wl->hw->wiphy->n_iface_combinations =
|
||||||
|
ARRAY_SIZE(wlcore_iface_combinations);
|
||||||
|
|
||||||
SET_IEEE80211_DEV(wl->hw, wl->dev);
|
SET_IEEE80211_DEV(wl->hw, wl->dev);
|
||||||
|
|
||||||
wl->hw->sta_data_size = sizeof(struct wl1271_station);
|
wl->hw->sta_data_size = sizeof(struct wl1271_station);
|
||||||
|
@ -5140,6 +5198,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
|
||||||
wl->channel_type = NL80211_CHAN_NO_HT;
|
wl->channel_type = NL80211_CHAN_NO_HT;
|
||||||
wl->flags = 0;
|
wl->flags = 0;
|
||||||
wl->sg_enabled = true;
|
wl->sg_enabled = true;
|
||||||
|
wl->sleep_auth = WL1271_PSM_ILLEGAL;
|
||||||
wl->hw_pg_ver = -1;
|
wl->hw_pg_ver = -1;
|
||||||
wl->ap_ps_map = 0;
|
wl->ap_ps_map = 0;
|
||||||
wl->ap_fw_ps_map = 0;
|
wl->ap_fw_ps_map = 0;
|
||||||
|
|
|
@ -76,7 +76,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
|
||||||
struct wl12xx_vif *wlvif;
|
struct wl12xx_vif *wlvif;
|
||||||
u32 timeout;
|
u32 timeout;
|
||||||
|
|
||||||
if (wl->quirks & WLCORE_QUIRK_NO_ELP)
|
if (wl->sleep_auth != WL1271_PSM_ELP)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* we shouldn't get consecutive sleep requests */
|
/* we shouldn't get consecutive sleep requests */
|
||||||
|
|
|
@ -127,7 +127,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rx_align == WLCORE_RX_BUF_UNALIGNED)
|
if (rx_align == WLCORE_RX_BUF_UNALIGNED)
|
||||||
reserved = NET_IP_ALIGN;
|
reserved = RX_BUF_ALIGN;
|
||||||
|
|
||||||
/* the data read starts with the descriptor */
|
/* the data read starts with the descriptor */
|
||||||
desc = (struct wl1271_rx_descriptor *) data;
|
desc = (struct wl1271_rx_descriptor *) data;
|
||||||
|
@ -175,7 +175,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
|
||||||
*/
|
*/
|
||||||
memcpy(buf, data + sizeof(*desc), pkt_data_len);
|
memcpy(buf, data + sizeof(*desc), pkt_data_len);
|
||||||
if (rx_align == WLCORE_RX_BUF_PADDED)
|
if (rx_align == WLCORE_RX_BUF_PADDED)
|
||||||
skb_pull(skb, NET_IP_ALIGN);
|
skb_pull(skb, RX_BUF_ALIGN);
|
||||||
|
|
||||||
*hlid = desc->hlid;
|
*hlid = desc->hlid;
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,12 @@
|
||||||
/* If set, the buffer was padded by the FW to be 4 bytes aligned */
|
/* If set, the buffer was padded by the FW to be 4 bytes aligned */
|
||||||
#define RX_BUF_PADDED_PAYLOAD BIT(30)
|
#define RX_BUF_PADDED_PAYLOAD BIT(30)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Account for the padding inserted by the FW in case of RX_ALIGNMENT
|
||||||
|
* or for fixing alignment in case the packet wasn't aligned.
|
||||||
|
*/
|
||||||
|
#define RX_BUF_ALIGN 2
|
||||||
|
|
||||||
/* Describes the alignment state of a Rx buffer */
|
/* Describes the alignment state of a Rx buffer */
|
||||||
enum wl_rx_buf_align {
|
enum wl_rx_buf_align {
|
||||||
WLCORE_RX_BUF_ALIGNED,
|
WLCORE_RX_BUF_ALIGNED,
|
||||||
|
|
|
@ -108,6 +108,20 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (answer) {
|
if (answer) {
|
||||||
|
/* If we got bip calibration answer print radio status */
|
||||||
|
struct wl1271_cmd_cal_p2g *params =
|
||||||
|
(struct wl1271_cmd_cal_p2g *) buf;
|
||||||
|
|
||||||
|
s16 radio_status = (s16) le16_to_cpu(params->radio_status);
|
||||||
|
|
||||||
|
if (params->test.id == TEST_CMD_P2G_CAL &&
|
||||||
|
radio_status < 0)
|
||||||
|
wl1271_warning("testmode cmd: radio status=%d",
|
||||||
|
radio_status);
|
||||||
|
else
|
||||||
|
wl1271_info("testmode cmd: radio status=%d",
|
||||||
|
radio_status);
|
||||||
|
|
||||||
len = nla_total_size(buf_len);
|
len = nla_total_size(buf_len);
|
||||||
skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len);
|
skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len);
|
||||||
if (!skb) {
|
if (!skb) {
|
||||||
|
|
|
@ -305,11 +305,15 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||||
if (is_dummy || !wlvif)
|
if (is_dummy || !wlvif)
|
||||||
rate_idx = 0;
|
rate_idx = 0;
|
||||||
else if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
|
else if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
|
||||||
/* if the packets are destined for AP (have a STA entry)
|
/*
|
||||||
send them with AP rate policies, otherwise use default
|
* if the packets are destined for AP (have a STA entry)
|
||||||
basic rates */
|
* send them with AP rate policies (EAPOLs are an exception),
|
||||||
|
* otherwise use default basic rates
|
||||||
|
*/
|
||||||
if (control->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
|
if (control->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
|
||||||
rate_idx = wlvif->sta.p2p_rate_idx;
|
rate_idx = wlvif->sta.p2p_rate_idx;
|
||||||
|
else if (skb->protocol == cpu_to_be16(ETH_P_PAE))
|
||||||
|
rate_idx = wlvif->sta.basic_rate_idx;
|
||||||
else if (control->control.sta)
|
else if (control->control.sta)
|
||||||
rate_idx = wlvif->sta.ap_rate_idx;
|
rate_idx = wlvif->sta.ap_rate_idx;
|
||||||
else
|
else
|
||||||
|
|
|
@ -387,6 +387,9 @@ struct wl1271 {
|
||||||
|
|
||||||
/* mutex for protecting the tx_flush function */
|
/* mutex for protecting the tx_flush function */
|
||||||
struct mutex flush_mutex;
|
struct mutex flush_mutex;
|
||||||
|
|
||||||
|
/* sleep auth value currently configured to FW */
|
||||||
|
int sleep_auth;
|
||||||
};
|
};
|
||||||
|
|
||||||
int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev);
|
int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev);
|
||||||
|
@ -398,6 +401,13 @@ 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);
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band,
|
||||||
|
struct ieee80211_sta_ht_cap *ht_cap)
|
||||||
|
{
|
||||||
|
memcpy(&wl->ht_cap[band], ht_cap, sizeof(*ht_cap));
|
||||||
|
}
|
||||||
|
|
||||||
/* Firmware image load chunk size */
|
/* Firmware image load chunk size */
|
||||||
#define CHUNK_SIZE 16384
|
#define CHUNK_SIZE 16384
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue