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_radio_parms_cmd *radio_parms;
|
||||
struct wl1271_ini_general_params *gp = &nvs->general_params;
|
||||
int ret;
|
||||
int ret, fem_idx;
|
||||
|
||||
if (!wl->nvs)
|
||||
return -ENODEV;
|
||||
|
@ -185,11 +185,13 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
|
|||
|
||||
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 */
|
||||
memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
|
||||
sizeof(struct wl1271_ini_band_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));
|
||||
|
||||
/* 5GHz parameters */
|
||||
|
@ -197,7 +199,7 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
|
|||
&nvs->stat_radio_params_5,
|
||||
sizeof(struct wl1271_ini_band_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));
|
||||
|
||||
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_radio_parms_cmd *radio_parms;
|
||||
struct wl128x_ini_general_params *gp = &nvs->general_params;
|
||||
int ret;
|
||||
int ret, fem_idx;
|
||||
|
||||
if (!wl->nvs)
|
||||
return -ENODEV;
|
||||
|
@ -227,11 +229,13 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl)
|
|||
|
||||
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 */
|
||||
memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
|
||||
sizeof(struct wl128x_ini_band_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));
|
||||
|
||||
/* 5GHz parameters */
|
||||
|
@ -239,7 +243,7 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl)
|
|||
&nvs->stat_radio_params_5,
|
||||
sizeof(struct wl128x_ini_band_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));
|
||||
|
||||
radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options;
|
||||
|
|
|
@ -246,6 +246,7 @@ static struct wlcore_conf wl12xx_conf = {
|
|||
.forced_ps = false,
|
||||
.keep_alive_interval = 55000,
|
||||
.max_listen_interval = 20,
|
||||
.sta_sleep_auth = WL1271_PSM_ILLEGAL,
|
||||
},
|
||||
.itrim = {
|
||||
.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->fw_status_priv_len = 0;
|
||||
wl->stats.fw_stats_len = sizeof(struct wl12xx_acx_statistics);
|
||||
memcpy(&wl->ht_cap[IEEE80211_BAND_2GHZ], &wl12xx_ht_cap,
|
||||
sizeof(wl12xx_ht_cap));
|
||||
memcpy(&wl->ht_cap[IEEE80211_BAND_5GHZ], &wl12xx_ht_cap,
|
||||
sizeof(wl12xx_ht_cap));
|
||||
wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ, &wl12xx_ht_cap);
|
||||
wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ, &wl12xx_ht_cap);
|
||||
wl12xx_conf_init(wl);
|
||||
|
||||
if (!fref_param) {
|
||||
|
|
|
@ -43,10 +43,11 @@
|
|||
|
||||
#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 bool checksum_param = false;
|
||||
static bool enable_11a_param = true;
|
||||
static int num_rx_desc_param = -1;
|
||||
|
||||
/* phy paramters */
|
||||
static int dc2dc_param = -1;
|
||||
|
@ -372,6 +373,7 @@ static struct wlcore_conf wl18xx_conf = {
|
|||
.forced_ps = false,
|
||||
.keep_alive_interval = 55000,
|
||||
.max_listen_interval = 20,
|
||||
.sta_sleep_auth = WL1271_PSM_ILLEGAL,
|
||||
},
|
||||
.itrim = {
|
||||
.enable = false,
|
||||
|
@ -606,8 +608,8 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
|
|||
wl->plt_fw_name = WL18XX_FW_NAME;
|
||||
wl->quirks |= WLCORE_QUIRK_NO_ELP |
|
||||
WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN |
|
||||
WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
|
||||
WLCORE_QUIRK_TX_PAD_LAST_FRAME;
|
||||
|
||||
break;
|
||||
case CHIP_ID_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) {
|
||||
wl1271_error("configuration binary file size is wrong, "
|
||||
"expected %ld got %zd",
|
||||
wl1271_error("configuration binary file size is wrong, expected %zu got %zu",
|
||||
WL18XX_CONF_SIZE, fw->size);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
|
@ -1214,8 +1215,8 @@ static struct wlcore_ops wl18xx_ops = {
|
|||
.pre_pkt_send = wl18xx_pre_pkt_send,
|
||||
};
|
||||
|
||||
/* HT cap appropriate for wide channels */
|
||||
static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap = {
|
||||
/* HT cap appropriate for wide channels in 2Ghz */
|
||||
static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_2ghz = {
|
||||
.cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
|
||||
IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40,
|
||||
.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 */
|
||||
static struct ieee80211_sta_ht_cap wl18xx_siso20_ht_cap = {
|
||||
.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)
|
||||
{
|
||||
struct wl1271 *wl;
|
||||
|
@ -1286,7 +1289,7 @@ static int __devinit wl18xx_probe(struct platform_device *pdev)
|
|||
wl->ptable = wl18xx_ptable;
|
||||
wl->rtable = wl18xx_rtable;
|
||||
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->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX;
|
||||
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->static_data_priv_len = sizeof(struct wl18xx_static_data_priv);
|
||||
|
||||
if (!strcmp(ht_mode_param, "wide")) {
|
||||
memcpy(&wl->ht_cap[IEEE80211_BAND_2GHZ],
|
||||
&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;
|
||||
}
|
||||
if (num_rx_desc_param != -1)
|
||||
wl->num_rx_desc = num_rx_desc_param;
|
||||
|
||||
ret = wl18xx_conf_init(wl, &pdev->dev);
|
||||
if (ret < 0)
|
||||
|
@ -1366,6 +1345,37 @@ static int __devinit wl18xx_probe(struct platform_device *pdev)
|
|||
if (dc2dc_param != -1)
|
||||
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) {
|
||||
wl18xx_ops.set_rx_csum = NULL;
|
||||
wl18xx_ops.init_vif = NULL;
|
||||
|
@ -1410,7 +1420,7 @@ static void __exit wl18xx_exit(void)
|
|||
module_exit(wl18xx_exit);
|
||||
|
||||
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_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 "
|
||||
"(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_AUTHOR("Luciano Coelho <coelho@ti.com>");
|
||||
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;
|
||||
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);
|
||||
if (!auth) {
|
||||
|
@ -81,7 +81,13 @@ int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth)
|
|||
auth->sleep_auth = sleep_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:
|
||||
kfree(auth);
|
||||
return ret;
|
||||
|
|
|
@ -118,6 +118,11 @@ enum wl1271_psm_mode {
|
|||
|
||||
/* Extreme low power */
|
||||
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 {
|
||||
|
|
|
@ -652,4 +652,25 @@ struct wl12xx_cmd_stop_channel_switch {
|
|||
struct wl1271_cmd_header header;
|
||||
} __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__ */
|
||||
|
|
|
@ -951,6 +951,12 @@ struct conf_conn_settings {
|
|||
* Range: u16
|
||||
*/
|
||||
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;
|
||||
|
||||
enum {
|
||||
|
@ -1276,7 +1282,7 @@ struct conf_hangover_settings {
|
|||
* version, the two LSB are the lower driver's private conf
|
||||
* version.
|
||||
*/
|
||||
#define WLCORE_CONF_VERSION (0x0001 << 16)
|
||||
#define WLCORE_CONF_VERSION (0x0002 << 16)
|
||||
#define WLCORE_CONF_MASK 0xffff0000
|
||||
#define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \
|
||||
sizeof(struct wlcore_conf))
|
||||
|
|
|
@ -963,6 +963,68 @@ static const struct file_operations fw_stats_raw_ops = {
|
|||
.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,
|
||||
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_timeout, rootdir);
|
||||
DEBUGFS_ADD(fw_stats_raw, rootdir);
|
||||
DEBUGFS_ADD(sleep_auth, rootdir);
|
||||
|
||||
streaming = debugfs_create_dir("rx_streaming", rootdir);
|
||||
if (!streaming || IS_ERR(streaming))
|
||||
|
|
|
@ -172,7 +172,19 @@ struct wl128x_ini_fem_params_5 {
|
|||
|
||||
/* NVS data structure */
|
||||
#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
|
||||
|
||||
|
@ -188,13 +200,13 @@ struct wl1271_nvs_file {
|
|||
struct {
|
||||
struct wl1271_ini_fem_params_2 params;
|
||||
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;
|
||||
u8 padding3;
|
||||
struct {
|
||||
struct wl1271_ini_fem_params_5 params;
|
||||
u8 padding;
|
||||
} dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT];
|
||||
} dyn_radio_params_5[WL12XX_NVS_FEM_MODULE_COUNT];
|
||||
} __packed;
|
||||
|
||||
struct wl128x_nvs_file {
|
||||
|
@ -209,12 +221,12 @@ struct wl128x_nvs_file {
|
|||
struct {
|
||||
struct wl128x_ini_fem_params_2 params;
|
||||
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;
|
||||
u8 padding3;
|
||||
struct {
|
||||
struct wl128x_ini_fem_params_5 params;
|
||||
u8 padding;
|
||||
} dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT];
|
||||
} dyn_radio_params_5[WL12XX_NVS_FEM_MODULE_COUNT];
|
||||
} __packed;
|
||||
#endif
|
||||
|
|
|
@ -554,29 +554,28 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
|
|||
bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
|
||||
int ret, i;
|
||||
|
||||
/*
|
||||
* consider all existing roles before configuring psm.
|
||||
* TODO: reconfigure on interface removal.
|
||||
*/
|
||||
if (!wl->ap_count) {
|
||||
if (is_ap) {
|
||||
/* Configure for power always on */
|
||||
/* consider all existing roles before configuring psm. */
|
||||
|
||||
if (wl->ap_count == 0 && is_ap) { /* first AP */
|
||||
/* Configure for power always on */
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* first STA, no APs */
|
||||
} 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 */
|
||||
else if (wl->quirks & WLCORE_QUIRK_NO_ELP)
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else if (!wl->sta_count) {
|
||||
if (wl->quirks & WLCORE_QUIRK_NO_ELP) {
|
||||
/* Configure for power always on */
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else {
|
||||
/* Configure for ELP power saving */
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
/* Configure for ELP power saving */
|
||||
else
|
||||
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Mode specific init */
|
||||
|
|
|
@ -770,14 +770,16 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
|
|||
return len;
|
||||
}
|
||||
|
||||
#define WLCORE_FW_LOG_END 0x2000000
|
||||
|
||||
static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
|
||||
{
|
||||
u32 addr;
|
||||
u32 first_addr;
|
||||
u32 offset;
|
||||
u32 end_of_log;
|
||||
u8 *block;
|
||||
|
||||
if ((wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
|
||||
(wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
|
||||
(wl->conf.fwlog.mem_blocks == 0))
|
||||
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.
|
||||
* Do not send a stop fwlog command if the fw is hanged.
|
||||
*/
|
||||
if (!wl1271_ps_elp_wakeup(wl) && !wl->watchdog_recovery)
|
||||
wl12xx_cmd_stop_fwlog(wl);
|
||||
else
|
||||
if (wl1271_ps_elp_wakeup(wl))
|
||||
goto out;
|
||||
if (!wl->watchdog_recovery)
|
||||
wl12xx_cmd_stop_fwlog(wl);
|
||||
|
||||
/* Read the first memory block address */
|
||||
wl12xx_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
|
||||
first_addr = le32_to_cpu(wl->fw_status_2->log_start_addr);
|
||||
if (!first_addr)
|
||||
addr = le32_to_cpu(wl->fw_status_2->log_start_addr);
|
||||
if (!addr)
|
||||
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 */
|
||||
addr = first_addr;
|
||||
do {
|
||||
memset(block, 0, 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
|
||||
* 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);
|
||||
if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
|
||||
WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
|
||||
if (!wl12xx_copy_fwlog(wl, block + offset,
|
||||
WL12XX_HW_BLOCK_SIZE - offset))
|
||||
break;
|
||||
} while (addr && (addr != first_addr));
|
||||
} while (addr && (addr != end_of_log));
|
||||
|
||||
wake_up_interruptible(&wl->fwlog_waitq);
|
||||
|
||||
|
@ -1082,6 +1092,7 @@ int wl1271_plt_stop(struct wl1271 *wl)
|
|||
mutex_lock(&wl->mutex);
|
||||
wl1271_power_off(wl);
|
||||
wl->flags = 0;
|
||||
wl->sleep_auth = WL1271_PSM_ILLEGAL;
|
||||
wl->state = WL1271_STATE_OFF;
|
||||
wl->plt = false;
|
||||
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_ps_map = 0;
|
||||
wl->sched_scanning = false;
|
||||
wl->sleep_auth = WL1271_PSM_ILLEGAL;
|
||||
memset(wl->roles_map, 0, sizeof(wl->roles_map));
|
||||
memset(wl->links_map, 0, sizeof(wl->links_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);
|
||||
int i, ret;
|
||||
bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
|
||||
|
||||
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->dev_role_id = WL12XX_INVALID_ROLE_ID;
|
||||
|
||||
if (wlvif->bss_type == BSS_TYPE_AP_BSS)
|
||||
if (is_ap)
|
||||
wl->ap_count--;
|
||||
else
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
if (is_ap) {
|
||||
wl1271_set_band_rate(wl, wlvif);
|
||||
ret = wl1271_init_ap_rates(wl, wlvif);
|
||||
if (ret < 0)
|
||||
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,
|
||||
struct survey_info *survey)
|
||||
{
|
||||
struct wl1271 *wl = hw->priv;
|
||||
struct ieee80211_conf *conf = &hw->conf;
|
||||
|
||||
if (idx != 0)
|
||||
return -ENOENT;
|
||||
|
||||
survey->channel = conf->channel;
|
||||
survey->filled = SURVEY_INFO_NOISE_DBM;
|
||||
survey->noise = wl->noise;
|
||||
|
||||
survey->filled = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -4365,9 +4390,14 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
|
|||
|
||||
case IEEE80211_AMPDU_RX_STOP:
|
||||
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);
|
||||
ret = 0;
|
||||
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 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_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);
|
||||
|
||||
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->flags = 0;
|
||||
wl->sg_enabled = true;
|
||||
wl->sleep_auth = WL1271_PSM_ILLEGAL;
|
||||
wl->hw_pg_ver = -1;
|
||||
wl->ap_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;
|
||||
u32 timeout;
|
||||
|
||||
if (wl->quirks & WLCORE_QUIRK_NO_ELP)
|
||||
if (wl->sleep_auth != WL1271_PSM_ELP)
|
||||
return;
|
||||
|
||||
/* 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)
|
||||
reserved = NET_IP_ALIGN;
|
||||
reserved = RX_BUF_ALIGN;
|
||||
|
||||
/* the data read starts with the descriptor */
|
||||
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);
|
||||
if (rx_align == WLCORE_RX_BUF_PADDED)
|
||||
skb_pull(skb, NET_IP_ALIGN);
|
||||
skb_pull(skb, RX_BUF_ALIGN);
|
||||
|
||||
*hlid = desc->hlid;
|
||||
|
||||
|
|
|
@ -103,6 +103,12 @@
|
|||
/* If set, the buffer was padded by the FW to be 4 bytes aligned */
|
||||
#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 */
|
||||
enum wl_rx_buf_align {
|
||||
WLCORE_RX_BUF_ALIGNED,
|
||||
|
|
|
@ -108,6 +108,20 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[])
|
|||
}
|
||||
|
||||
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);
|
||||
skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len);
|
||||
if (!skb) {
|
||||
|
|
|
@ -305,11 +305,15 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
|||
if (is_dummy || !wlvif)
|
||||
rate_idx = 0;
|
||||
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
|
||||
basic rates */
|
||||
/*
|
||||
* if the packets are destined for AP (have a STA entry)
|
||||
* send them with AP rate policies (EAPOLs are an exception),
|
||||
* otherwise use default basic rates
|
||||
*/
|
||||
if (control->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
|
||||
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)
|
||||
rate_idx = wlvif->sta.ap_rate_idx;
|
||||
else
|
||||
|
|
|
@ -387,6 +387,9 @@ struct wl1271 {
|
|||
|
||||
/* mutex for protecting the tx_flush function */
|
||||
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);
|
||||
|
@ -398,6 +401,13 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
|||
struct ieee80211_sta *sta,
|
||||
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 */
|
||||
#define CHUNK_SIZE 16384
|
||||
|
||||
|
|
Loading…
Reference in New Issue