mirror of
https://github.com/torvalds/linux.git
synced 2024-11-08 21:21:47 +00:00
Merge branch 'for-linville' of git://github.com/kvalo/ath
This commit is contained in:
commit
a72e25f781
@ -283,7 +283,7 @@ static int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
|
||||
|
||||
if (unlikely(CE_RING_DELTA(nentries_mask,
|
||||
write_index, sw_index - 1) <= 0)) {
|
||||
ret = -EIO;
|
||||
ret = -ENOSR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@ -338,38 +338,19 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath10k_ce_sendlist_send(struct ath10k_ce_pipe *ce_state,
|
||||
void *per_transfer_context,
|
||||
unsigned int transfer_id,
|
||||
u32 paddr, unsigned int nbytes,
|
||||
u32 flags)
|
||||
int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe)
|
||||
{
|
||||
struct ath10k_ce_ring *src_ring = ce_state->src_ring;
|
||||
struct ath10k *ar = ce_state->ar;
|
||||
struct ath10k *ar = pipe->ar;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
unsigned int nentries_mask = src_ring->nentries_mask;
|
||||
unsigned int sw_index;
|
||||
unsigned int write_index;
|
||||
int delta, ret = -ENOMEM;
|
||||
int delta;
|
||||
|
||||
spin_lock_bh(&ar_pci->ce_lock);
|
||||
|
||||
sw_index = src_ring->sw_index;
|
||||
write_index = src_ring->write_index;
|
||||
|
||||
delta = CE_RING_DELTA(nentries_mask, write_index, sw_index - 1);
|
||||
|
||||
if (delta >= 1) {
|
||||
ret = ath10k_ce_send_nolock(ce_state, per_transfer_context,
|
||||
paddr, nbytes,
|
||||
transfer_id, flags);
|
||||
if (ret)
|
||||
ath10k_warn("CE send failed: %d\n", ret);
|
||||
}
|
||||
|
||||
delta = CE_RING_DELTA(pipe->src_ring->nentries_mask,
|
||||
pipe->src_ring->write_index,
|
||||
pipe->src_ring->sw_index - 1);
|
||||
spin_unlock_bh(&ar_pci->ce_lock);
|
||||
|
||||
return ret;
|
||||
return delta;
|
||||
}
|
||||
|
||||
int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state,
|
||||
|
@ -156,21 +156,7 @@ void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
|
||||
void (*send_cb)(struct ath10k_ce_pipe *),
|
||||
int disable_interrupts);
|
||||
|
||||
/*
|
||||
* Queue a "sendlist" of buffers to be sent using gather to a single
|
||||
* anonymous destination buffer
|
||||
* ce - which copy engine to use
|
||||
* sendlist - list of simple buffers to send using gather
|
||||
* transfer_id - arbitrary ID; reflected to destination
|
||||
* Returns 0 on success; otherwise an error status.
|
||||
*
|
||||
* Implemenation note: Pushes multiple buffers with Gather to Source ring.
|
||||
*/
|
||||
int ath10k_ce_sendlist_send(struct ath10k_ce_pipe *ce_state,
|
||||
void *per_transfer_context,
|
||||
unsigned int transfer_id,
|
||||
u32 paddr, unsigned int nbytes,
|
||||
u32 flags);
|
||||
int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe);
|
||||
|
||||
/*==================Recv=======================*/
|
||||
|
||||
|
@ -59,27 +59,6 @@ static void ath10k_send_suspend_complete(struct ath10k *ar)
|
||||
wake_up(&ar->event_queue);
|
||||
}
|
||||
|
||||
static int ath10k_check_fw_version(struct ath10k *ar)
|
||||
{
|
||||
char version[32];
|
||||
|
||||
if (ar->fw_version_major >= SUPPORTED_FW_MAJOR &&
|
||||
ar->fw_version_minor >= SUPPORTED_FW_MINOR &&
|
||||
ar->fw_version_release >= SUPPORTED_FW_RELEASE &&
|
||||
ar->fw_version_build >= SUPPORTED_FW_BUILD)
|
||||
return 0;
|
||||
|
||||
snprintf(version, sizeof(version), "%u.%u.%u.%u",
|
||||
SUPPORTED_FW_MAJOR, SUPPORTED_FW_MINOR,
|
||||
SUPPORTED_FW_RELEASE, SUPPORTED_FW_BUILD);
|
||||
|
||||
ath10k_warn("WARNING: Firmware version %s is not officially supported.\n",
|
||||
ar->hw->wiphy->fw_version);
|
||||
ath10k_warn("Please upgrade to version %s (or newer)\n", version);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_init_connect_htc(struct ath10k *ar)
|
||||
{
|
||||
int status;
|
||||
@ -189,8 +168,7 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar,
|
||||
return fw;
|
||||
}
|
||||
|
||||
static int ath10k_push_board_ext_data(struct ath10k *ar,
|
||||
const struct firmware *fw)
|
||||
static int ath10k_push_board_ext_data(struct ath10k *ar)
|
||||
{
|
||||
u32 board_data_size = QCA988X_BOARD_DATA_SZ;
|
||||
u32 board_ext_data_size = QCA988X_BOARD_EXT_DATA_SZ;
|
||||
@ -210,14 +188,14 @@ static int ath10k_push_board_ext_data(struct ath10k *ar,
|
||||
if (board_ext_data_addr == 0)
|
||||
return 0;
|
||||
|
||||
if (fw->size != (board_data_size + board_ext_data_size)) {
|
||||
if (ar->board_len != (board_data_size + board_ext_data_size)) {
|
||||
ath10k_err("invalid board (ext) data sizes %zu != %d+%d\n",
|
||||
fw->size, board_data_size, board_ext_data_size);
|
||||
ar->board_len, board_data_size, board_ext_data_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = ath10k_bmi_write_memory(ar, board_ext_data_addr,
|
||||
fw->data + board_data_size,
|
||||
ar->board_data + board_data_size,
|
||||
board_ext_data_size);
|
||||
if (ret) {
|
||||
ath10k_err("could not write board ext data (%d)\n", ret);
|
||||
@ -236,12 +214,11 @@ static int ath10k_push_board_ext_data(struct ath10k *ar,
|
||||
|
||||
static int ath10k_download_board_data(struct ath10k *ar)
|
||||
{
|
||||
const struct firmware *fw = ar->board_data;
|
||||
u32 board_data_size = QCA988X_BOARD_DATA_SZ;
|
||||
u32 address;
|
||||
int ret;
|
||||
|
||||
ret = ath10k_push_board_ext_data(ar, fw);
|
||||
ret = ath10k_push_board_ext_data(ar);
|
||||
if (ret) {
|
||||
ath10k_err("could not push board ext data (%d)\n", ret);
|
||||
goto exit;
|
||||
@ -253,8 +230,9 @@ static int ath10k_download_board_data(struct ath10k *ar)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = ath10k_bmi_write_memory(ar, address, fw->data,
|
||||
min_t(u32, board_data_size, fw->size));
|
||||
ret = ath10k_bmi_write_memory(ar, address, ar->board_data,
|
||||
min_t(u32, board_data_size,
|
||||
ar->board_len));
|
||||
if (ret) {
|
||||
ath10k_err("could not write board data (%d)\n", ret);
|
||||
goto exit;
|
||||
@ -272,17 +250,16 @@ exit:
|
||||
|
||||
static int ath10k_download_and_run_otp(struct ath10k *ar)
|
||||
{
|
||||
const struct firmware *fw = ar->otp;
|
||||
u32 address = ar->hw_params.patch_load_addr;
|
||||
u32 exec_param;
|
||||
int ret;
|
||||
|
||||
/* OTP is optional */
|
||||
|
||||
if (!ar->otp)
|
||||
if (!ar->otp_data || !ar->otp_len)
|
||||
return 0;
|
||||
|
||||
ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size);
|
||||
ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len);
|
||||
if (ret) {
|
||||
ath10k_err("could not write otp (%d)\n", ret);
|
||||
goto exit;
|
||||
@ -301,13 +278,13 @@ exit:
|
||||
|
||||
static int ath10k_download_fw(struct ath10k *ar)
|
||||
{
|
||||
const struct firmware *fw = ar->firmware;
|
||||
u32 address;
|
||||
int ret;
|
||||
|
||||
address = ar->hw_params.patch_load_addr;
|
||||
|
||||
ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size);
|
||||
ret = ath10k_bmi_fast_download(ar, address, ar->firmware_data,
|
||||
ar->firmware_len);
|
||||
if (ret) {
|
||||
ath10k_err("could not write fw (%d)\n", ret);
|
||||
goto exit;
|
||||
@ -319,8 +296,8 @@ exit:
|
||||
|
||||
static void ath10k_core_free_firmware_files(struct ath10k *ar)
|
||||
{
|
||||
if (ar->board_data && !IS_ERR(ar->board_data))
|
||||
release_firmware(ar->board_data);
|
||||
if (ar->board && !IS_ERR(ar->board))
|
||||
release_firmware(ar->board);
|
||||
|
||||
if (ar->otp && !IS_ERR(ar->otp))
|
||||
release_firmware(ar->otp);
|
||||
@ -328,12 +305,20 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar)
|
||||
if (ar->firmware && !IS_ERR(ar->firmware))
|
||||
release_firmware(ar->firmware);
|
||||
|
||||
ar->board = NULL;
|
||||
ar->board_data = NULL;
|
||||
ar->board_len = 0;
|
||||
|
||||
ar->otp = NULL;
|
||||
ar->otp_data = NULL;
|
||||
ar->otp_len = 0;
|
||||
|
||||
ar->firmware = NULL;
|
||||
ar->firmware_data = NULL;
|
||||
ar->firmware_len = 0;
|
||||
}
|
||||
|
||||
static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
|
||||
static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@ -347,15 +332,18 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ar->board_data = ath10k_fetch_fw_file(ar,
|
||||
ar->hw_params.fw.dir,
|
||||
ar->hw_params.fw.board);
|
||||
if (IS_ERR(ar->board_data)) {
|
||||
ret = PTR_ERR(ar->board_data);
|
||||
ar->board = ath10k_fetch_fw_file(ar,
|
||||
ar->hw_params.fw.dir,
|
||||
ar->hw_params.fw.board);
|
||||
if (IS_ERR(ar->board)) {
|
||||
ret = PTR_ERR(ar->board);
|
||||
ath10k_err("could not fetch board data (%d)\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ar->board_data = ar->board->data;
|
||||
ar->board_len = ar->board->size;
|
||||
|
||||
ar->firmware = ath10k_fetch_fw_file(ar,
|
||||
ar->hw_params.fw.dir,
|
||||
ar->hw_params.fw.fw);
|
||||
@ -365,6 +353,9 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
|
||||
goto err;
|
||||
}
|
||||
|
||||
ar->firmware_data = ar->firmware->data;
|
||||
ar->firmware_len = ar->firmware->size;
|
||||
|
||||
/* OTP may be undefined. If so, don't fetch it at all */
|
||||
if (ar->hw_params.fw.otp == NULL)
|
||||
return 0;
|
||||
@ -378,6 +369,9 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
|
||||
goto err;
|
||||
}
|
||||
|
||||
ar->otp_data = ar->otp->data;
|
||||
ar->otp_len = ar->otp->size;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
@ -385,6 +379,191 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
|
||||
{
|
||||
size_t magic_len, len, ie_len;
|
||||
int ie_id, i, index, bit, ret;
|
||||
struct ath10k_fw_ie *hdr;
|
||||
const u8 *data;
|
||||
__le32 *timestamp;
|
||||
|
||||
/* first fetch the firmware file (firmware-*.bin) */
|
||||
ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name);
|
||||
if (IS_ERR(ar->firmware)) {
|
||||
ath10k_err("Could not fetch firmware file '%s': %ld\n",
|
||||
name, PTR_ERR(ar->firmware));
|
||||
return PTR_ERR(ar->firmware);
|
||||
}
|
||||
|
||||
data = ar->firmware->data;
|
||||
len = ar->firmware->size;
|
||||
|
||||
/* magic also includes the null byte, check that as well */
|
||||
magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1;
|
||||
|
||||
if (len < magic_len) {
|
||||
ath10k_err("firmware image too small to contain magic: %zu\n",
|
||||
len);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) {
|
||||
ath10k_err("Invalid firmware magic\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* jump over the padding */
|
||||
magic_len = ALIGN(magic_len, 4);
|
||||
|
||||
len -= magic_len;
|
||||
data += magic_len;
|
||||
|
||||
/* loop elements */
|
||||
while (len > sizeof(struct ath10k_fw_ie)) {
|
||||
hdr = (struct ath10k_fw_ie *)data;
|
||||
|
||||
ie_id = le32_to_cpu(hdr->id);
|
||||
ie_len = le32_to_cpu(hdr->len);
|
||||
|
||||
len -= sizeof(*hdr);
|
||||
data += sizeof(*hdr);
|
||||
|
||||
if (len < ie_len) {
|
||||
ath10k_err("Invalid length for FW IE %d (%zu < %zu)\n",
|
||||
ie_id, len, ie_len);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
switch (ie_id) {
|
||||
case ATH10K_FW_IE_FW_VERSION:
|
||||
if (ie_len > sizeof(ar->hw->wiphy->fw_version) - 1)
|
||||
break;
|
||||
|
||||
memcpy(ar->hw->wiphy->fw_version, data, ie_len);
|
||||
ar->hw->wiphy->fw_version[ie_len] = '\0';
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT,
|
||||
"found fw version %s\n",
|
||||
ar->hw->wiphy->fw_version);
|
||||
break;
|
||||
case ATH10K_FW_IE_TIMESTAMP:
|
||||
if (ie_len != sizeof(u32))
|
||||
break;
|
||||
|
||||
timestamp = (__le32 *)data;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "found fw timestamp %d\n",
|
||||
le32_to_cpup(timestamp));
|
||||
break;
|
||||
case ATH10K_FW_IE_FEATURES:
|
||||
ath10k_dbg(ATH10K_DBG_BOOT,
|
||||
"found firmware features ie (%zd B)\n",
|
||||
ie_len);
|
||||
|
||||
for (i = 0; i < ATH10K_FW_FEATURE_COUNT; i++) {
|
||||
index = i / 8;
|
||||
bit = i % 8;
|
||||
|
||||
if (index == ie_len)
|
||||
break;
|
||||
|
||||
if (data[index] & (1 << bit))
|
||||
__set_bit(i, ar->fw_features);
|
||||
}
|
||||
|
||||
ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "",
|
||||
ar->fw_features,
|
||||
sizeof(ar->fw_features));
|
||||
break;
|
||||
case ATH10K_FW_IE_FW_IMAGE:
|
||||
ath10k_dbg(ATH10K_DBG_BOOT,
|
||||
"found fw image ie (%zd B)\n",
|
||||
ie_len);
|
||||
|
||||
ar->firmware_data = data;
|
||||
ar->firmware_len = ie_len;
|
||||
|
||||
break;
|
||||
case ATH10K_FW_IE_OTP_IMAGE:
|
||||
ath10k_dbg(ATH10K_DBG_BOOT,
|
||||
"found otp image ie (%zd B)\n",
|
||||
ie_len);
|
||||
|
||||
ar->otp_data = data;
|
||||
ar->otp_len = ie_len;
|
||||
|
||||
break;
|
||||
default:
|
||||
ath10k_warn("Unknown FW IE: %u\n",
|
||||
le32_to_cpu(hdr->id));
|
||||
break;
|
||||
}
|
||||
|
||||
/* jump over the padding */
|
||||
ie_len = ALIGN(ie_len, 4);
|
||||
|
||||
len -= ie_len;
|
||||
data += ie_len;
|
||||
}
|
||||
|
||||
if (!ar->firmware_data || !ar->firmware_len) {
|
||||
ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from %s, skipping\n",
|
||||
name);
|
||||
ret = -ENOMEDIUM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* now fetch the board file */
|
||||
if (ar->hw_params.fw.board == NULL) {
|
||||
ath10k_err("board data file not defined");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ar->board = ath10k_fetch_fw_file(ar,
|
||||
ar->hw_params.fw.dir,
|
||||
ar->hw_params.fw.board);
|
||||
if (IS_ERR(ar->board)) {
|
||||
ret = PTR_ERR(ar->board);
|
||||
ath10k_err("could not fetch board data (%d)\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ar->board_data = ar->board->data;
|
||||
ar->board_len = ar->board->size;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
ath10k_core_free_firmware_files(ar);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE);
|
||||
if (ret == 0) {
|
||||
ar->fw_api = 2;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ath10k_core_fetch_firmware_api_1(ar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ar->fw_api = 1;
|
||||
|
||||
out:
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_init_download_firmware(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
@ -541,6 +720,9 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
|
||||
INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work);
|
||||
skb_queue_head_init(&ar->offchan_tx_queue);
|
||||
|
||||
INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work);
|
||||
skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
|
||||
|
||||
init_waitqueue_head(&ar->event_queue);
|
||||
|
||||
INIT_WORK(&ar->restart_work, ath10k_core_restart);
|
||||
@ -555,6 +737,8 @@ EXPORT_SYMBOL(ath10k_core_create);
|
||||
|
||||
void ath10k_core_destroy(struct ath10k *ar)
|
||||
{
|
||||
ath10k_debug_destroy(ar);
|
||||
|
||||
flush_workqueue(ar->workqueue);
|
||||
destroy_workqueue(ar->workqueue);
|
||||
|
||||
@ -566,6 +750,8 @@ int ath10k_core_start(struct ath10k *ar)
|
||||
{
|
||||
int status;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
ath10k_bmi_start(ar);
|
||||
|
||||
if (ath10k_init_configure_target(ar)) {
|
||||
@ -616,10 +802,6 @@ int ath10k_core_start(struct ath10k *ar)
|
||||
|
||||
ath10k_info("firmware %s booted\n", ar->hw->wiphy->fw_version);
|
||||
|
||||
status = ath10k_check_fw_version(ar);
|
||||
if (status)
|
||||
goto err_disconnect_htc;
|
||||
|
||||
status = ath10k_wmi_cmd_init(ar);
|
||||
if (status) {
|
||||
ath10k_err("could not send WMI init command (%d)\n", status);
|
||||
@ -642,6 +824,7 @@ int ath10k_core_start(struct ath10k *ar)
|
||||
goto err_disconnect_htc;
|
||||
|
||||
ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1;
|
||||
INIT_LIST_HEAD(&ar->arvifs);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -658,6 +841,8 @@ EXPORT_SYMBOL(ath10k_core_start);
|
||||
|
||||
void ath10k_core_stop(struct ath10k *ar)
|
||||
{
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
ath10k_debug_stop(ar);
|
||||
ath10k_htc_stop(&ar->htc);
|
||||
ath10k_htt_detach(&ar->htt);
|
||||
@ -705,15 +890,21 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
ret = ath10k_core_start(ar);
|
||||
if (ret) {
|
||||
ath10k_err("could not init core (%d)\n", ret);
|
||||
ath10k_core_free_firmware_files(ar);
|
||||
ath10k_hif_power_down(ar);
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ath10k_core_stop(ar);
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
ath10k_hif_power_down(ar);
|
||||
return 0;
|
||||
}
|
||||
|
@ -43,15 +43,17 @@
|
||||
/* Antenna noise floor */
|
||||
#define ATH10K_DEFAULT_NOISE_FLOOR -95
|
||||
|
||||
#define ATH10K_MAX_NUM_MGMT_PENDING 16
|
||||
|
||||
struct ath10k;
|
||||
|
||||
struct ath10k_skb_cb {
|
||||
dma_addr_t paddr;
|
||||
bool is_mapped;
|
||||
bool is_aborted;
|
||||
u8 vdev_id;
|
||||
|
||||
struct {
|
||||
u8 vdev_id;
|
||||
u8 tid;
|
||||
bool is_offchan;
|
||||
|
||||
@ -102,11 +104,26 @@ struct ath10k_bmi {
|
||||
bool done_sent;
|
||||
};
|
||||
|
||||
#define ATH10K_MAX_MEM_REQS 16
|
||||
|
||||
struct ath10k_mem_chunk {
|
||||
void *vaddr;
|
||||
dma_addr_t paddr;
|
||||
u32 len;
|
||||
u32 req_id;
|
||||
};
|
||||
|
||||
struct ath10k_wmi {
|
||||
enum ath10k_htc_ep_id eid;
|
||||
struct completion service_ready;
|
||||
struct completion unified_ready;
|
||||
wait_queue_head_t tx_credits_wq;
|
||||
struct wmi_cmd_map *cmd;
|
||||
struct wmi_vdev_param_map *vdev_param;
|
||||
struct wmi_pdev_param_map *pdev_param;
|
||||
|
||||
u32 num_mem_chunks;
|
||||
struct ath10k_mem_chunk mem_chunks[ATH10K_MAX_MEM_REQS];
|
||||
};
|
||||
|
||||
struct ath10k_peer_stat {
|
||||
@ -188,6 +205,8 @@ struct ath10k_peer {
|
||||
#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ)
|
||||
|
||||
struct ath10k_vif {
|
||||
struct list_head list;
|
||||
|
||||
u32 vdev_id;
|
||||
enum wmi_vdev_type vdev_type;
|
||||
enum wmi_vdev_subtype vdev_subtype;
|
||||
@ -198,8 +217,10 @@ struct ath10k_vif {
|
||||
struct ath10k *ar;
|
||||
struct ieee80211_vif *vif;
|
||||
|
||||
struct work_struct wep_key_work;
|
||||
struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1];
|
||||
u8 def_wep_key_index;
|
||||
u8 def_wep_key_idx;
|
||||
u8 def_wep_key_newidx;
|
||||
|
||||
u16 tx_seq_no;
|
||||
|
||||
@ -268,6 +289,12 @@ enum ath10k_fw_features {
|
||||
/* wmi_mgmt_rx_hdr contains extra RSSI information */
|
||||
ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0,
|
||||
|
||||
/* firmware from 10X branch */
|
||||
ATH10K_FW_FEATURE_WMI_10X = 1,
|
||||
|
||||
/* firmware support tx frame management over WMI, otherwise it's HTT */
|
||||
ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX = 2,
|
||||
|
||||
/* keep last */
|
||||
ATH10K_FW_FEATURE_COUNT,
|
||||
};
|
||||
@ -324,9 +351,19 @@ struct ath10k {
|
||||
} fw;
|
||||
} hw_params;
|
||||
|
||||
const struct firmware *board_data;
|
||||
const struct firmware *board;
|
||||
const void *board_data;
|
||||
size_t board_len;
|
||||
|
||||
const struct firmware *otp;
|
||||
const void *otp_data;
|
||||
size_t otp_len;
|
||||
|
||||
const struct firmware *firmware;
|
||||
const void *firmware_data;
|
||||
size_t firmware_len;
|
||||
|
||||
int fw_api;
|
||||
|
||||
struct {
|
||||
struct completion started;
|
||||
@ -369,6 +406,7 @@ struct ath10k {
|
||||
/* protects shared structure data */
|
||||
spinlock_t data_lock;
|
||||
|
||||
struct list_head arvifs;
|
||||
struct list_head peers;
|
||||
wait_queue_head_t peer_mapping_wq;
|
||||
|
||||
@ -377,6 +415,9 @@ struct ath10k {
|
||||
struct completion offchan_tx_completed;
|
||||
struct sk_buff *offchan_tx_skb;
|
||||
|
||||
struct work_struct wmi_mgmt_tx_work;
|
||||
struct sk_buff_head wmi_mgmt_tx_queue;
|
||||
|
||||
enum ath10k_state state;
|
||||
|
||||
struct work_struct restart_work;
|
||||
|
@ -618,6 +618,8 @@ int ath10k_debug_start(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
ret = ath10k_debug_htt_stats_req(ar);
|
||||
if (ret)
|
||||
/* continue normally anyway, this isn't serious */
|
||||
@ -628,7 +630,13 @@ int ath10k_debug_start(struct ath10k *ar)
|
||||
|
||||
void ath10k_debug_stop(struct ath10k *ar)
|
||||
{
|
||||
cancel_delayed_work_sync(&ar->debug.htt_stats_dwork);
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
/* Must not use _sync to avoid deadlock, we do that in
|
||||
* ath10k_debug_destroy(). The check for htt_stats_mask is to avoid
|
||||
* warning from del_timer(). */
|
||||
if (ar->debug.htt_stats_mask != 0)
|
||||
cancel_delayed_work(&ar->debug.htt_stats_dwork);
|
||||
}
|
||||
|
||||
int ath10k_debug_create(struct ath10k *ar)
|
||||
@ -662,6 +670,11 @@ int ath10k_debug_create(struct ath10k *ar)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath10k_debug_destroy(struct ath10k *ar)
|
||||
{
|
||||
cancel_delayed_work_sync(&ar->debug.htt_stats_dwork);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ATH10K_DEBUGFS */
|
||||
|
||||
#ifdef CONFIG_ATH10K_DEBUG
|
||||
|
@ -46,6 +46,7 @@ extern __printf(1, 2) int ath10k_warn(const char *fmt, ...);
|
||||
int ath10k_debug_start(struct ath10k *ar);
|
||||
void ath10k_debug_stop(struct ath10k *ar);
|
||||
int ath10k_debug_create(struct ath10k *ar);
|
||||
void ath10k_debug_destroy(struct ath10k *ar);
|
||||
void ath10k_debug_read_service_map(struct ath10k *ar,
|
||||
void *service_map,
|
||||
size_t map_size);
|
||||
@ -67,6 +68,10 @@ static inline int ath10k_debug_create(struct ath10k *ar)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath10k_debug_destroy(struct ath10k *ar)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath10k_debug_read_service_map(struct ath10k *ar,
|
||||
void *service_map,
|
||||
size_t map_size)
|
||||
|
@ -308,7 +308,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
||||
struct sk_buff *txdesc = NULL;
|
||||
struct htt_cmd *cmd;
|
||||
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
|
||||
u8 vdev_id = skb_cb->htt.vdev_id;
|
||||
u8 vdev_id = skb_cb->vdev_id;
|
||||
int len = 0;
|
||||
int msdu_id = -1;
|
||||
int res;
|
||||
@ -384,7 +384,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
||||
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
|
||||
struct sk_buff *txdesc = NULL;
|
||||
bool use_frags;
|
||||
u8 vdev_id = ATH10K_SKB_CB(msdu)->htt.vdev_id;
|
||||
u8 vdev_id = ATH10K_SKB_CB(msdu)->vdev_id;
|
||||
u8 tid;
|
||||
int prefetch_len, desc_len;
|
||||
int msdu_id = -1;
|
||||
|
@ -20,12 +20,6 @@
|
||||
|
||||
#include "targaddrs.h"
|
||||
|
||||
/* Supported FW version */
|
||||
#define SUPPORTED_FW_MAJOR 1
|
||||
#define SUPPORTED_FW_MINOR 0
|
||||
#define SUPPORTED_FW_RELEASE 0
|
||||
#define SUPPORTED_FW_BUILD 636
|
||||
|
||||
/* QCA988X 1.0 definitions (unsupported) */
|
||||
#define QCA988X_HW_1_0_CHIP_ID_REV 0x0
|
||||
|
||||
@ -38,6 +32,25 @@
|
||||
#define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin"
|
||||
#define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234
|
||||
|
||||
#define ATH10K_FW_API2_FILE "firmware-2.bin"
|
||||
|
||||
/* includes also the null byte */
|
||||
#define ATH10K_FIRMWARE_MAGIC "QCA-ATH10K"
|
||||
|
||||
struct ath10k_fw_ie {
|
||||
__le32 id;
|
||||
__le32 len;
|
||||
u8 data[0];
|
||||
};
|
||||
|
||||
enum ath10k_fw_ie_type {
|
||||
ATH10K_FW_IE_FW_VERSION = 0,
|
||||
ATH10K_FW_IE_TIMESTAMP = 1,
|
||||
ATH10K_FW_IE_FEATURES = 2,
|
||||
ATH10K_FW_IE_FW_IMAGE = 3,
|
||||
ATH10K_FW_IE_OTP_IMAGE = 4,
|
||||
};
|
||||
|
||||
/* Known pecularities:
|
||||
* - current FW doesn't support raw rx mode (last tested v599)
|
||||
* - current FW dumps upon raw tx mode (last tested v599)
|
||||
@ -59,6 +72,7 @@ enum ath10k_mcast2ucast_mode {
|
||||
ATH10K_MCAST2UCAST_ENABLED = 1,
|
||||
};
|
||||
|
||||
/* Target specific defines for MAIN firmware */
|
||||
#define TARGET_NUM_VDEVS 8
|
||||
#define TARGET_NUM_PEER_AST 2
|
||||
#define TARGET_NUM_WDS_ENTRIES 32
|
||||
@ -93,6 +107,36 @@ enum ath10k_mcast2ucast_mode {
|
||||
#define TARGET_NUM_MSDU_DESC (1024 + 400)
|
||||
#define TARGET_MAX_FRAG_ENTRIES 0
|
||||
|
||||
/* Target specific defines for 10.X firmware */
|
||||
#define TARGET_10X_NUM_VDEVS 16
|
||||
#define TARGET_10X_NUM_PEER_AST 2
|
||||
#define TARGET_10X_NUM_WDS_ENTRIES 32
|
||||
#define TARGET_10X_DMA_BURST_SIZE 0
|
||||
#define TARGET_10X_MAC_AGGR_DELIM 0
|
||||
#define TARGET_10X_AST_SKID_LIMIT 16
|
||||
#define TARGET_10X_NUM_PEERS (128 + (TARGET_10X_NUM_VDEVS))
|
||||
#define TARGET_10X_NUM_OFFLOAD_PEERS 0
|
||||
#define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS 0
|
||||
#define TARGET_10X_NUM_PEER_KEYS 2
|
||||
#define TARGET_10X_NUM_TIDS 256
|
||||
#define TARGET_10X_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
|
||||
#define TARGET_10X_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
|
||||
#define TARGET_10X_RX_TIMEOUT_LO_PRI 100
|
||||
#define TARGET_10X_RX_TIMEOUT_HI_PRI 40
|
||||
#define TARGET_10X_RX_DECAP_MODE ATH10K_HW_TXRX_NATIVE_WIFI
|
||||
#define TARGET_10X_SCAN_MAX_PENDING_REQS 4
|
||||
#define TARGET_10X_BMISS_OFFLOAD_MAX_VDEV 2
|
||||
#define TARGET_10X_ROAM_OFFLOAD_MAX_VDEV 2
|
||||
#define TARGET_10X_ROAM_OFFLOAD_MAX_AP_PROFILES 8
|
||||
#define TARGET_10X_GTK_OFFLOAD_MAX_VDEV 3
|
||||
#define TARGET_10X_NUM_MCAST_GROUPS 0
|
||||
#define TARGET_10X_NUM_MCAST_TABLE_ELEMS 0
|
||||
#define TARGET_10X_MCAST2UCAST_MODE ATH10K_MCAST2UCAST_DISABLED
|
||||
#define TARGET_10X_TX_DBG_LOG_SIZE 1024
|
||||
#define TARGET_10X_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 1
|
||||
#define TARGET_10X_VOW_CONFIG 0
|
||||
#define TARGET_10X_NUM_MSDU_DESC (1024 + 400)
|
||||
#define TARGET_10X_MAX_FRAG_ENTRIES 0
|
||||
|
||||
/* Number of Copy Engines supported */
|
||||
#define CE_COUNT 8
|
||||
|
@ -334,25 +334,29 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
|
||||
|
||||
static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)
|
||||
{
|
||||
struct ath10k *ar = arvif->ar;
|
||||
u32 vdev_param;
|
||||
|
||||
if (value != 0xFFFFFFFF)
|
||||
value = min_t(u32, arvif->ar->hw->wiphy->rts_threshold,
|
||||
ATH10K_RTS_MAX);
|
||||
|
||||
return ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id,
|
||||
WMI_VDEV_PARAM_RTS_THRESHOLD,
|
||||
value);
|
||||
vdev_param = ar->wmi.vdev_param->rts_threshold;
|
||||
return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value);
|
||||
}
|
||||
|
||||
static int ath10k_mac_set_frag(struct ath10k_vif *arvif, u32 value)
|
||||
{
|
||||
struct ath10k *ar = arvif->ar;
|
||||
u32 vdev_param;
|
||||
|
||||
if (value != 0xFFFFFFFF)
|
||||
value = clamp_t(u32, arvif->ar->hw->wiphy->frag_threshold,
|
||||
ATH10K_FRAGMT_THRESHOLD_MIN,
|
||||
ATH10K_FRAGMT_THRESHOLD_MAX);
|
||||
|
||||
return ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id,
|
||||
WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD,
|
||||
value);
|
||||
vdev_param = ar->wmi.vdev_param->fragmentation_threshold;
|
||||
return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value);
|
||||
}
|
||||
|
||||
static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)
|
||||
@ -562,12 +566,9 @@ static int ath10k_monitor_stop(struct ath10k *ar)
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
/* For some reasons, ath10k_wmi_vdev_down() here couse
|
||||
* often ath10k_wmi_vdev_stop() to fail. Next we could
|
||||
* not run monitor vdev and driver reload
|
||||
* required. Don't see such problems we skip
|
||||
* ath10k_wmi_vdev_down() here.
|
||||
*/
|
||||
ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id);
|
||||
if (ret)
|
||||
ath10k_warn("Monitor vdev down failed: %d\n", ret);
|
||||
|
||||
ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
|
||||
if (ret)
|
||||
@ -677,6 +678,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
|
||||
struct ieee80211_bss_conf *info,
|
||||
const u8 self_peer[ETH_ALEN])
|
||||
{
|
||||
u32 vdev_param;
|
||||
int ret = 0;
|
||||
|
||||
lockdep_assert_held(&arvif->ar->conf_mutex);
|
||||
@ -710,8 +712,8 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
|
||||
return;
|
||||
}
|
||||
|
||||
ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id,
|
||||
WMI_VDEV_PARAM_ATIM_WINDOW,
|
||||
vdev_param = arvif->ar->wmi.vdev_param->atim_window;
|
||||
ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, vdev_param,
|
||||
ATH10K_DEFAULT_ATIM);
|
||||
if (ret)
|
||||
ath10k_warn("Failed to set IBSS ATIM for VDEV:%d ret:%d\n",
|
||||
@ -721,35 +723,30 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
|
||||
/*
|
||||
* Review this when mac80211 gains per-interface powersave support.
|
||||
*/
|
||||
static void ath10k_ps_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
||||
static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
|
||||
{
|
||||
struct ath10k_generic_iter *ar_iter = data;
|
||||
struct ieee80211_conf *conf = &ar_iter->ar->hw->conf;
|
||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
struct ath10k *ar = arvif->ar;
|
||||
struct ieee80211_conf *conf = &ar->hw->conf;
|
||||
enum wmi_sta_powersave_param param;
|
||||
enum wmi_sta_ps_mode psmode;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&arvif->ar->conf_mutex);
|
||||
|
||||
if (vif->type != NL80211_IFTYPE_STATION)
|
||||
return;
|
||||
if (arvif->vif->type != NL80211_IFTYPE_STATION)
|
||||
return 0;
|
||||
|
||||
if (conf->flags & IEEE80211_CONF_PS) {
|
||||
psmode = WMI_STA_PS_MODE_ENABLED;
|
||||
param = WMI_STA_PS_PARAM_INACTIVITY_TIME;
|
||||
|
||||
ret = ath10k_wmi_set_sta_ps_param(ar_iter->ar,
|
||||
arvif->vdev_id,
|
||||
param,
|
||||
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param,
|
||||
conf->dynamic_ps_timeout);
|
||||
if (ret) {
|
||||
ath10k_warn("Failed to set inactivity time for VDEV: %d\n",
|
||||
arvif->vdev_id);
|
||||
return;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ar_iter->ret = ret;
|
||||
} else {
|
||||
psmode = WMI_STA_PS_MODE_DISABLED;
|
||||
}
|
||||
@ -757,11 +754,14 @@ static void ath10k_ps_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d psmode %s\n",
|
||||
arvif->vdev_id, psmode ? "enable" : "disable");
|
||||
|
||||
ar_iter->ret = ath10k_wmi_set_psmode(ar_iter->ar, arvif->vdev_id,
|
||||
psmode);
|
||||
if (ar_iter->ret)
|
||||
ret = ath10k_wmi_set_psmode(ar, arvif->vdev_id, psmode);
|
||||
if (ret) {
|
||||
ath10k_warn("Failed to set PS Mode: %d for VDEV: %d\n",
|
||||
psmode, arvif->vdev_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**********************/
|
||||
@ -1031,14 +1031,27 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
|
||||
struct wmi_peer_assoc_complete_arg *arg)
|
||||
{
|
||||
const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
|
||||
u8 ampdu_factor;
|
||||
|
||||
if (!vht_cap->vht_supported)
|
||||
return;
|
||||
|
||||
arg->peer_flags |= WMI_PEER_VHT;
|
||||
|
||||
arg->peer_vht_caps = vht_cap->cap;
|
||||
|
||||
|
||||
ampdu_factor = (vht_cap->cap &
|
||||
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >>
|
||||
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
|
||||
|
||||
/* Workaround: Some Netgear/Linksys 11ac APs set Rx A-MPDU factor to
|
||||
* zero in VHT IE. Using it would result in degraded throughput.
|
||||
* arg->peer_max_mpdu at this point contains HT max_mpdu so keep
|
||||
* it if VHT max_mpdu is smaller. */
|
||||
arg->peer_max_mpdu = max(arg->peer_max_mpdu,
|
||||
(1U << (IEEE80211_HT_MAX_AMPDU_FACTOR +
|
||||
ampdu_factor)) - 1);
|
||||
|
||||
if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
|
||||
arg->peer_flags |= WMI_PEER_80MHZ;
|
||||
|
||||
@ -1124,26 +1137,25 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
|
||||
WARN_ON(phymode == MODE_UNKNOWN);
|
||||
}
|
||||
|
||||
static int ath10k_peer_assoc(struct ath10k *ar,
|
||||
struct ath10k_vif *arvif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_bss_conf *bss_conf)
|
||||
static int ath10k_peer_assoc_prepare(struct ath10k *ar,
|
||||
struct ath10k_vif *arvif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_bss_conf *bss_conf,
|
||||
struct wmi_peer_assoc_complete_arg *arg)
|
||||
{
|
||||
struct wmi_peer_assoc_complete_arg arg;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
memset(&arg, 0, sizeof(struct wmi_peer_assoc_complete_arg));
|
||||
memset(arg, 0, sizeof(*arg));
|
||||
|
||||
ath10k_peer_assoc_h_basic(ar, arvif, sta, bss_conf, &arg);
|
||||
ath10k_peer_assoc_h_crypto(ar, arvif, &arg);
|
||||
ath10k_peer_assoc_h_rates(ar, sta, &arg);
|
||||
ath10k_peer_assoc_h_ht(ar, sta, &arg);
|
||||
ath10k_peer_assoc_h_vht(ar, sta, &arg);
|
||||
ath10k_peer_assoc_h_qos(ar, arvif, sta, bss_conf, &arg);
|
||||
ath10k_peer_assoc_h_phymode(ar, arvif, sta, &arg);
|
||||
ath10k_peer_assoc_h_basic(ar, arvif, sta, bss_conf, arg);
|
||||
ath10k_peer_assoc_h_crypto(ar, arvif, arg);
|
||||
ath10k_peer_assoc_h_rates(ar, sta, arg);
|
||||
ath10k_peer_assoc_h_ht(ar, sta, arg);
|
||||
ath10k_peer_assoc_h_vht(ar, sta, arg);
|
||||
ath10k_peer_assoc_h_qos(ar, arvif, sta, bss_conf, arg);
|
||||
ath10k_peer_assoc_h_phymode(ar, arvif, sta, arg);
|
||||
|
||||
return ath10k_wmi_peer_assoc(ar, &arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* can be called only in mac80211 callbacks due to `key_count` usage */
|
||||
@ -1153,6 +1165,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
struct wmi_peer_assoc_complete_arg peer_arg;
|
||||
struct ieee80211_sta *ap_sta;
|
||||
int ret;
|
||||
|
||||
@ -1168,15 +1181,24 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
|
||||
return;
|
||||
}
|
||||
|
||||
ret = ath10k_peer_assoc(ar, arvif, ap_sta, bss_conf);
|
||||
ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
|
||||
bss_conf, &peer_arg);
|
||||
if (ret) {
|
||||
ath10k_warn("Peer assoc failed for %pM\n", bss_conf->bssid);
|
||||
ath10k_warn("Peer assoc prepare failed for %pM\n: %d",
|
||||
bss_conf->bssid, ret);
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
|
||||
if (ret) {
|
||||
ath10k_warn("Peer assoc failed for %pM\n: %d",
|
||||
bss_conf->bssid, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MAC,
|
||||
"mac vdev %d up (associated) bssid %pM aid %d\n",
|
||||
arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
|
||||
@ -1224,19 +1246,28 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
|
||||
/* FIXME: why don't we print error if wmi call fails? */
|
||||
ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
|
||||
|
||||
arvif->def_wep_key_index = 0;
|
||||
arvif->def_wep_key_idx = 0;
|
||||
}
|
||||
|
||||
static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct wmi_peer_assoc_complete_arg peer_arg;
|
||||
int ret = 0;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
ret = ath10k_peer_assoc(ar, arvif, sta, NULL);
|
||||
ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg);
|
||||
if (ret) {
|
||||
ath10k_warn("WMI peer assoc failed for %pM\n", sta->addr);
|
||||
ath10k_warn("WMI peer assoc prepare failed for %pM\n",
|
||||
sta->addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
|
||||
if (ret) {
|
||||
ath10k_warn("Peer assoc failed for STA %pM\n: %d",
|
||||
sta->addr, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1405,6 +1436,33 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,
|
||||
/* TX handlers */
|
||||
/***************/
|
||||
|
||||
static u8 ath10k_tx_h_get_tid(struct ieee80211_hdr *hdr)
|
||||
{
|
||||
if (ieee80211_is_mgmt(hdr->frame_control))
|
||||
return HTT_DATA_TX_EXT_TID_MGMT;
|
||||
|
||||
if (!ieee80211_is_data_qos(hdr->frame_control))
|
||||
return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
|
||||
|
||||
if (!is_unicast_ether_addr(ieee80211_get_DA(hdr)))
|
||||
return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
|
||||
|
||||
return ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
|
||||
}
|
||||
|
||||
static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar,
|
||||
struct ieee80211_tx_info *info)
|
||||
{
|
||||
if (info->control.vif)
|
||||
return ath10k_vif_to_arvif(info->control.vif)->vdev_id;
|
||||
|
||||
if (ar->monitor_enabled)
|
||||
return ar->monitor_vdev_id;
|
||||
|
||||
ath10k_warn("could not resolve vdev id\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Frames sent to the FW have to be in "Native Wifi" format.
|
||||
* Strip the QoS field from the 802.11 header.
|
||||
@ -1425,6 +1483,30 @@ static void ath10k_tx_h_qos_workaround(struct ieee80211_hw *hw,
|
||||
skb_pull(skb, IEEE80211_QOS_CTL_LEN);
|
||||
}
|
||||
|
||||
static void ath10k_tx_wep_key_work(struct work_struct *work)
|
||||
{
|
||||
struct ath10k_vif *arvif = container_of(work, struct ath10k_vif,
|
||||
wep_key_work);
|
||||
int ret, keyidx = arvif->def_wep_key_newidx;
|
||||
|
||||
if (arvif->def_wep_key_idx == keyidx)
|
||||
return;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n",
|
||||
arvif->vdev_id, keyidx);
|
||||
|
||||
ret = ath10k_wmi_vdev_set_param(arvif->ar,
|
||||
arvif->vdev_id,
|
||||
arvif->ar->wmi.vdev_param->def_keyid,
|
||||
keyidx);
|
||||
if (ret) {
|
||||
ath10k_warn("could not update wep keyidx (%d)\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
arvif->def_wep_key_idx = keyidx;
|
||||
}
|
||||
|
||||
static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
@ -1433,7 +1515,6 @@ static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)
|
||||
struct ath10k *ar = arvif->ar;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ieee80211_key_conf *key = info->control.hw_key;
|
||||
int ret;
|
||||
|
||||
if (!ieee80211_has_protected(hdr->frame_control))
|
||||
return;
|
||||
@ -1445,21 +1526,14 @@ static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)
|
||||
key->cipher != WLAN_CIPHER_SUITE_WEP104)
|
||||
return;
|
||||
|
||||
if (key->keyidx == arvif->def_wep_key_index)
|
||||
if (key->keyidx == arvif->def_wep_key_idx)
|
||||
return;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d keyidx %d\n",
|
||||
arvif->vdev_id, key->keyidx);
|
||||
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
|
||||
WMI_VDEV_PARAM_DEF_KEYID,
|
||||
key->keyidx);
|
||||
if (ret) {
|
||||
ath10k_warn("could not update wep keyidx (%d)\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
arvif->def_wep_key_index = key->keyidx;
|
||||
/* FIXME: Most likely a few frames will be TXed with an old key. Simply
|
||||
* queueing frames until key index is updated is not an option because
|
||||
* sk_buff may need more processing to be done, e.g. offchannel */
|
||||
arvif->def_wep_key_newidx = key->keyidx;
|
||||
ieee80211_queue_work(ar->hw, &arvif->wep_key_work);
|
||||
}
|
||||
|
||||
static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, struct sk_buff *skb)
|
||||
@ -1489,7 +1563,7 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, struct sk_buff *skb)
|
||||
static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
if (ar->htt.target_version_major >= 3) {
|
||||
/* Since HTT 3.0 there is no separate mgmt tx command */
|
||||
@ -1497,16 +1571,32 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (ieee80211_is_mgmt(hdr->frame_control))
|
||||
ret = ath10k_htt_mgmt_tx(&ar->htt, skb);
|
||||
else if (ieee80211_is_nullfunc(hdr->frame_control))
|
||||
if (ieee80211_is_mgmt(hdr->frame_control)) {
|
||||
if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
|
||||
ar->fw_features)) {
|
||||
if (skb_queue_len(&ar->wmi_mgmt_tx_queue) >=
|
||||
ATH10K_MAX_NUM_MGMT_PENDING) {
|
||||
ath10k_warn("wmi mgmt_tx queue limit reached\n");
|
||||
ret = -EBUSY;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
skb_queue_tail(&ar->wmi_mgmt_tx_queue, skb);
|
||||
ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work);
|
||||
} else {
|
||||
ret = ath10k_htt_mgmt_tx(&ar->htt, skb);
|
||||
}
|
||||
} else if (!test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
|
||||
ar->fw_features) &&
|
||||
ieee80211_is_nullfunc(hdr->frame_control)) {
|
||||
/* FW does not report tx status properly for NullFunc frames
|
||||
* unless they are sent through mgmt tx path. mac80211 sends
|
||||
* those frames when it detects link/beacon loss and depends on
|
||||
* the tx status to be correct. */
|
||||
* those frames when it detects link/beacon loss and depends
|
||||
* on the tx status to be correct. */
|
||||
ret = ath10k_htt_mgmt_tx(&ar->htt, skb);
|
||||
else
|
||||
} else {
|
||||
ret = ath10k_htt_tx(&ar->htt, skb);
|
||||
}
|
||||
|
||||
exit:
|
||||
if (ret) {
|
||||
@ -1557,7 +1647,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
peer_addr = ieee80211_get_DA(hdr);
|
||||
vdev_id = ATH10K_SKB_CB(skb)->htt.vdev_id;
|
||||
vdev_id = ATH10K_SKB_CB(skb)->vdev_id;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
peer = ath10k_peer_find(ar, vdev_id, peer_addr);
|
||||
@ -1599,6 +1689,36 @@ void ath10k_offchan_tx_work(struct work_struct *work)
|
||||
}
|
||||
}
|
||||
|
||||
void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
for (;;) {
|
||||
skb = skb_dequeue(&ar->wmi_mgmt_tx_queue);
|
||||
if (!skb)
|
||||
break;
|
||||
|
||||
ieee80211_free_txskb(ar->hw, skb);
|
||||
}
|
||||
}
|
||||
|
||||
void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
|
||||
{
|
||||
struct ath10k *ar = container_of(work, struct ath10k, wmi_mgmt_tx_work);
|
||||
struct sk_buff *skb;
|
||||
int ret;
|
||||
|
||||
for (;;) {
|
||||
skb = skb_dequeue(&ar->wmi_mgmt_tx_queue);
|
||||
if (!skb)
|
||||
break;
|
||||
|
||||
ret = ath10k_wmi_mgmt_tx(ar, skb);
|
||||
if (ret)
|
||||
ath10k_warn("wmi mgmt_tx failed (%d)\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
/************/
|
||||
/* Scanning */
|
||||
/************/
|
||||
@ -1722,16 +1842,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_vif *arvif = NULL;
|
||||
u32 vdev_id = 0;
|
||||
u8 tid;
|
||||
|
||||
if (info->control.vif) {
|
||||
arvif = ath10k_vif_to_arvif(info->control.vif);
|
||||
vdev_id = arvif->vdev_id;
|
||||
} else if (ar->monitor_enabled) {
|
||||
vdev_id = ar->monitor_vdev_id;
|
||||
}
|
||||
u8 tid, vdev_id;
|
||||
|
||||
/* We should disable CCK RATE due to P2P */
|
||||
if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
|
||||
@ -1739,14 +1850,8 @@ static void ath10k_tx(struct ieee80211_hw *hw,
|
||||
|
||||
/* we must calculate tid before we apply qos workaround
|
||||
* as we'd lose the qos control field */
|
||||
tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
|
||||
if (ieee80211_is_mgmt(hdr->frame_control)) {
|
||||
tid = HTT_DATA_TX_EXT_TID_MGMT;
|
||||
} else if (ieee80211_is_data_qos(hdr->frame_control) &&
|
||||
is_unicast_ether_addr(ieee80211_get_DA(hdr))) {
|
||||
u8 *qc = ieee80211_get_qos_ctl(hdr);
|
||||
tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
|
||||
}
|
||||
tid = ath10k_tx_h_get_tid(hdr);
|
||||
vdev_id = ath10k_tx_h_get_vdev_id(ar, info);
|
||||
|
||||
/* it makes no sense to process injected frames like that */
|
||||
if (info->control.vif &&
|
||||
@ -1757,14 +1862,14 @@ static void ath10k_tx(struct ieee80211_hw *hw,
|
||||
ath10k_tx_h_seq_no(skb);
|
||||
}
|
||||
|
||||
ATH10K_SKB_CB(skb)->vdev_id = vdev_id;
|
||||
ATH10K_SKB_CB(skb)->htt.is_offchan = false;
|
||||
ATH10K_SKB_CB(skb)->htt.vdev_id = vdev_id;
|
||||
ATH10K_SKB_CB(skb)->htt.tid = tid;
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ATH10K_SKB_CB(skb)->htt.is_offchan = true;
|
||||
ATH10K_SKB_CB(skb)->htt.vdev_id = ar->scan.vdev_id;
|
||||
ATH10K_SKB_CB(skb)->vdev_id = ar->scan.vdev_id;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "queued offchannel skb %p\n", skb);
|
||||
@ -1786,6 +1891,7 @@ void ath10k_halt(struct ath10k *ar)
|
||||
|
||||
del_timer_sync(&ar->scan.timeout);
|
||||
ath10k_offchan_tx_purge(ar);
|
||||
ath10k_mgmt_over_wmi_tx_purge(ar);
|
||||
ath10k_peer_cleanup_all(ar);
|
||||
ath10k_core_stop(ar);
|
||||
ath10k_hif_power_down(ar);
|
||||
@ -1832,12 +1938,12 @@ static int ath10k_start(struct ieee80211_hw *hw)
|
||||
else if (ar->state == ATH10K_STATE_RESTARTING)
|
||||
ar->state = ATH10K_STATE_RESTARTED;
|
||||
|
||||
ret = ath10k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS, 1);
|
||||
ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pmf_qos, 1);
|
||||
if (ret)
|
||||
ath10k_warn("could not enable WMI_PDEV_PARAM_PMF_QOS (%d)\n",
|
||||
ret);
|
||||
|
||||
ret = ath10k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_DYNAMIC_BW, 0);
|
||||
ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 0);
|
||||
if (ret)
|
||||
ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n",
|
||||
ret);
|
||||
@ -1862,32 +1968,29 @@ static void ath10k_stop(struct ieee80211_hw *hw)
|
||||
ar->state = ATH10K_STATE_OFF;
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
ath10k_mgmt_over_wmi_tx_purge(ar);
|
||||
|
||||
cancel_work_sync(&ar->offchan_tx_work);
|
||||
cancel_work_sync(&ar->wmi_mgmt_tx_work);
|
||||
cancel_work_sync(&ar->restart_work);
|
||||
}
|
||||
|
||||
static void ath10k_config_ps(struct ath10k *ar)
|
||||
static int ath10k_config_ps(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_generic_iter ar_iter;
|
||||
struct ath10k_vif *arvif;
|
||||
int ret = 0;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
/* During HW reconfiguration mac80211 reports all interfaces that were
|
||||
* running until reconfiguration was started. Since FW doesn't have any
|
||||
* vdevs at this point we must not iterate over this interface list.
|
||||
* This setting will be updated upon add_interface(). */
|
||||
if (ar->state == ATH10K_STATE_RESTARTED)
|
||||
return;
|
||||
list_for_each_entry(arvif, &ar->arvifs, list) {
|
||||
ret = ath10k_mac_vif_setup_ps(arvif);
|
||||
if (ret) {
|
||||
ath10k_warn("could not setup powersave (%d)\n", ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter));
|
||||
ar_iter.ar = ar;
|
||||
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
ar->hw, IEEE80211_IFACE_ITER_NORMAL,
|
||||
ath10k_ps_iter, &ar_iter);
|
||||
|
||||
if (ar_iter.ret)
|
||||
ath10k_warn("failed to set ps config (%d)\n", ar_iter.ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
|
||||
@ -1936,6 +2039,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||
int ret = 0;
|
||||
u32 value;
|
||||
int bit;
|
||||
u32 vdev_param;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
@ -1944,21 +2048,22 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||
arvif->ar = ar;
|
||||
arvif->vif = vif;
|
||||
|
||||
INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work);
|
||||
|
||||
if ((vif->type == NL80211_IFTYPE_MONITOR) && ar->monitor_present) {
|
||||
ath10k_warn("Only one monitor interface allowed\n");
|
||||
ret = -EBUSY;
|
||||
goto exit;
|
||||
goto err;
|
||||
}
|
||||
|
||||
bit = ffs(ar->free_vdev_map);
|
||||
if (bit == 0) {
|
||||
ret = -EBUSY;
|
||||
goto exit;
|
||||
goto err;
|
||||
}
|
||||
|
||||
arvif->vdev_id = bit - 1;
|
||||
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
|
||||
ar->free_vdev_map &= ~(1 << arvif->vdev_id);
|
||||
|
||||
if (ar->p2p)
|
||||
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE;
|
||||
@ -1994,25 +2099,34 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||
arvif->vdev_subtype, vif->addr);
|
||||
if (ret) {
|
||||
ath10k_warn("WMI vdev create failed: ret %d\n", ret);
|
||||
goto exit;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = ath10k_wmi_vdev_set_param(ar, 0, WMI_VDEV_PARAM_DEF_KEYID,
|
||||
arvif->def_wep_key_index);
|
||||
if (ret)
|
||||
ath10k_warn("Failed to set default keyid: %d\n", ret);
|
||||
ar->free_vdev_map &= ~BIT(arvif->vdev_id);
|
||||
list_add(&arvif->list, &ar->arvifs);
|
||||
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
|
||||
WMI_VDEV_PARAM_TX_ENCAP_TYPE,
|
||||
vdev_param = ar->wmi.vdev_param->def_keyid;
|
||||
ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param,
|
||||
arvif->def_wep_key_idx);
|
||||
if (ret) {
|
||||
ath10k_warn("Failed to set default keyid: %d\n", ret);
|
||||
goto err_vdev_delete;
|
||||
}
|
||||
|
||||
vdev_param = ar->wmi.vdev_param->tx_encap_type;
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
|
||||
ATH10K_HW_TXRX_NATIVE_WIFI);
|
||||
if (ret)
|
||||
/* 10.X firmware does not support this VDEV parameter. Do not warn */
|
||||
if (ret && ret != -EOPNOTSUPP) {
|
||||
ath10k_warn("Failed to set TX encap: %d\n", ret);
|
||||
goto err_vdev_delete;
|
||||
}
|
||||
|
||||
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
|
||||
ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr);
|
||||
if (ret) {
|
||||
ath10k_warn("Failed to create peer for AP: %d\n", ret);
|
||||
goto exit;
|
||||
goto err_vdev_delete;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2021,39 +2135,62 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||
value = WMI_STA_PS_RX_WAKE_POLICY_WAKE;
|
||||
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
|
||||
param, value);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
ath10k_warn("Failed to set RX wake policy: %d\n", ret);
|
||||
goto err_peer_delete;
|
||||
}
|
||||
|
||||
param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD;
|
||||
value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS;
|
||||
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
|
||||
param, value);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
ath10k_warn("Failed to set TX wake thresh: %d\n", ret);
|
||||
goto err_peer_delete;
|
||||
}
|
||||
|
||||
param = WMI_STA_PS_PARAM_PSPOLL_COUNT;
|
||||
value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX;
|
||||
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
|
||||
param, value);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
ath10k_warn("Failed to set PSPOLL count: %d\n", ret);
|
||||
goto err_peer_delete;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
ath10k_warn("failed to set rts threshold for vdev %d (%d)\n",
|
||||
arvif->vdev_id, ret);
|
||||
goto err_peer_delete;
|
||||
}
|
||||
|
||||
ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
ath10k_warn("failed to set frag threshold for vdev %d (%d)\n",
|
||||
arvif->vdev_id, ret);
|
||||
goto err_peer_delete;
|
||||
}
|
||||
|
||||
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
|
||||
ar->monitor_present = true;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return 0;
|
||||
|
||||
err_peer_delete:
|
||||
if (arvif->vdev_type == WMI_VDEV_TYPE_AP)
|
||||
ath10k_wmi_peer_delete(ar, arvif->vdev_id, vif->addr);
|
||||
|
||||
err_vdev_delete:
|
||||
ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
|
||||
ar->free_vdev_map &= ~BIT(arvif->vdev_id);
|
||||
list_del(&arvif->list);
|
||||
|
||||
err:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2066,6 +2203,8 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
cancel_work_sync(&arvif->wep_key_work);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
if (arvif->beacon) {
|
||||
dev_kfree_skb_any(arvif->beacon);
|
||||
@ -2074,6 +2213,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
ar->free_vdev_map |= 1 << (arvif->vdev_id);
|
||||
list_del(&arvif->list);
|
||||
|
||||
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
|
||||
ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, vif->addr);
|
||||
@ -2154,6 +2294,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
int ret = 0;
|
||||
u32 vdev_param, pdev_param;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
@ -2162,8 +2303,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
|
||||
if (changed & BSS_CHANGED_BEACON_INT) {
|
||||
arvif->beacon_interval = info->beacon_int;
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
|
||||
WMI_VDEV_PARAM_BEACON_INTERVAL,
|
||||
vdev_param = ar->wmi.vdev_param->beacon_interval;
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
|
||||
arvif->beacon_interval);
|
||||
ath10k_dbg(ATH10K_DBG_MAC,
|
||||
"mac vdev %d beacon_interval %d\n",
|
||||
@ -2179,8 +2320,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
"vdev %d set beacon tx mode to staggered\n",
|
||||
arvif->vdev_id);
|
||||
|
||||
ret = ath10k_wmi_pdev_set_param(ar,
|
||||
WMI_PDEV_PARAM_BEACON_TX_MODE,
|
||||
pdev_param = ar->wmi.pdev_param->beacon_tx_mode;
|
||||
ret = ath10k_wmi_pdev_set_param(ar, pdev_param,
|
||||
WMI_BEACON_STAGGERED_MODE);
|
||||
if (ret)
|
||||
ath10k_warn("Failed to set beacon mode for VDEV: %d\n",
|
||||
@ -2194,8 +2335,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
"mac vdev %d dtim_period %d\n",
|
||||
arvif->vdev_id, arvif->dtim_period);
|
||||
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
|
||||
WMI_VDEV_PARAM_DTIM_PERIOD,
|
||||
vdev_param = ar->wmi.vdev_param->dtim_period;
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
|
||||
arvif->dtim_period);
|
||||
if (ret)
|
||||
ath10k_warn("Failed to set dtim period for VDEV: %d\n",
|
||||
@ -2262,8 +2403,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n",
|
||||
arvif->vdev_id, cts_prot);
|
||||
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
|
||||
WMI_VDEV_PARAM_ENABLE_RTSCTS,
|
||||
vdev_param = ar->wmi.vdev_param->enable_rtscts;
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
|
||||
cts_prot);
|
||||
if (ret)
|
||||
ath10k_warn("Failed to set CTS prot for VDEV: %d\n",
|
||||
@ -2281,8 +2422,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n",
|
||||
arvif->vdev_id, slottime);
|
||||
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
|
||||
WMI_VDEV_PARAM_SLOT_TIME,
|
||||
vdev_param = ar->wmi.vdev_param->slot_time;
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
|
||||
slottime);
|
||||
if (ret)
|
||||
ath10k_warn("Failed to set erp slot for VDEV: %d\n",
|
||||
@ -2300,8 +2441,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
"mac vdev %d preamble %dn",
|
||||
arvif->vdev_id, preamble);
|
||||
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
|
||||
WMI_VDEV_PARAM_PREAMBLE,
|
||||
vdev_param = ar->wmi.vdev_param->preamble;
|
||||
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
|
||||
preamble);
|
||||
if (ret)
|
||||
ath10k_warn("Failed to set preamble for VDEV: %d\n",
|
||||
@ -2751,86 +2892,51 @@ static int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw)
|
||||
* Both RTS and Fragmentation threshold are interface-specific
|
||||
* in ath10k, but device-specific in mac80211.
|
||||
*/
|
||||
static void ath10k_set_rts_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath10k_generic_iter *ar_iter = data;
|
||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
u32 rts = ar_iter->ar->hw->wiphy->rts_threshold;
|
||||
|
||||
lockdep_assert_held(&arvif->ar->conf_mutex);
|
||||
|
||||
/* During HW reconfiguration mac80211 reports all interfaces that were
|
||||
* running until reconfiguration was started. Since FW doesn't have any
|
||||
* vdevs at this point we must not iterate over this interface list.
|
||||
* This setting will be updated upon add_interface(). */
|
||||
if (ar_iter->ar->state == ATH10K_STATE_RESTARTED)
|
||||
return;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d rts_threshold %d\n",
|
||||
arvif->vdev_id, rts);
|
||||
|
||||
ar_iter->ret = ath10k_mac_set_rts(arvif, rts);
|
||||
if (ar_iter->ret)
|
||||
ath10k_warn("Failed to set RTS threshold for VDEV: %d\n",
|
||||
arvif->vdev_id);
|
||||
}
|
||||
|
||||
static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
|
||||
{
|
||||
struct ath10k_generic_iter ar_iter;
|
||||
struct ath10k *ar = hw->priv;
|
||||
|
||||
memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter));
|
||||
ar_iter.ar = ar;
|
||||
struct ath10k_vif *arvif;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
hw, IEEE80211_IFACE_ITER_NORMAL,
|
||||
ath10k_set_rts_iter, &ar_iter);
|
||||
list_for_each_entry(arvif, &ar->arvifs, list) {
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n",
|
||||
arvif->vdev_id, value);
|
||||
|
||||
ret = ath10k_mac_set_rts(arvif, value);
|
||||
if (ret) {
|
||||
ath10k_warn("could not set rts threshold for vdev %d (%d)\n",
|
||||
arvif->vdev_id, ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return ar_iter.ret;
|
||||
}
|
||||
|
||||
static void ath10k_set_frag_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath10k_generic_iter *ar_iter = data;
|
||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||
u32 frag = ar_iter->ar->hw->wiphy->frag_threshold;
|
||||
|
||||
lockdep_assert_held(&arvif->ar->conf_mutex);
|
||||
|
||||
/* During HW reconfiguration mac80211 reports all interfaces that were
|
||||
* running until reconfiguration was started. Since FW doesn't have any
|
||||
* vdevs at this point we must not iterate over this interface list.
|
||||
* This setting will be updated upon add_interface(). */
|
||||
if (ar_iter->ar->state == ATH10K_STATE_RESTARTED)
|
||||
return;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d fragmentation_threshold %d\n",
|
||||
arvif->vdev_id, frag);
|
||||
|
||||
ar_iter->ret = ath10k_mac_set_frag(arvif, frag);
|
||||
if (ar_iter->ret)
|
||||
ath10k_warn("Failed to set frag threshold for VDEV: %d\n",
|
||||
arvif->vdev_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
|
||||
{
|
||||
struct ath10k_generic_iter ar_iter;
|
||||
struct ath10k *ar = hw->priv;
|
||||
|
||||
memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter));
|
||||
ar_iter.ar = ar;
|
||||
struct ath10k_vif *arvif;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
hw, IEEE80211_IFACE_ITER_NORMAL,
|
||||
ath10k_set_frag_iter, &ar_iter);
|
||||
list_for_each_entry(arvif, &ar->arvifs, list) {
|
||||
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n",
|
||||
arvif->vdev_id, value);
|
||||
|
||||
ret = ath10k_mac_set_rts(arvif, value);
|
||||
if (ret) {
|
||||
ath10k_warn("could not set fragmentation threshold for vdev %d (%d)\n",
|
||||
arvif->vdev_id, ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return ar_iter.ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
|
||||
|
@ -34,6 +34,8 @@ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id);
|
||||
void ath10k_reset_scan(unsigned long ptr);
|
||||
void ath10k_offchan_tx_purge(struct ath10k *ar);
|
||||
void ath10k_offchan_tx_work(struct work_struct *work);
|
||||
void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar);
|
||||
void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work);
|
||||
void ath10k_halt(struct ath10k *ar);
|
||||
|
||||
static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
|
||||
|
@ -720,18 +720,8 @@ static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id,
|
||||
"ath10k tx: data: ",
|
||||
nbuf->data, nbuf->len);
|
||||
|
||||
/* Make sure we have resources to handle this request */
|
||||
spin_lock_bh(&pipe_info->pipe_lock);
|
||||
if (!pipe_info->num_sends_allowed) {
|
||||
ath10k_warn("Pipe: %d is full\n", pipe_id);
|
||||
spin_unlock_bh(&pipe_info->pipe_lock);
|
||||
return -ENOSR;
|
||||
}
|
||||
pipe_info->num_sends_allowed--;
|
||||
spin_unlock_bh(&pipe_info->pipe_lock);
|
||||
|
||||
ret = ath10k_ce_sendlist_send(ce_hdl, nbuf, transfer_id,
|
||||
skb_cb->paddr, len, flags);
|
||||
ret = ath10k_ce_send(ce_hdl, nbuf, skb_cb->paddr, len, transfer_id,
|
||||
flags);
|
||||
if (ret)
|
||||
ath10k_warn("CE send failed: %p\n", nbuf);
|
||||
|
||||
@ -741,14 +731,7 @@ static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id,
|
||||
static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ath10k_pci_pipe *pipe_info = &(ar_pci->pipe_info[pipe]);
|
||||
int ret;
|
||||
|
||||
spin_lock_bh(&pipe_info->pipe_lock);
|
||||
ret = pipe_info->num_sends_allowed;
|
||||
spin_unlock_bh(&pipe_info->pipe_lock);
|
||||
|
||||
return ret;
|
||||
return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl);
|
||||
}
|
||||
|
||||
static void ath10k_pci_hif_dump_area(struct ath10k *ar)
|
||||
@ -863,7 +846,6 @@ static int ath10k_pci_start_ce(struct ath10k *ar)
|
||||
ath10k_pci_ce_send_done,
|
||||
disable_interrupts);
|
||||
completions += attr->src_nentries;
|
||||
pipe_info->num_sends_allowed = attr->src_nentries - 1;
|
||||
}
|
||||
|
||||
if (attr->dest_nentries) {
|
||||
@ -1033,7 +1015,6 @@ static void ath10k_pci_process_ce(struct ath10k *ar)
|
||||
*/
|
||||
spin_lock_bh(&compl->pipe_info->pipe_lock);
|
||||
list_add_tail(&compl->list, &compl->pipe_info->compl_free);
|
||||
compl->pipe_info->num_sends_allowed += send_done;
|
||||
spin_unlock_bh(&compl->pipe_info->pipe_lock);
|
||||
}
|
||||
|
||||
|
@ -178,9 +178,6 @@ struct ath10k_pci_pipe {
|
||||
/* List of free CE completion slots */
|
||||
struct list_head compl_free;
|
||||
|
||||
/* Limit the number of outstanding send requests. */
|
||||
int num_sends_allowed;
|
||||
|
||||
struct ath10k_pci *ar_pci;
|
||||
struct tasklet_struct intr;
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -60,7 +60,7 @@
|
||||
/* disable credit flow control on a specific service */
|
||||
#define HTC_CONN_FLGS_DISABLE_CRED_FLOW_CTRL (1 << 3)
|
||||
#define HTC_CONN_FLGS_SET_RECV_ALLOC_SHIFT 8
|
||||
#define HTC_CONN_FLGS_SET_RECV_ALLOC_MASK 0xFF00
|
||||
#define HTC_CONN_FLGS_SET_RECV_ALLOC_MASK 0xFF00U
|
||||
|
||||
/* connect response status codes */
|
||||
#define HTC_SERVICE_SUCCESS 0
|
||||
|
Loading…
Reference in New Issue
Block a user